From 0f70c59e559e33982b9bf2b12e2ac3ff8684d50f Mon Sep 17 00:00:00 2001
From: Gary Willoughby
Date: Wed, 18 Mar 2026 11:51:29 +0000
Subject: [PATCH 1/6] hotfix: port third-party fixes.
---
go.mod | 2 +-
go.sum | 6 +-
internal/http3/client.go | 68 +++++++--------
internal/http3/conn.go | 119 ++++++++++---------------
internal/http3/transport.go | 48 +++++++++--
internal/http3/transport_test.go | 143 +++++++++++++++++++++++++++++++
6 files changed, 261 insertions(+), 125 deletions(-)
create mode 100644 internal/http3/transport_test.go
diff --git a/go.mod b/go.mod
index e08be995..ff4b7795 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
github.com/icholy/digest v1.1.0
github.com/klauspost/compress v1.18.2
github.com/quic-go/qpack v0.6.0
- github.com/quic-go/quic-go v0.57.1
+ github.com/quic-go/quic-go v0.59.0
github.com/refraction-networking/utls v1.8.1
golang.org/x/net v0.48.0
golang.org/x/text v0.32.0
diff --git a/go.sum b/go.sum
index abc0b4e2..ed6aa9ec 100644
--- a/go.sum
+++ b/go.sum
@@ -15,8 +15,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
-github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10=
-github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s=
+github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
+github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/refraction-networking/utls v1.8.1 h1:yNY1kapmQU8JeM1sSw2H2asfTIwWxIkrMJI0pRUOCAo=
github.com/refraction-networking/utls v1.8.1/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
@@ -33,8 +33,6 @@ golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
-golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
-golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/internal/http3/client.go b/internal/http3/client.go
index f8786129..f1a85b11 100644
--- a/internal/http3/client.go
+++ b/internal/http3/client.go
@@ -84,8 +84,6 @@ func newClientConn(
conn *quic.Conn,
enableDatagrams bool,
additionalSettings map[uint64]uint64,
- streamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error),
- uniStreamHijacker func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool),
maxResponseHeaderBytes int,
disableCompression bool,
logger *slog.Logger,
@@ -122,13 +120,14 @@ func newClientConn(
c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeInternalError), "")
}
}()
- if streamHijacker != nil {
- go c.handleBidirectionalStreams(streamHijacker)
- }
- go c.conn.handleUnidirectionalStreams(uniStreamHijacker)
return c
}
+// handleUnidirectionalStream handles an incoming unidirectional stream.
+func (c *ClientConn) handleUnidirectionalStream(str *quic.ReceiveStream) {
+ c.conn.handleUnidirectionalStream(str)
+}
+
// OpenRequestStream opens a new request stream on the HTTP/3 connection.
func (c *ClientConn) OpenRequestStream(ctx context.Context) (*RequestStream, error) {
return c.conn.openRequestStream(ctx, c.requestWriter, nil, c.disableCompression, c.maxResponseHeaderBytes)
@@ -166,37 +165,6 @@ func (c *ClientConn) setupConn() error {
return err
}
-func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error)) {
- for {
- str, err := c.conn.conn.AcceptStream(context.Background())
- if err != nil {
- if c.logger != nil {
- c.logger.Debug("accepting bidirectional stream failed", "error", err)
- }
- return
- }
- fp := &frameParser{
- r: str,
- closeConn: c.conn.CloseWithError,
- unknownFrameHandler: func(ft FrameType, e error) (processed bool, err error) {
- id := c.conn.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID)
- return streamHijacker(ft, id, str, e)
- },
- }
- go func() {
- if _, err := fp.ParseNext(c.conn.qlogger); err == errHijacked {
- return
- }
- if err != nil {
- if c.logger != nil {
- c.logger.Debug("error handling stream", "error", err)
- }
- }
- c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "received HTTP/3 frame on bidirectional stream")
- }()
- }
-}
-
// RoundTrip executes a request and returns a response
func (c *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
rsp, err := c.roundTrip(req)
@@ -382,7 +350,7 @@ func (c *ClientConn) doRequest(req *http.Request, str *RequestStream) (*http.Res
if req.ContentLength > 0 {
contentLength = req.ContentLength
}
- dumps := dump.GetDumpers(req.Context(), c.Dump)
+ dumps := dump.GetDumpers(req.Context(), c.Dump)
err := c.sendRequestBody(str, req.Body, contentLength, dumps)
traceWroteRequest(trace, err)
if err != nil {
@@ -435,3 +403,27 @@ func (c *ClientConn) doRequest(req *http.Request, str *RequestStream) (*http.Res
func (c *ClientConn) Conn() *Conn {
return c.conn
}
+
+// HandleBidirectionalStream handles an incoming bidirectional stream.
+// According to RFC 9114, the server is not allowed to open bidirectional streams,
+// so this method closes the connection with an error.
+func (c *ClientConn) HandleBidirectionalStream(str *quic.Stream) {
+ c.conn.CloseWithError(
+ quic.ApplicationErrorCode(ErrCodeStreamCreationError),
+ fmt.Sprintf("server opened bidirectional stream %d", str.StreamID()),
+ )
+}
+
+// RawClientConn is a low-level HTTP/3 client connection.
+// It allows the application to take control of the stream accept loops,
+// giving the application the ability to handle streams originating from the server.
+// This is useful for implementing WebTransport or other advanced protocols.
+type RawClientConn struct {
+ *ClientConn
+}
+
+// HandleUnidirectionalStream handles an incoming unidirectional stream.
+// This should be called for each unidirectional stream accepted from the QUIC connection.
+func (c *RawClientConn) HandleUnidirectionalStream(str *quic.ReceiveStream) {
+ c.handleUnidirectionalStream(str)
+}
diff --git a/internal/http3/conn.go b/internal/http3/conn.go
index 5e20ce6e..b1f09c23 100644
--- a/internal/http3/conn.go
+++ b/internal/http3/conn.go
@@ -57,6 +57,11 @@ type Conn struct {
idleTimer *time.Timer
qlogger qlogwriter.Recorder
+
+ // Track received unidirectional streams (only one of each type allowed)
+ rcvdControlStr atomic.Bool
+ rcvdQPACKEncoderStr atomic.Bool
+ rcvdQPACKDecoderStr atomic.Bool
}
func newConnection(
@@ -232,80 +237,48 @@ func (c *Conn) CloseWithError(code quic.ApplicationErrorCode, msg string) error
return c.conn.CloseWithError(code, msg)
}
-func (c *Conn) handleUnidirectionalStreams(hijack func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool)) {
- var (
- rcvdControlStr atomic.Bool
- rcvdQPACKEncoderStr atomic.Bool
- rcvdQPACKDecoderStr atomic.Bool
- )
-
- for {
- str, err := c.conn.AcceptUniStream(context.Background())
- if err != nil {
- if c.logger != nil {
- c.logger.Debug("accepting unidirectional stream failed", "error", err)
- }
- return
+func (c *Conn) handleUnidirectionalStream(str *quic.ReceiveStream) {
+ streamType, err := quicvarint.Read(quicvarint.NewReader(str))
+ if err != nil {
+ if c.logger != nil {
+ c.logger.Debug("reading stream type on stream failed", "stream ID", str.StreamID(), "error", err)
}
-
- go func(str *quic.ReceiveStream) {
- streamType, err := quicvarint.Read(quicvarint.NewReader(str))
- if err != nil {
- id := c.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID)
- if hijack != nil && hijack(StreamType(streamType), id, str, err) {
- return
- }
- if c.logger != nil {
- c.logger.Debug("reading stream type on stream failed", "stream ID", str.StreamID(), "error", err)
- }
- return
- }
- // We're only interested in the control stream here.
- switch streamType {
- case streamTypeControlStream:
- case streamTypeQPACKEncoderStream:
- if isFirst := rcvdQPACKEncoderStr.CompareAndSwap(false, true); !isFirst {
- c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK encoder stream")
- }
- // Our QPACK implementation doesn't use the dynamic table yet.
- return
- case streamTypeQPACKDecoderStream:
- if isFirst := rcvdQPACKDecoderStr.CompareAndSwap(false, true); !isFirst {
- c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK decoder stream")
- }
- // Our QPACK implementation doesn't use the dynamic table yet.
- return
- case streamTypePushStream:
- if c.isServer {
- // only the server can push
- c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "")
- } else {
- // we never increased the Push ID, so we don't expect any push streams
- c.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "")
- }
- return
- default:
- if hijack != nil {
- if hijack(
- StreamType(streamType),
- c.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID),
- str,
- nil,
- ) {
- return
- }
- }
- str.CancelRead(quic.StreamErrorCode(ErrCodeStreamCreationError))
- return
- }
- // Only a single control stream is allowed.
- if isFirstControlStr := rcvdControlStr.CompareAndSwap(false, true); !isFirstControlStr {
- c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate control stream")
- return
- }
- c.handleControlStream(str)
- }(str)
+ return
+ }
+ // We're only interested in the control stream here.
+ switch streamType {
+ case streamTypeControlStream:
+ case streamTypeQPACKEncoderStream:
+ if isFirst := c.rcvdQPACKEncoderStr.CompareAndSwap(false, true); !isFirst {
+ c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK encoder stream")
+ }
+ // Our QPACK implementation doesn't use the dynamic table yet.
+ return
+ case streamTypeQPACKDecoderStream:
+ if isFirst := c.rcvdQPACKDecoderStr.CompareAndSwap(false, true); !isFirst {
+ c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK decoder stream")
+ }
+ // Our QPACK implementation doesn't use the dynamic table yet.
+ return
+ case streamTypePushStream:
+ if c.isServer {
+ // only the server can push
+ c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "")
+ } else {
+ // we never increased the Push ID, so we don't expect any push streams
+ c.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "")
+ }
+ return
+ default:
+ str.CancelRead(quic.StreamErrorCode(ErrCodeStreamCreationError))
+ return
+ }
+ // Only a single control stream is allowed.
+ if isFirstControlStr := c.rcvdControlStr.CompareAndSwap(false, true); !isFirstControlStr {
+ c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate control stream")
+ return
}
+ c.handleControlStream(str)
}
func (c *Conn) handleControlStream(str *quic.ReceiveStream) {
@@ -335,7 +308,7 @@ func (c *Conn) handleControlStream(str *quic.ReceiveStream) {
// If datagram support was enabled on our side as well as on the server side,
// we can expect it to have been negotiated both on the transport and on the HTTP/3 layer.
// Note: ConnectionState() will block until the handshake is complete (relevant when using 0-RTT).
- if c.enableDatagrams && !c.ConnectionState().SupportsDatagrams {
+ if c.enableDatagrams && !c.ConnectionState().SupportsDatagrams.Remote {
c.CloseWithError(quic.ApplicationErrorCode(ErrCodeSettingsError), "missing QUIC Datagram support")
return
}
diff --git a/internal/http3/transport.go b/internal/http3/transport.go
index ebe4b5b9..acde40df 100644
--- a/internal/http3/transport.go
+++ b/internal/http3/transport.go
@@ -41,6 +41,7 @@ type RoundTripOpt struct {
type clientConn interface {
OpenRequestStream(context.Context) (*RequestStream, error)
RoundTrip(*http.Request) (*http.Response, error)
+ handleUnidirectionalStream(*quic.ReceiveStream)
}
type roundTripperWithCount struct {
@@ -99,9 +100,6 @@ type Transport struct {
// However, if the user explicitly requested gzip it is not automatically uncompressed.
DisableCompression bool
- StreamHijacker func(FrameType, quic.ConnectionTracingID, *quic.Stream, error) (hijacked bool, err error)
- UniStreamHijacker func(StreamType, quic.ConnectionTracingID, *quic.ReceiveStream, error) (hijacked bool)
-
Logger *slog.Logger
mutex sync.Mutex
@@ -136,8 +134,6 @@ func (t *Transport) init() error {
conn,
t.EnableDatagrams,
t.AdditionalSettings,
- t.StreamHijacker,
- t.UniStreamHijacker,
t.MaxResponseHeaderBytes,
t.DisableCompression,
t.Logger,
@@ -410,7 +406,23 @@ func (t *Transport) dial(ctx context.Context, hostname string) (*quic.Conn, clie
if err != nil {
return nil, nil, err
}
- return conn, t.newClientConn(conn), nil
+ cc := t.newClientConn(conn)
+ startUnidirectionalStreamAcceptLoop(conn, cc)
+ return conn, cc, nil
+}
+
+// startUnidirectionalStreamAcceptLoop starts a goroutine that accepts incoming
+// unidirectional streams and passes them to the clientConn for handling.
+func startUnidirectionalStreamAcceptLoop(conn *quic.Conn, cc clientConn) {
+ go func() {
+ for {
+ str, err := conn.AcceptUniStream(context.Background())
+ if err != nil {
+ return
+ }
+ go cc.handleUnidirectionalStream(str)
+ }
+ }()
}
func (t *Transport) resolveUDPAddr(ctx context.Context, network, addr string) (*net.UDPAddr, error) {
@@ -448,17 +460,35 @@ func (t *Transport) removeClient(hostname string) {
// Obtaining a ClientConn is only needed for more advanced use cases, such as
// using Extended CONNECT for WebTransport or the various MASQUE protocols.
func (t *Transport) NewClientConn(conn *quic.Conn) *ClientConn {
- return newClientConn(
+ c := newClientConn(
t.Options,
conn,
t.EnableDatagrams,
t.AdditionalSettings,
- t.StreamHijacker,
- t.UniStreamHijacker,
t.MaxResponseHeaderBytes,
t.DisableCompression,
t.Logger,
)
+ startUnidirectionalStreamAcceptLoop(conn, c)
+ return c
+}
+
+// NewRawClientConn creates a new low-level HTTP/3 client connection on top of a QUIC connection.
+// Unlike NewClientConn, the returned RawClientConn allows the application to take control
+// of the stream accept loops, by calling HandleUnidirectionalStream for incoming unidirectional
+// streams and HandleBidirectionalStream for incoming bidirectional streams.
+func (t *Transport) NewRawClientConn(conn *quic.Conn) *RawClientConn {
+ return &RawClientConn{
+ ClientConn: newClientConn(
+ t.Options,
+ conn,
+ t.EnableDatagrams,
+ t.AdditionalSettings,
+ t.MaxResponseHeaderBytes,
+ t.DisableCompression,
+ t.Logger,
+ ),
+ }
}
// Close closes the QUIC connections that this Transport has used.
diff --git a/internal/http3/transport_test.go b/internal/http3/transport_test.go
new file mode 100644
index 00000000..4c8713c7
--- /dev/null
+++ b/internal/http3/transport_test.go
@@ -0,0 +1,143 @@
+package http3
+
+import (
+ "context"
+ "crypto/tls"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/imroc/req/v3/internal/testcert"
+ "github.com/quic-go/quic-go"
+)
+
+func TestTransportInit(t *testing.T) {
+ tr := &Transport{}
+ // Trigger init by calling RoundTrip with invalid request
+ // This tests that init() doesn't panic
+ _, err := tr.RoundTrip(&http.Request{})
+ if err == nil {
+ t.Fatal("expected error for nil URL")
+ }
+}
+
+func TestTransportInitWithDatagrams(t *testing.T) {
+ tr := &Transport{
+ EnableDatagrams: true,
+ QUICConfig: &quic.Config{
+ EnableDatagrams: true,
+ },
+ }
+ _, err := tr.RoundTrip(&http.Request{})
+ if err == nil {
+ t.Fatal("expected error for nil URL")
+ }
+}
+
+func TestTransportInitDatagramMismatch(t *testing.T) {
+ tr := &Transport{
+ EnableDatagrams: true,
+ QUICConfig: &quic.Config{
+ EnableDatagrams: false,
+ },
+ }
+ _, err := tr.RoundTrip(&http.Request{})
+ if err == nil || err.Error() != "HTTP Datagrams enabled, but QUIC Datagrams disabled" {
+ t.Fatalf("expected datagram mismatch error, got: %v", err)
+ }
+}
+
+func TestRawClientConnType(t *testing.T) {
+ // Test that RawClientConn embeds ClientConn correctly
+ // This is a compile-time type check
+ type hasClientConn interface {
+ RoundTrip(*http.Request) (*http.Response, error)
+ }
+ // Verify RawClientConn satisfies the same interface as ClientConn
+ var _ hasClientConn = (*RawClientConn)(nil)
+ var _ hasClientConn = (*ClientConn)(nil)
+}
+
+// TestNewClientConnAndRawClientConn tests the creation of client connections
+func TestNewClientConnAndRawClientConn(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping integration test in short mode")
+ }
+
+ // Create TLS config from test certificates
+ cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
+ if err != nil {
+ t.Fatalf("failed to load test cert: %v", err)
+ }
+ serverTLSConfig := &tls.Config{
+ Certificates: []tls.Certificate{cert},
+ NextProtos: []string{"h3"},
+ }
+
+ // Start QUIC listener
+ listener, err := quic.ListenAddr("127.0.0.1:0", serverTLSConfig, &quic.Config{})
+ if err != nil {
+ t.Fatalf("failed to start QUIC listener: %v", err)
+ }
+ defer listener.Close()
+
+ serverAddr := listener.Addr().String()
+
+ // Accept connections in background
+ go func() {
+ for {
+ conn, err := listener.Accept(context.Background())
+ if err != nil {
+ return
+ }
+ conn.CloseWithError(0, "test done")
+ }
+ }()
+
+ // Create client transport
+ clientTLSConfig := &tls.Config{
+ InsecureSkipVerify: true,
+ NextProtos: []string{"h3"},
+ }
+
+ tr := &Transport{
+ TLSClientConfig: clientTLSConfig,
+ QUICConfig: &quic.Config{
+ MaxIdleTimeout: 5 * time.Second,
+ },
+ }
+ defer tr.Close()
+
+ // Test dialing a QUIC connection
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ quicConn, err := quic.DialAddr(ctx, serverAddr, clientTLSConfig, tr.QUICConfig)
+ if err != nil {
+ t.Fatalf("failed to dial QUIC: %v", err)
+ }
+ defer quicConn.CloseWithError(0, "")
+
+ // Test NewClientConn
+ clientConn := tr.NewClientConn(quicConn)
+ if clientConn == nil {
+ t.Fatal("NewClientConn returned nil")
+ }
+
+ // Test NewRawClientConn with a new connection
+ quicConn2, err := quic.DialAddr(ctx, serverAddr, clientTLSConfig, tr.QUICConfig)
+ if err != nil {
+ t.Fatalf("failed to dial QUIC for raw conn: %v", err)
+ }
+ defer quicConn2.CloseWithError(0, "")
+
+ rawConn := tr.NewRawClientConn(quicConn2)
+ if rawConn == nil {
+ t.Fatal("NewRawClientConn returned nil")
+ }
+ if rawConn.ClientConn == nil {
+ t.Fatal("RawClientConn.ClientConn is nil")
+ }
+
+ t.Log("Successfully created ClientConn and RawClientConn")
+}
From 7024cd027b87525ed5a19f40c48ffa508f04839f Mon Sep 17 00:00:00 2001
From: Gary Willoughby
Date: Wed, 18 Mar 2026 12:19:05 +0000
Subject: [PATCH 2/6] Updated the module name.
---
.testdata/sample-file.txt | 2 +-
README.md | 50 +++++++++----------
client.go | 8 +--
client_impersonate.go | 2 +-
client_test.go | 4 +-
client_wrapper.go | 2 +-
decode.go | 3 +-
decode_test.go | 3 +-
digest.go | 2 +-
dump.go | 3 +-
examples/find-popular-repo/go.mod | 4 +-
examples/find-popular-repo/main.go | 2 +-
.../github/github.go | 7 +--
examples/opentelemetry-jaeger-tracing/go.mod | 4 +-
examples/upload/uploadclient/go.mod | 4 +-
examples/upload/uploadclient/main.go | 4 +-
examples/uploadcallback/uploadclient/go.mod | 4 +-
examples/uploadcallback/uploadclient/main.go | 3 +-
go.mod | 2 +-
header.go | 2 +-
http.go | 2 +-
http_request.go | 4 +-
internal/altsvcutil/altsvcutil.go | 5 +-
internal/altsvcutil/altsvcutil_test.go | 3 +-
internal/charsets/charsets_test.go | 3 +-
internal/chunked.go | 12 +++--
internal/godebug/godebug.go | 4 +-
internal/header/header.go | 2 +-
internal/http2/frame.go | 4 +-
internal/http2/headermap.go | 3 +-
internal/http2/transport.go | 18 +++----
internal/http3/client.go | 4 +-
internal/http3/conn.go | 2 +-
internal/http3/headers.go | 2 +-
internal/http3/request_writer.go | 4 +-
internal/http3/stream.go | 6 +--
internal/http3/transport.go | 2 +-
internal/http3/transport_test.go | 2 +-
internal/socks/socks_test.go | 3 +-
internal/transport/option.go | 2 +-
logger_test.go | 2 +-
middleware.go | 4 +-
req_test.go | 4 +-
request.go | 6 +--
request_test.go | 4 +-
response.go | 4 +-
retry_test.go | 2 +-
roundtrip_js.go | 2 +-
textproto_reader.go | 2 +-
transfer.go | 8 +--
transport.go | 30 +++++------
51 files changed, 141 insertions(+), 129 deletions(-)
diff --git a/.testdata/sample-file.txt b/.testdata/sample-file.txt
index 032120aa..a49a1205 100644
--- a/.testdata/sample-file.txt
+++ b/.testdata/sample-file.txt
@@ -1,3 +1,3 @@
THIS IS A SAMPLE FILE FOR TEST
-https://github.com/imroc/req
+https://github.com/ennismore/req
diff --git a/README.md b/README.md
index 2e71bd02..892c8018 100644
--- a/README.md
+++ b/README.md
@@ -4,13 +4,13 @@
Simple Go HTTP client with Black Magic
-
-
-
+
+
+
-
+
-
+
## Documentation
@@ -38,7 +38,7 @@ Full documentation is available on the official website: https://req.cool.
You first need [Go](https://go.dev/) installed (version 1.24+ is required), then you can use the below Go command to install req:
``` sh
-go get github.com/imroc/req/v3
+go get github.com/ennismore/req/v3
```
**Import**
@@ -46,7 +46,7 @@ go get github.com/imroc/req/v3
Import req to your code:
```go
-import "github.com/imroc/req/v3"
+import "github.com/ennismore/req/v3"
```
**Basic Usage**
@@ -60,7 +60,7 @@ $ cat main.go
package main
import (
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
)
func main() {
@@ -79,7 +79,7 @@ $ go run main.go
:method: GET
:path: /uuid
:scheme: https
-user-agent: req/v3 (https://github.com/imroc/req/v3)
+user-agent: req/v3 (https://github.com/ennismore/req/v3)
accept-encoding: gzip
:status: 200
@@ -97,7 +97,7 @@ access-control-allow-credentials: true
2022/05/19 10:05:09.340974 DEBUG [req] HTTP/1.1 GET https://httpbin.org/uuid
GET /uuid HTTP/1.1
Host: httpbin.org
-User-Agent: req/v3 (https://github.com/imroc/req/v3)
+User-Agent: req/v3 (https://github.com/ennismore/req/v3)
Accept-Encoding: gzip
HTTP/1.1 200 OK
@@ -136,7 +136,7 @@ package main
import (
"fmt"
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
"log"
)
@@ -164,7 +164,7 @@ package main
import (
"fmt"
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
"log"
"time"
)
@@ -232,7 +232,7 @@ package main
import (
"fmt"
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
"log"
"time"
)
@@ -296,7 +296,7 @@ package main
import (
"fmt"
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
"log"
)
@@ -314,7 +314,7 @@ func main() {
var result Result
resp, err := client.R().
- SetBody(&Repo{Name: "req", Url: "https://github.com/imroc/req"}).
+ SetBody(&Repo{Name: "req", Url: "https://github.com/ennismore/req"}).
SetSuccessResult(&result).
Post("https://httpbin.org/post")
if err != nil {
@@ -337,12 +337,12 @@ func main() {
:method: POST
:path: /post
:scheme: https
-user-agent: req/v3 (https://github.com/imroc/req/v3)
+user-agent: req/v3 (https://github.com/ennismore/req/v3)
content-type: application/json; charset=utf-8
content-length: 55
accept-encoding: gzip
-{"name":"req","website":"https://github.com/imroc/req"}
+{"name":"req","website":"https://github.com/ennismore/req"}
:status: 200
date: Thu, 19 May 2022 12:11:00 GMT
@@ -354,7 +354,7 @@ access-control-allow-credentials: true
{
"args": {},
- "data": "{\"name\":\"req\",\"website\":\"https://github.com/imroc/req\"}",
+ "data": "{\"name\":\"req\",\"website\":\"https://github.com/ennismore/req\"}",
"files": {},
"form": {},
"headers": {
@@ -362,19 +362,19 @@ access-control-allow-credentials: true
"Content-Length": "55",
"Content-Type": "application/json; charset=utf-8",
"Host": "httpbin.org",
- "User-Agent": "req/v3 (https://github.com/imroc/req/v3)",
+ "User-Agent": "req/v3 (https://github.com/ennismore/req/v3)",
"X-Amzn-Trace-Id": "Root=1-628633d4-7559d633152b4307288ead2e"
},
"json": {
"name": "req",
- "website": "https://github.com/imroc/req"
+ "website": "https://github.com/ennismore/req"
},
"origin": "103.7.29.30",
"url": "https://httpbin.org/post"
}
++++++++++++++++++++++++++++++++++++++++++++++++
-data: {"name":"req","url":"https://github.com/imroc/req"}
+data: {"name":"req","url":"https://github.com/ennismore/req"}
++++++++++++++++++++++++++++++++++++++++++++++++
```
@@ -387,7 +387,7 @@ package main
import (
"fmt"
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
)
type APIResponse struct {
@@ -425,7 +425,7 @@ Here is an example of building GitHub's SDK with req, using two styles (`GetUser
import (
"context"
"fmt"
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
)
type ErrorMessage struct {
@@ -502,13 +502,13 @@ func (c *GithubClient) GetUserProfile_Style2(ctx context.Context, username strin
## Contributing
-If you have a bug report or feature request, you can [open an issue](https://github.com/imroc/req/issues/new), and [pull requests](https://github.com/imroc/req/pulls) are also welcome.
+If you have a bug report or feature request, you can [open an issue](https://github.com/ennismore/req/issues/new), and [pull requests](https://github.com/ennismore/req/pulls) are also welcome.
## Contact
If you have questions, feel free to reach out to us in the following ways:
-* [Github Discussion](https://github.com/imroc/req/discussions)
+* [Github Discussion](https://github.com/ennismore/req/discussions)
* [Slack](https://imroc-req.slack.com/archives/C03UFPGSNC8) | [Join](https://slack.req.cool/)
## Sponsors
diff --git a/client.go b/client.go
index e9db4b8c..664c7649 100644
--- a/client.go
+++ b/client.go
@@ -21,9 +21,9 @@ import (
utls "github.com/refraction-networking/utls"
"golang.org/x/net/publicsuffix"
- "github.com/imroc/req/v3/http2"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/util"
+ "github.com/ennismore/req/v3/http2"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/util"
"github.com/google/go-querystring/query"
)
@@ -557,7 +557,7 @@ func (c *Client) DevMode() *Client {
}
// SetScheme set the default scheme for client, will be used when
-// there is no scheme in the request URL (e.g. "github.com/imroc/req").
+// there is no scheme in the request URL (e.g. "github.com/ennismore/req").
func (c *Client) SetScheme(scheme string) *Client {
if !util.IsStringEmpty(scheme) {
c.scheme = strings.TrimSpace(scheme)
diff --git a/client_impersonate.go b/client_impersonate.go
index dfa9235e..030f9783 100644
--- a/client_impersonate.go
+++ b/client_impersonate.go
@@ -7,7 +7,7 @@ import (
"strconv"
"strings"
- "github.com/imroc/req/v3/http2"
+ "github.com/ennismore/req/v3/http2"
utls "github.com/refraction-networking/utls"
)
diff --git a/client_test.go b/client_test.go
index 8f7bc9b0..2562885b 100644
--- a/client_test.go
+++ b/client_test.go
@@ -17,8 +17,8 @@ import (
"testing"
"time"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/tests"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/tests"
"golang.org/x/net/publicsuffix"
)
diff --git a/client_wrapper.go b/client_wrapper.go
index 74c5312e..51d2da4d 100644
--- a/client_wrapper.go
+++ b/client_wrapper.go
@@ -9,7 +9,7 @@ import (
"net/url"
"time"
- "github.com/imroc/req/v3/http2"
+ "github.com/ennismore/req/v3/http2"
utls "github.com/refraction-networking/utls"
)
diff --git a/decode.go b/decode.go
index 825cffc6..d9173717 100644
--- a/decode.go
+++ b/decode.go
@@ -1,9 +1,10 @@
package req
import (
- "github.com/imroc/req/v3/internal/charsets"
"io"
"strings"
+
+ "github.com/ennismore/req/v3/internal/charsets"
)
var textContentTypes = []string{"text", "json", "xml", "html", "java"}
diff --git a/decode_test.go b/decode_test.go
index e65a8ea6..fd6ce4f9 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1,8 +1,9 @@
package req
import (
- "github.com/imroc/req/v3/internal/tests"
"testing"
+
+ "github.com/ennismore/req/v3/internal/tests"
)
func TestPeekDrain(t *testing.T) {
diff --git a/digest.go b/digest.go
index 0695d8c3..1766378c 100644
--- a/digest.go
+++ b/digest.go
@@ -6,8 +6,8 @@ import (
"net/http"
"sync"
+ "github.com/ennismore/req/v3/internal/header"
"github.com/icholy/digest"
- "github.com/imroc/req/v3/internal/header"
)
// cchal is a cached challenge and the number of times it's been used.
diff --git a/dump.go b/dump.go
index 77f96349..594fd4d5 100644
--- a/dump.go
+++ b/dump.go
@@ -1,9 +1,10 @@
package req
import (
- "github.com/imroc/req/v3/internal/dump"
"io"
"os"
+
+ "github.com/ennismore/req/v3/internal/dump"
)
// DumpOptions controls the dump behavior.
diff --git a/examples/find-popular-repo/go.mod b/examples/find-popular-repo/go.mod
index 86ab366e..7c0159e8 100644
--- a/examples/find-popular-repo/go.mod
+++ b/examples/find-popular-repo/go.mod
@@ -4,9 +4,9 @@ go 1.24
toolchain go1.24.4
-replace github.com/imroc/req/v3 => ../../
+replace github.com/ennismore/req/v3 => ../../
-require github.com/imroc/req/v3 v3.0.0
+require github.com/ennismore/req/v3 v3.0.0
require (
github.com/andybalholm/brotli v1.2.0 // indirect
diff --git a/examples/find-popular-repo/main.go b/examples/find-popular-repo/main.go
index 44708f3b..ed5099da 100644
--- a/examples/find-popular-repo/main.go
+++ b/examples/find-popular-repo/main.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strconv"
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
)
// Change the name if you want
diff --git a/examples/opentelemetry-jaeger-tracing/github/github.go b/examples/opentelemetry-jaeger-tracing/github/github.go
index b7898301..f17be3c1 100644
--- a/examples/opentelemetry-jaeger-tracing/github/github.go
+++ b/examples/opentelemetry-jaeger-tracing/github/github.go
@@ -3,12 +3,13 @@ package github
import (
"context"
"fmt"
- "github.com/imroc/req/v3"
+ "strconv"
+ "strings"
+
+ "github.com/ennismore/req/v3"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
- "strconv"
- "strings"
)
// Client is the go client for GitHub API.
diff --git a/examples/opentelemetry-jaeger-tracing/go.mod b/examples/opentelemetry-jaeger-tracing/go.mod
index eb0dc4ac..5e7a958b 100644
--- a/examples/opentelemetry-jaeger-tracing/go.mod
+++ b/examples/opentelemetry-jaeger-tracing/go.mod
@@ -4,10 +4,10 @@ go 1.24
toolchain go1.24.4
-replace github.com/imroc/req/v3 => ../../
+replace github.com/ennismore/req/v3 => ../../
require (
- github.com/imroc/req/v3 v3.0.0
+ github.com/ennismore/req/v3 v3.0.0
go.opentelemetry.io/otel v1.9.0
go.opentelemetry.io/otel/exporters/jaeger v1.9.0
go.opentelemetry.io/otel/sdk v1.9.0
diff --git a/examples/upload/uploadclient/go.mod b/examples/upload/uploadclient/go.mod
index 3503e383..a4ee9c5a 100644
--- a/examples/upload/uploadclient/go.mod
+++ b/examples/upload/uploadclient/go.mod
@@ -4,9 +4,9 @@ go 1.24
toolchain go1.24.4
-replace github.com/imroc/req/v3 => ../../../
+replace github.com/ennismore/req/v3 => ../../../
-require github.com/imroc/req/v3 v3.0.0
+require github.com/ennismore/req/v3 v3.0.0
require (
github.com/andybalholm/brotli v1.2.0 // indirect
diff --git a/examples/upload/uploadclient/main.go b/examples/upload/uploadclient/main.go
index d9c8fd34..e76e0725 100644
--- a/examples/upload/uploadclient/main.go
+++ b/examples/upload/uploadclient/main.go
@@ -1,7 +1,7 @@
package main
import (
- "github.com/imroc/req/v3"
+ "github.com/ennismore/req/v3"
)
func main() {
@@ -16,7 +16,7 @@ func main() {
/* Output
POST /upload HTTP/1.1
Host: 127.0.0.1:8888
- User-Agent: req/v2 (https://github.com/imroc/req)
+ User-Agent: req/v2 (https://github.com/ennismore/req)
Transfer-Encoding: chunked
Content-Type: multipart/form-data; boundary=6af1b071a682709355cf5fb15b9cf9e793df7a45e5cd1eb7c413f2e72bf6
Accept-Encoding: gzip
diff --git a/examples/uploadcallback/uploadclient/go.mod b/examples/uploadcallback/uploadclient/go.mod
index 3503e383..a4ee9c5a 100644
--- a/examples/uploadcallback/uploadclient/go.mod
+++ b/examples/uploadcallback/uploadclient/go.mod
@@ -4,9 +4,9 @@ go 1.24
toolchain go1.24.4
-replace github.com/imroc/req/v3 => ../../../
+replace github.com/ennismore/req/v3 => ../../../
-require github.com/imroc/req/v3 v3.0.0
+require github.com/ennismore/req/v3 v3.0.0
require (
github.com/andybalholm/brotli v1.2.0 // indirect
diff --git a/examples/uploadcallback/uploadclient/main.go b/examples/uploadcallback/uploadclient/main.go
index 19dd217e..9cb48cd8 100644
--- a/examples/uploadcallback/uploadclient/main.go
+++ b/examples/uploadcallback/uploadclient/main.go
@@ -4,7 +4,8 @@ import (
"fmt"
"io"
"time"
- "github.com/imroc/req/v3"
+
+ "github.com/ennismore/req/v3"
)
type SlowReader struct {
diff --git a/go.mod b/go.mod
index ff4b7795..cf8e73f8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/imroc/req/v3
+module github.com/ennismore/req/v3
go 1.24.0
diff --git a/header.go b/header.go
index 9ded8623..c719a37e 100644
--- a/header.go
+++ b/header.go
@@ -10,7 +10,7 @@ import (
"golang.org/x/net/http/httpguts"
- "github.com/imroc/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/header"
)
var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
diff --git a/http.go b/http.go
index 61a63676..8c05d694 100644
--- a/http.go
+++ b/http.go
@@ -8,7 +8,7 @@ import (
"net/textproto"
"strings"
- "github.com/imroc/req/v3/internal/ascii"
+ "github.com/ennismore/req/v3/internal/ascii"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/idna"
)
diff --git a/http_request.go b/http_request.go
index 5816de44..8819ad9e 100644
--- a/http_request.go
+++ b/http_request.go
@@ -7,8 +7,8 @@ import (
"golang.org/x/net/http/httpguts"
- "github.com/imroc/req/v3/internal/ascii"
- "github.com/imroc/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/ascii"
+ "github.com/ennismore/req/v3/internal/header"
)
// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
diff --git a/internal/altsvcutil/altsvcutil.go b/internal/altsvcutil/altsvcutil.go
index 84978d7e..759ab640 100644
--- a/internal/altsvcutil/altsvcutil.go
+++ b/internal/altsvcutil/altsvcutil.go
@@ -3,14 +3,15 @@ package altsvcutil
import (
"bytes"
"fmt"
- "github.com/imroc/req/v3/internal/netutil"
- "github.com/imroc/req/v3/pkg/altsvc"
"io"
"net"
"net/url"
"strconv"
"strings"
"time"
+
+ "github.com/ennismore/req/v3/internal/netutil"
+ "github.com/ennismore/req/v3/pkg/altsvc"
)
type altAvcParser struct {
diff --git a/internal/altsvcutil/altsvcutil_test.go b/internal/altsvcutil/altsvcutil_test.go
index 3cbc0019..5a6a54c2 100644
--- a/internal/altsvcutil/altsvcutil_test.go
+++ b/internal/altsvcutil/altsvcutil_test.go
@@ -1,8 +1,9 @@
package altsvcutil
import (
- "github.com/imroc/req/v3/internal/tests"
"testing"
+
+ "github.com/ennismore/req/v3/internal/tests"
)
func TestParseHeader(t *testing.T) {
diff --git a/internal/charsets/charsets_test.go b/internal/charsets/charsets_test.go
index 28cd698a..c758120e 100644
--- a/internal/charsets/charsets_test.go
+++ b/internal/charsets/charsets_test.go
@@ -5,10 +5,11 @@
package charsets
import (
- "github.com/imroc/req/v3/internal/tests"
"os"
"runtime"
"testing"
+
+ "github.com/ennismore/req/v3/internal/tests"
)
var sniffTestCases = []struct {
diff --git a/internal/chunked.go b/internal/chunked.go
index dec4ddca..d30f13fd 100644
--- a/internal/chunked.go
+++ b/internal/chunked.go
@@ -13,8 +13,9 @@ import (
"bytes"
"errors"
"fmt"
- "github.com/imroc/req/v3/internal/util"
"io"
+
+ "github.com/ennismore/req/v3/internal/util"
)
const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
@@ -165,10 +166,11 @@ var semi = []byte(";")
// removeChunkExtension removes any chunk-extension from p.
// For example,
-// "0" => "0"
-// "0;token" => "0"
-// "0;token=val" => "0"
-// `0;token="quoted string"` => "0"
+//
+// "0" => "0"
+// "0;token" => "0"
+// "0;token=val" => "0"
+// `0;token="quoted string"` => "0"
func removeChunkExtension(p []byte) ([]byte, error) {
p, _, _ = util.CutBytes(p, semi)
// TODO: care about exact syntax of chunk extensions? We're
diff --git a/internal/godebug/godebug.go b/internal/godebug/godebug.go
index f5a0f53a..66ef8fc5 100644
--- a/internal/godebug/godebug.go
+++ b/internal/godebug/godebug.go
@@ -38,8 +38,8 @@ import (
"sync/atomic"
_ "unsafe" // go:linkname
- "github.com/imroc/req/v3/internal/bisect"
- "github.com/imroc/req/v3/internal/godebugs"
+ "github.com/ennismore/req/v3/internal/bisect"
+ "github.com/ennismore/req/v3/internal/godebugs"
)
// A Setting is a single setting in the $GODEBUG environment variable.
diff --git a/internal/header/header.go b/internal/header/header.go
index 4098febe..0459468c 100644
--- a/internal/header/header.go
+++ b/internal/header/header.go
@@ -3,7 +3,7 @@ package header
import "strings"
const (
- DefaultUserAgent = "req/v3 (https://github.com/imroc/req)"
+ DefaultUserAgent = "req/v3 (https://github.com/ennismore/req)"
UserAgent = "User-Agent"
Location = "Location"
ContentType = "Content-Type"
diff --git a/internal/http2/frame.go b/internal/http2/frame.go
index 23c10936..7146a8d3 100644
--- a/internal/http2/frame.go
+++ b/internal/http2/frame.go
@@ -16,8 +16,8 @@ import (
"strings"
"sync"
- "github.com/imroc/req/v3/http2"
- "github.com/imroc/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/http2"
+ "github.com/ennismore/req/v3/internal/dump"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
)
diff --git a/internal/http2/headermap.go b/internal/http2/headermap.go
index a8e01cf9..62984bc3 100644
--- a/internal/http2/headermap.go
+++ b/internal/http2/headermap.go
@@ -5,9 +5,10 @@
package http2
import (
- "github.com/imroc/req/v3/internal/ascii"
"net/http"
"sync"
+
+ "github.com/ennismore/req/v3/internal/ascii"
)
var (
diff --git a/internal/http2/transport.go b/internal/http2/transport.go
index 3677f190..25da54ef 100644
--- a/internal/http2/transport.go
+++ b/internal/http2/transport.go
@@ -35,15 +35,15 @@ import (
"golang.org/x/net/http2/hpack"
"golang.org/x/net/idna"
- "github.com/imroc/req/v3/http2"
- "github.com/imroc/req/v3/internal/ascii"
- "github.com/imroc/req/v3/internal/common"
- "github.com/imroc/req/v3/internal/compress"
- "github.com/imroc/req/v3/internal/dump"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/netutil"
- "github.com/imroc/req/v3/internal/transport"
- reqtls "github.com/imroc/req/v3/pkg/tls"
+ "github.com/ennismore/req/v3/http2"
+ "github.com/ennismore/req/v3/internal/ascii"
+ "github.com/ennismore/req/v3/internal/common"
+ "github.com/ennismore/req/v3/internal/compress"
+ "github.com/ennismore/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/netutil"
+ "github.com/ennismore/req/v3/internal/transport"
+ reqtls "github.com/ennismore/req/v3/pkg/tls"
)
const (
diff --git a/internal/http3/client.go b/internal/http3/client.go
index f1a85b11..8c032e11 100644
--- a/internal/http3/client.go
+++ b/internal/http3/client.go
@@ -12,8 +12,8 @@ import (
"net/textproto"
"time"
- "github.com/imroc/req/v3/internal/dump"
- "github.com/imroc/req/v3/internal/transport"
+ "github.com/ennismore/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/transport"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3/qlog"
"github.com/quic-go/quic-go/quicvarint"
diff --git a/internal/http3/conn.go b/internal/http3/conn.go
index b1f09c23..a035b04e 100644
--- a/internal/http3/conn.go
+++ b/internal/http3/conn.go
@@ -13,7 +13,7 @@ import (
"sync/atomic"
"time"
- "github.com/imroc/req/v3/internal/transport"
+ "github.com/ennismore/req/v3/internal/transport"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3/qlog"
"github.com/quic-go/quic-go/qlogwriter"
diff --git a/internal/http3/headers.go b/internal/http3/headers.go
index ff1ac659..103bfea6 100644
--- a/internal/http3/headers.go
+++ b/internal/http3/headers.go
@@ -11,7 +11,7 @@ import (
"golang.org/x/net/http/httpguts"
- "github.com/imroc/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/dump"
"github.com/quic-go/qpack"
)
diff --git a/internal/http3/request_writer.go b/internal/http3/request_writer.go
index 187d58b8..efc1a748 100644
--- a/internal/http3/request_writer.go
+++ b/internal/http3/request_writer.go
@@ -12,8 +12,8 @@ import (
"strings"
"sync"
- "github.com/imroc/req/v3/internal/dump"
- reqheader "github.com/imroc/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/dump"
+ reqheader "github.com/ennismore/req/v3/internal/header"
"github.com/quic-go/qpack"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3/qlog"
diff --git a/internal/http3/stream.go b/internal/http3/stream.go
index 025f43e2..81416c1c 100644
--- a/internal/http3/stream.go
+++ b/internal/http3/stream.go
@@ -9,9 +9,9 @@ import (
"net/http/httptrace"
"time"
- "github.com/imroc/req/v3/internal/compress"
- "github.com/imroc/req/v3/internal/dump"
- "github.com/imroc/req/v3/internal/transport"
+ "github.com/ennismore/req/v3/internal/compress"
+ "github.com/ennismore/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/transport"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3/qlog"
"github.com/quic-go/quic-go/qlogwriter"
diff --git a/internal/http3/transport.go b/internal/http3/transport.go
index acde40df..780d6c9f 100644
--- a/internal/http3/transport.go
+++ b/internal/http3/transport.go
@@ -17,7 +17,7 @@ import (
"golang.org/x/net/http/httpguts"
- "github.com/imroc/req/v3/internal/transport"
+ "github.com/ennismore/req/v3/internal/transport"
"github.com/quic-go/quic-go"
)
diff --git a/internal/http3/transport_test.go b/internal/http3/transport_test.go
index 4c8713c7..fd6769ce 100644
--- a/internal/http3/transport_test.go
+++ b/internal/http3/transport_test.go
@@ -7,7 +7,7 @@ import (
"testing"
"time"
- "github.com/imroc/req/v3/internal/testcert"
+ "github.com/ennismore/req/v3/internal/testcert"
"github.com/quic-go/quic-go"
)
diff --git a/internal/socks/socks_test.go b/internal/socks/socks_test.go
index 824a09d7..6cbe1d71 100644
--- a/internal/socks/socks_test.go
+++ b/internal/socks/socks_test.go
@@ -3,9 +3,10 @@ package socks
import (
"bytes"
"context"
- "github.com/imroc/req/v3/internal/tests"
"strings"
"testing"
+
+ "github.com/ennismore/req/v3/internal/tests"
)
func TestReply(t *testing.T) {
diff --git a/internal/transport/option.go b/internal/transport/option.go
index d45b51c1..2fc30fc0 100644
--- a/internal/transport/option.go
+++ b/internal/transport/option.go
@@ -8,7 +8,7 @@ import (
"net/url"
"time"
- "github.com/imroc/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/dump"
)
// Options is transport's options.
diff --git a/logger_test.go b/logger_test.go
index 8a456da8..9598bc7c 100644
--- a/logger_test.go
+++ b/logger_test.go
@@ -5,7 +5,7 @@ import (
"log"
"testing"
- "github.com/imroc/req/v3/internal/tests"
+ "github.com/ennismore/req/v3/internal/tests"
)
func TestLogger(t *testing.T) {
diff --git a/middleware.go b/middleware.go
index 54129d89..34c31fd1 100644
--- a/middleware.go
+++ b/middleware.go
@@ -14,8 +14,8 @@ import (
"strings"
"time"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/util"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/util"
)
type (
diff --git a/req_test.go b/req_test.go
index 9942bcb9..c8b9e41e 100644
--- a/req_test.go
+++ b/req_test.go
@@ -18,8 +18,8 @@ import (
"testing"
"unsafe"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/tests"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/tests"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
diff --git a/request.go b/request.go
index d7695a32..fbb78d5b 100644
--- a/request.go
+++ b/request.go
@@ -14,10 +14,10 @@ import (
"strings"
"time"
+ "github.com/ennismore/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/util"
"github.com/google/go-querystring/query"
- "github.com/imroc/req/v3/internal/dump"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/util"
)
// Request struct is used to compose and fire individual request from
diff --git a/request_test.go b/request_test.go
index a1c649a3..79cd6403 100644
--- a/request_test.go
+++ b/request_test.go
@@ -14,8 +14,8 @@ import (
"testing"
"time"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/tests"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/tests"
)
func TestMustSendMethods(t *testing.T) {
diff --git a/response.go b/response.go
index 69aee127..e2676838 100644
--- a/response.go
+++ b/response.go
@@ -6,8 +6,8 @@ import (
"strings"
"time"
- "github.com/imroc/req/v3/internal/header"
- "github.com/imroc/req/v3/internal/util"
+ "github.com/ennismore/req/v3/internal/header"
+ "github.com/ennismore/req/v3/internal/util"
)
// Response is the http response.
diff --git a/retry_test.go b/retry_test.go
index 5814b5fe..028e04d5 100644
--- a/retry_test.go
+++ b/retry_test.go
@@ -8,7 +8,7 @@ import (
"testing"
"time"
- "github.com/imroc/req/v3/internal/tests"
+ "github.com/ennismore/req/v3/internal/tests"
)
func TestRetryBackOff(t *testing.T) {
diff --git a/roundtrip_js.go b/roundtrip_js.go
index 958d9a4b..09784e42 100644
--- a/roundtrip_js.go
+++ b/roundtrip_js.go
@@ -15,7 +15,7 @@ import (
"strings"
"syscall/js"
- "github.com/imroc/req/v3/internal/ascii"
+ "github.com/ennismore/req/v3/internal/ascii"
)
var uint8Array = js.Global().Get("Uint8Array")
diff --git a/textproto_reader.go b/textproto_reader.go
index 64f3bb28..d072ad2b 100644
--- a/textproto_reader.go
+++ b/textproto_reader.go
@@ -13,7 +13,7 @@ import (
"net/textproto"
"sync"
- "github.com/imroc/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/dump"
)
func isASCIILetter(b byte) bool {
diff --git a/transfer.go b/transfer.go
index 6af7431c..d8ae31a7 100644
--- a/transfer.go
+++ b/transfer.go
@@ -19,10 +19,10 @@ import (
"sync"
"time"
- "github.com/imroc/req/v3/internal"
- "github.com/imroc/req/v3/internal/ascii"
- "github.com/imroc/req/v3/internal/dump"
- "github.com/imroc/req/v3/internal/godebug"
+ "github.com/ennismore/req/v3/internal"
+ "github.com/ennismore/req/v3/internal/ascii"
+ "github.com/ennismore/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/godebug"
"golang.org/x/net/http/httpguts"
)
diff --git a/transport.go b/transport.go
index 1c549b16..3077f974 100644
--- a/transport.go
+++ b/transport.go
@@ -32,21 +32,21 @@ import (
"time"
_ "unsafe"
- "github.com/imroc/req/v3/http2"
- "github.com/imroc/req/v3/internal/altsvcutil"
- "github.com/imroc/req/v3/internal/ascii"
- "github.com/imroc/req/v3/internal/common"
- "github.com/imroc/req/v3/internal/compress"
- "github.com/imroc/req/v3/internal/dump"
- "github.com/imroc/req/v3/internal/header"
- h2internal "github.com/imroc/req/v3/internal/http2"
- "github.com/imroc/req/v3/internal/http3"
- "github.com/imroc/req/v3/internal/netutil"
- "github.com/imroc/req/v3/internal/socks"
- "github.com/imroc/req/v3/internal/transport"
- "github.com/imroc/req/v3/internal/util"
- "github.com/imroc/req/v3/pkg/altsvc"
- reqtls "github.com/imroc/req/v3/pkg/tls"
+ "github.com/ennismore/req/v3/http2"
+ "github.com/ennismore/req/v3/internal/altsvcutil"
+ "github.com/ennismore/req/v3/internal/ascii"
+ "github.com/ennismore/req/v3/internal/common"
+ "github.com/ennismore/req/v3/internal/compress"
+ "github.com/ennismore/req/v3/internal/dump"
+ "github.com/ennismore/req/v3/internal/header"
+ h2internal "github.com/ennismore/req/v3/internal/http2"
+ "github.com/ennismore/req/v3/internal/http3"
+ "github.com/ennismore/req/v3/internal/netutil"
+ "github.com/ennismore/req/v3/internal/socks"
+ "github.com/ennismore/req/v3/internal/transport"
+ "github.com/ennismore/req/v3/internal/util"
+ "github.com/ennismore/req/v3/pkg/altsvc"
+ reqtls "github.com/ennismore/req/v3/pkg/tls"
htmlcharset "golang.org/x/net/html/charset"
"golang.org/x/text/encoding/ianaindex"
From 9cbd4d4799b695bd124cbebd2ee6e14d4d668ab7 Mon Sep 17 00:00:00 2001
From: Gary Willoughby
Date: Wed, 18 Mar 2026 12:27:37 +0000
Subject: [PATCH 3/6] Removed examples due to security issues.
---
examples/README.md | 4 -
examples/find-popular-repo/README.md | 17 --
examples/find-popular-repo/go.mod | 27 ---
examples/find-popular-repo/go.sum | 44 ----
examples/find-popular-repo/main.go | 97 ---------
.../opentelemetry-jaeger-tracing/README.md | 30 ---
.../github/github.go | 193 ------------------
examples/opentelemetry-jaeger-tracing/go.mod | 35 ----
examples/opentelemetry-jaeger-tracing/go.sum | 59 ------
examples/opentelemetry-jaeger-tracing/main.go | 162 ---------------
examples/upload/README.md | 19 --
examples/upload/uploadclient/go.mod | 27 ---
examples/upload/uploadclient/go.sum | 44 ----
examples/upload/uploadclient/main.go | 31 ---
examples/upload/uploadserver/go.mod | 26 ---
examples/upload/uploadserver/go.sum | 92 ---------
examples/upload/uploadserver/main.go | 35 ----
examples/uploadcallback/README.md | 19 --
examples/uploadcallback/uploadclient/go.mod | 27 ---
examples/uploadcallback/uploadclient/go.sum | 44 ----
examples/uploadcallback/uploadclient/main.go | 48 -----
examples/uploadcallback/uploadserver/go.mod | 26 ---
examples/uploadcallback/uploadserver/go.sum | 92 ---------
examples/uploadcallback/uploadserver/main.go | 17 --
24 files changed, 1215 deletions(-)
delete mode 100644 examples/README.md
delete mode 100644 examples/find-popular-repo/README.md
delete mode 100644 examples/find-popular-repo/go.mod
delete mode 100644 examples/find-popular-repo/go.sum
delete mode 100644 examples/find-popular-repo/main.go
delete mode 100644 examples/opentelemetry-jaeger-tracing/README.md
delete mode 100644 examples/opentelemetry-jaeger-tracing/github/github.go
delete mode 100644 examples/opentelemetry-jaeger-tracing/go.mod
delete mode 100644 examples/opentelemetry-jaeger-tracing/go.sum
delete mode 100644 examples/opentelemetry-jaeger-tracing/main.go
delete mode 100644 examples/upload/README.md
delete mode 100644 examples/upload/uploadclient/go.mod
delete mode 100644 examples/upload/uploadclient/go.sum
delete mode 100644 examples/upload/uploadclient/main.go
delete mode 100644 examples/upload/uploadserver/go.mod
delete mode 100644 examples/upload/uploadserver/go.sum
delete mode 100644 examples/upload/uploadserver/main.go
delete mode 100644 examples/uploadcallback/README.md
delete mode 100644 examples/uploadcallback/uploadclient/go.mod
delete mode 100644 examples/uploadcallback/uploadclient/go.sum
delete mode 100644 examples/uploadcallback/uploadclient/main.go
delete mode 100644 examples/uploadcallback/uploadserver/go.mod
delete mode 100644 examples/uploadcallback/uploadserver/go.sum
delete mode 100644 examples/uploadcallback/uploadserver/main.go
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index 5ec6097e..00000000
--- a/examples/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# examples
-
-* [find-popular-repo](find-popular-repo): Invoke github api to find someone's most popular repo.
-* [upload](upload): Use `req` to upload files. Contains a server written with `gin` and a client written with `req`
\ No newline at end of file
diff --git a/examples/find-popular-repo/README.md b/examples/find-popular-repo/README.md
deleted file mode 100644
index a95944a8..00000000
--- a/examples/find-popular-repo/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# find-popular-repo
-
-This is a runable example of req, using the Github API [List repositories for a user](https://docs.github.com/cn/rest/reference/repos#list-repositories-for-a-user) to find someone's the most popular github repo.
-
-## How to run
-
-```bash
-go run .
-```
-
-## Modify it
-
-Change the global `username` variable to your own github username:
-
-```go
-var username = "imroc"
-```
\ No newline at end of file
diff --git a/examples/find-popular-repo/go.mod b/examples/find-popular-repo/go.mod
deleted file mode 100644
index 7c0159e8..00000000
--- a/examples/find-popular-repo/go.mod
+++ /dev/null
@@ -1,27 +0,0 @@
-module find-popular-repo
-
-go 1.24
-
-toolchain go1.24.4
-
-replace github.com/ennismore/req/v3 => ../../
-
-require github.com/ennismore/req/v3 v3.0.0
-
-require (
- github.com/andybalholm/brotli v1.2.0 // indirect
- github.com/cloudflare/circl v1.6.1 // indirect
- github.com/icholy/digest v1.1.0 // indirect
- github.com/klauspost/compress v1.18.0 // indirect
- github.com/quic-go/qpack v0.5.1 // indirect
- github.com/quic-go/quic-go v0.53.0 // indirect
- github.com/refraction-networking/utls v1.7.3 // indirect
- go.uber.org/mock v0.5.2 // indirect
- golang.org/x/crypto v0.39.0 // indirect
- golang.org/x/mod v0.25.0 // indirect
- golang.org/x/net v0.41.0 // indirect
- golang.org/x/sync v0.15.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- golang.org/x/tools v0.34.0 // indirect
-)
diff --git a/examples/find-popular-repo/go.sum b/examples/find-popular-repo/go.sum
deleted file mode 100644
index b67b187c..00000000
--- a/examples/find-popular-repo/go.sum
+++ /dev/null
@@ -1,44 +0,0 @@
-github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
-github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
-github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
-github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
-github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
-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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
-github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI=
-github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
-github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
-github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
-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/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
-github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
-go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
-go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
-golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
-golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
-golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
-golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
-gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
diff --git a/examples/find-popular-repo/main.go b/examples/find-popular-repo/main.go
deleted file mode 100644
index ed5099da..00000000
--- a/examples/find-popular-repo/main.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package main
-
-import (
- "fmt"
- "strconv"
-
- "github.com/ennismore/req/v3"
-)
-
-// Change the name if you want
-var username = "imroc"
-
-func main() {
- repo, star, err := findTheMostPopularRepo(username)
- if err != nil {
- fmt.Println(err)
- return
- }
- fmt.Printf("The most popular repo of %s is %s, which have %d stars\n", username, repo, star)
-}
-
-func init() {
- req.EnableDebugLog().
- EnableTraceAll().
- EnableDumpEachRequest().
- SetCommonErrorResult(&ErrorMessage{}).
- OnAfterResponse(func(client *req.Client, resp *req.Response) error {
- if resp.Err != nil {
- return nil
- }
- if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok {
- resp.Err = errMsg
- return nil
- }
- if !resp.IsSuccessState() {
- resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump())
- }
- return nil
- })
-}
-
-type Repo struct {
- Name string `json:"name"`
- Star int `json:"stargazers_count"`
-}
-type ErrorMessage struct {
- Message string `json:"message"`
-}
-
-func (msg *ErrorMessage) Error() string {
- return fmt.Sprintf("API Error: %s", msg.Message)
-}
-
-func findTheMostPopularRepo(username string) (repo string, star int, err error) {
- var popularRepo Repo
- var resp *req.Response
-
- for page := 1; ; page++ {
- repos := []*Repo{}
- resp, err = req.SetHeader("Accept", "application/vnd.github.v3+json").
- SetQueryParams(map[string]string{
- "type": "owner",
- "page": strconv.Itoa(page),
- "per_page": "100",
- "sort": "updated",
- "direction": "desc",
- }).
- SetPathParam("username", username).
- SetSuccessResult(&repos).
- Get("https://api.github.com/users/{username}/repos")
-
- fmt.Println("TraceInfo:")
- fmt.Println("----------")
- fmt.Println(resp.TraceInfo())
- fmt.Println()
-
- if err != nil {
- return
- }
-
- if !resp.IsSuccessState() { // HTTP status `code >= 200 and <= 299` is considered as success by default
- return
- }
- for _, repo := range repos {
- if repo.Star >= popularRepo.Star {
- popularRepo = *repo
- }
- }
- if len(repo) == 100 { // Try Next page
- continue
- }
- // All repos have been traversed, return the final result
- repo = popularRepo.Name
- star = popularRepo.Star
- return
- }
-}
diff --git a/examples/opentelemetry-jaeger-tracing/README.md b/examples/opentelemetry-jaeger-tracing/README.md
deleted file mode 100644
index 3dfa4a56..00000000
--- a/examples/opentelemetry-jaeger-tracing/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# opentelemetry-jaeger-tracing
-
-This is a runnable example of req, which uses the built-in tiny github sdk built on req to query and display the information of the specified user.
-
-Best of all, it integrates seamlessly with jaeger tracing and is very easy to extend.
-
-## How to run
-
-First, use `docker` or `podman` to start a test jeager container (see jeager official doc: [ Getting Started](https://www.jaegertracing.io/docs/1.37/getting-started/#all-in-one)).
-
-Then, run example:
-
-```bash
-go run .
-```
-```txt
-Please give a github username:
-```
-
-Input a github username, e.g. `imroc`:
-
-```bash
-$ go run .
-Please give a github username: imroc
-The moust popular repo of roc (https://imroc.cc) is req, which have 2500 stars
-```
-
-Then enter the Jaeger UI with browser (`http://127.0.0.1:16686/`), checkout the tracing details.
-
-Run example again, try to input some username that doesn't exist, and check the error log in Jaeger UI.
diff --git a/examples/opentelemetry-jaeger-tracing/github/github.go b/examples/opentelemetry-jaeger-tracing/github/github.go
deleted file mode 100644
index f17be3c1..00000000
--- a/examples/opentelemetry-jaeger-tracing/github/github.go
+++ /dev/null
@@ -1,193 +0,0 @@
-package github
-
-import (
- "context"
- "fmt"
- "strconv"
- "strings"
-
- "github.com/ennismore/req/v3"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/codes"
- "go.opentelemetry.io/otel/trace"
-)
-
-// Client is the go client for GitHub API.
-type Client struct {
- *req.Client
-}
-
-// APIError represents the error message that GitHub API returns.
-// GitHub API doc: https://docs.github.com/en/rest/overview/resources-in-the-rest-api#client-errors
-type APIError struct {
- Message string `json:"message"`
- DocumentationUrl string `json:"documentation_url,omitempty"`
- Errors []struct {
- Resource string `json:"resource"`
- Field string `json:"field"`
- Code string `json:"code"`
- } `json:"errors,omitempty"`
-}
-
-// Error convert APIError to a human readable error and return.
-func (e *APIError) Error() string {
- msg := fmt.Sprintf("API error: %s", e.Message)
- if e.DocumentationUrl != "" {
- return fmt.Sprintf("%s (see doc %s)", msg, e.DocumentationUrl)
- }
- if len(e.Errors) == 0 {
- return msg
- }
- errs := []string{}
- for _, err := range e.Errors {
- errs = append(errs, fmt.Sprintf("resource:%s field:%s code:%s", err.Resource, err.Field, err.Code))
- }
- return fmt.Sprintf("%s (%s)", msg, strings.Join(errs, " | "))
-}
-
-// NewClient create a GitHub client.
-func NewClient() *Client {
- c := req.C().
- // All GitHub API requests need this header.
- SetCommonHeader("Accept", "application/vnd.github.v3+json").
- // All GitHub API requests use the same base URL.
- SetBaseURL("https://api.github.com").
- // Enable dump at the request-level for each request, and only
- // temporarily stores the dump content in memory, so we can call
- // resp.Dump() to get the dump content when needed in response
- // middleware.
- // This is actually a syntax sugar, implemented internally using
- // request middleware
- EnableDumpEachRequest().
- // Unmarshal response body into an APIError struct when status >= 400.
- SetCommonErrorResult(&APIError{}).
- // Handle common exceptions in response middleware.
- OnAfterResponse(func(client *req.Client, resp *req.Response) error {
- if resp.Err != nil { // There is an underlying error, e.g. network error or unmarshal error (SetSuccessResult or SetErrorResult was invoked before).
- if dump := resp.Dump(); dump != "" { // Append dump content to original underlying error to help troubleshoot.
- resp.Err = fmt.Errorf("error: %s\nraw content:\n%s", resp.Err.Error(), resp.Dump())
- }
- return nil // Skip the following logic if there is an underlying error.
- }
- if err, ok := resp.ErrorResult().(*APIError); ok { // Server returns an error message.
- // Convert it to human-readable go error which implements the error interface.
- resp.Err = err
- return nil
- }
- // Corner case: neither an error response nor a success response, e.g. status code < 200 or
- // code >= 300 && code <= 399, just dump the raw content into error to help troubleshoot.
- if !resp.IsSuccessState() {
- resp.Err = fmt.Errorf("bad response, raw content:\n%s", resp.Dump())
- }
- return nil
- })
-
- return &Client{
- Client: c,
- }
-}
-
-type apiNameType int
-
-const apiNameKey apiNameType = iota
-
-// SetTracer set the tracer of opentelemetry.
-func (c *Client) SetTracer(tracer trace.Tracer) {
- c.WrapRoundTripFunc(func(rt req.RoundTripper) req.RoundTripFunc {
- return func(req *req.Request) (resp *req.Response, err error) {
- ctx := req.Context()
- apiName, ok := ctx.Value(apiNameKey).(string)
- if !ok {
- apiName = req.URL.Path
- }
- _, span := tracer.Start(req.Context(), apiName)
- defer span.End()
- span.SetAttributes(
- attribute.String("http.url", req.URL.String()),
- attribute.String("http.method", req.Method),
- attribute.String("http.req.header", req.HeaderToString()),
- )
- if len(req.Body) > 0 {
- span.SetAttributes(
- attribute.String("http.req.body", string(req.Body)),
- )
- }
- resp, err = rt.RoundTrip(req)
- if err != nil {
- span.RecordError(err)
- span.SetStatus(codes.Error, err.Error())
- }
- if resp.Response != nil {
- span.SetAttributes(
- attribute.Int("http.status_code", resp.StatusCode),
- attribute.String("http.resp.header", resp.HeaderToString()),
- attribute.String("http.resp.body", resp.String()),
- )
- }
- return
- }
- })
-}
-
-func withAPIName(ctx context.Context, name string) context.Context {
- if ctx == nil {
- ctx = context.Background()
- }
- return context.WithValue(ctx, apiNameKey, name)
-}
-
-type UserProfile struct {
- Name string `json:"name"`
- Blog string `json:"blog"`
-}
-
-// GetUserProfile returns the user profile for the specified user.
-// Github API doc: https://docs.github.com/en/rest/users/users#get-a-user
-func (c *Client) GetUserProfile(ctx context.Context, username string) (user *UserProfile, err error) {
- err = c.Get("/users/{username}").
- SetPathParam("username", username).
- SetSuccessResult(&user).
- Do(withAPIName(ctx, "GetUserProfile")).Err
- return
-}
-
-type Repo struct {
- Name string `json:"name"`
- Star int `json:"stargazers_count"`
-}
-
-// ListUserRepo returns a list of public repositories for the specified user
-// Github API doc: https://docs.github.com/en/rest/repos/repos#list-repositories-for-a-user
-func (c *Client) ListUserRepo(ctx context.Context, username string, page int) (repos []*Repo, err error) {
- err = c.Get("/users/{username}/repos").
- SetPathParam("username", username).
- SetQueryParamsAnyType(map[string]any{
- "type": "owner",
- "page": strconv.Itoa(page),
- "per_page": "100",
- "sort": "updated",
- "direction": "desc",
- }).
- Do(withAPIName(ctx, "ListUserRepo")).
- Into(&repos)
- return
-}
-
-// LoginWithToken login with GitHub personal access token.
-// GitHub API doc: https://docs.github.com/en/rest/overview/other-authentication-methods#authenticating-for-saml-sso
-func (c *Client) LoginWithToken(token string) *Client {
- c.SetCommonHeader("Authorization", "token "+token)
- return c
-}
-
-// SetDebug enable debug if set to true, disable debug if set to false.
-func (c *Client) SetDebug(enable bool) *Client {
- if enable {
- c.EnableDebugLog()
- c.EnableDumpAll()
- } else {
- c.DisableDebugLog()
- c.DisableDumpAll()
- }
- return c
-}
diff --git a/examples/opentelemetry-jaeger-tracing/go.mod b/examples/opentelemetry-jaeger-tracing/go.mod
deleted file mode 100644
index 5e7a958b..00000000
--- a/examples/opentelemetry-jaeger-tracing/go.mod
+++ /dev/null
@@ -1,35 +0,0 @@
-module opentelemetry-jaeger-tracing
-
-go 1.24
-
-toolchain go1.24.4
-
-replace github.com/ennismore/req/v3 => ../../
-
-require (
- github.com/ennismore/req/v3 v3.0.0
- go.opentelemetry.io/otel v1.9.0
- go.opentelemetry.io/otel/exporters/jaeger v1.9.0
- go.opentelemetry.io/otel/sdk v1.9.0
- go.opentelemetry.io/otel/trace v1.9.0
-)
-
-require (
- github.com/andybalholm/brotli v1.2.0 // indirect
- github.com/cloudflare/circl v1.6.1 // indirect
- github.com/go-logr/logr v1.2.3 // indirect
- github.com/go-logr/stdr v1.2.2 // indirect
- github.com/icholy/digest v1.1.0 // indirect
- github.com/klauspost/compress v1.18.0 // indirect
- github.com/quic-go/qpack v0.5.1 // indirect
- github.com/quic-go/quic-go v0.53.0 // indirect
- github.com/refraction-networking/utls v1.7.3 // indirect
- go.uber.org/mock v0.5.2 // indirect
- golang.org/x/crypto v0.39.0 // indirect
- golang.org/x/mod v0.25.0 // indirect
- golang.org/x/net v0.41.0 // indirect
- golang.org/x/sync v0.15.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- golang.org/x/tools v0.34.0 // indirect
-)
diff --git a/examples/opentelemetry-jaeger-tracing/go.sum b/examples/opentelemetry-jaeger-tracing/go.sum
deleted file mode 100644
index c6b15d9e..00000000
--- a/examples/opentelemetry-jaeger-tracing/go.sum
+++ /dev/null
@@ -1,59 +0,0 @@
-github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
-github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
-github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
-github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
-github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
-github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
-github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
-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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
-github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI=
-github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
-github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
-github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-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/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
-github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
-go.opentelemetry.io/otel v1.9.0 h1:8WZNQFIB2a71LnANS9JeyidJKKGOOremcUtb/OtHISw=
-go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo=
-go.opentelemetry.io/otel/exporters/jaeger v1.9.0 h1:gAEgEVGDWwFjcis9jJTOJqZNxDzoZfR12WNIxr7g9Ww=
-go.opentelemetry.io/otel/exporters/jaeger v1.9.0/go.mod h1:hquezOLVAybNW6vanIxkdLXTXvzlj2Vn3wevSP15RYs=
-go.opentelemetry.io/otel/sdk v1.9.0 h1:LNXp1vrr83fNXTHgU8eO89mhzxb/bbWAsHG6fNf3qWo=
-go.opentelemetry.io/otel/sdk v1.9.0/go.mod h1:AEZc8nt5bd2F7BC24J5R0mrjYnpEgYHyTcM/vrSple4=
-go.opentelemetry.io/otel/trace v1.9.0 h1:oZaCNJUjWcg60VXWee8lJKlqhPbXAPB51URuR47pQYc=
-go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo=
-go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
-go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
-golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
-golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
-golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
-golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
-gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
diff --git a/examples/opentelemetry-jaeger-tracing/main.go b/examples/opentelemetry-jaeger-tracing/main.go
deleted file mode 100644
index c4620b57..00000000
--- a/examples/opentelemetry-jaeger-tracing/main.go
+++ /dev/null
@@ -1,162 +0,0 @@
-package main
-
-import (
- "context"
- "fmt"
- "go.opentelemetry.io/otel"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/codes"
- "go.opentelemetry.io/otel/exporters/jaeger"
- "go.opentelemetry.io/otel/sdk/resource"
- "go.opentelemetry.io/otel/sdk/trace"
- semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
- "log"
- "opentelemetry-jaeger-tracing/github"
- "os"
- "os/signal"
- "syscall"
-)
-
-const serviceName = "github-query"
-
-var githubClient *github.Client
-
-func traceProvider() (*trace.TracerProvider, error) {
- // Create the Jaeger exporter
- ep := os.Getenv("JAEGER_ENDPOINT")
- if ep == "" {
- ep = "http://localhost:14268/api/traces"
- }
- exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(ep)))
- if err != nil {
- return nil, err
- }
-
- // Record information about this application in a Resource.
- res, _ := resource.Merge(
- resource.Default(),
- resource.NewWithAttributes(
- semconv.SchemaURL,
- semconv.ServiceNameKey.String(serviceName),
- semconv.ServiceVersionKey.String("v0.1.0"),
- attribute.String("environment", "test"),
- ),
- )
-
- // Create the TraceProvider.
- tp := trace.NewTracerProvider(
- // Always be sure to batch in production.
- trace.WithBatcher(exp),
- // Record information about this application in a Resource.
- trace.WithResource(res),
- trace.WithSampler(trace.AlwaysSample()),
- )
- return tp, nil
-}
-
-// QueryUser queries information for specified GitHub user, and display a
-// brief introduction which includes name, blog, and the most popular repo.
-func QueryUser(username string) error {
- ctx, span := otel.Tracer("query").Start(context.Background(), "QueryUser")
- defer span.End()
-
- span.SetAttributes(
- attribute.String("query.username", username),
- )
- profile, err := githubClient.GetUserProfile(ctx, username)
- if err != nil {
- span.RecordError(err)
- span.SetStatus(codes.Error, err.Error())
- return err
- }
- span.SetAttributes(
- attribute.String("query.name", profile.Name),
- attribute.String("result.blog", profile.Blog),
- )
- repo, err := findMostPopularRepo(ctx, username)
- if err != nil {
- span.RecordError(err)
- span.SetStatus(codes.Error, err.Error())
- return err
- }
- span.SetAttributes(
- attribute.String("popular.repo.name", repo.Name),
- attribute.Int("popular.repo.star", repo.Star),
- )
- fmt.Printf("The most popular repo of %s (%s) is %s, with %d stars\n", profile.Name, profile.Blog, repo.Name, repo.Star)
- return nil
-}
-
-func findMostPopularRepo(ctx context.Context, username string) (repo *github.Repo, err error) {
- ctx, span := otel.Tracer("query").Start(ctx, "findMostPopularRepo")
- defer span.End()
-
- for page := 1; ; page++ {
- var repos []*github.Repo
- repos, err = githubClient.ListUserRepo(ctx, username, page)
- if err != nil {
- return
- }
- if len(repos) == 0 {
- break
- }
- if repo == nil {
- repo = repos[0]
- }
- for _, rp := range repos[1:] {
- if rp.Star >= repo.Star {
- repo = rp
- }
- }
- if len(repos) == 100 {
- continue
- }
- break
- }
-
- if repo == nil {
- err = fmt.Errorf("no repo found for %s", username)
- }
- return
-}
-
-func main() {
- tp, err := traceProvider()
- if err != nil {
- panic(err)
- }
- otel.SetTracerProvider(tp)
-
- githubClient = github.NewClient()
- if os.Getenv("DEBUG") == "on" {
- githubClient.SetDebug(true)
- }
- if token := os.Getenv("GITHUB_TOKEN"); token != "" {
- githubClient.LoginWithToken(token)
- }
- githubClient.SetTracer(otel.Tracer("github"))
-
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT)
- go func() {
- sig := <-sigs
- fmt.Printf("Caught %s, shutting down\n", sig)
- if err := tp.Shutdown(context.Background()); err != nil {
- log.Fatal(err)
- }
- os.Exit(0)
- }()
-
- for {
- var name string
- fmt.Printf("Please give a github username: ")
- _, err := fmt.Fscanf(os.Stdin, "%s\n", &name)
- if err != nil {
- panic(err)
- }
- err = QueryUser(name)
- if err != nil {
- fmt.Println(err.Error())
- }
- }
-}
diff --git a/examples/upload/README.md b/examples/upload/README.md
deleted file mode 100644
index a498b711..00000000
--- a/examples/upload/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# upload
-
-This is a upload example for `req`
-
-## How to Run
-
-Run `uploadserver`:
-
-```go
-cd uploadserver
-go run .
-```
-
-Run `uploadclient`:
-
-```go
-cd uploadclient
-go run .
-```
\ No newline at end of file
diff --git a/examples/upload/uploadclient/go.mod b/examples/upload/uploadclient/go.mod
deleted file mode 100644
index a4ee9c5a..00000000
--- a/examples/upload/uploadclient/go.mod
+++ /dev/null
@@ -1,27 +0,0 @@
-module uploadclient
-
-go 1.24
-
-toolchain go1.24.4
-
-replace github.com/ennismore/req/v3 => ../../../
-
-require github.com/ennismore/req/v3 v3.0.0
-
-require (
- github.com/andybalholm/brotli v1.2.0 // indirect
- github.com/cloudflare/circl v1.6.1 // indirect
- github.com/icholy/digest v1.1.0 // indirect
- github.com/klauspost/compress v1.18.0 // indirect
- github.com/quic-go/qpack v0.5.1 // indirect
- github.com/quic-go/quic-go v0.53.0 // indirect
- github.com/refraction-networking/utls v1.7.3 // indirect
- go.uber.org/mock v0.5.2 // indirect
- golang.org/x/crypto v0.39.0 // indirect
- golang.org/x/mod v0.25.0 // indirect
- golang.org/x/net v0.41.0 // indirect
- golang.org/x/sync v0.15.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- golang.org/x/tools v0.34.0 // indirect
-)
diff --git a/examples/upload/uploadclient/go.sum b/examples/upload/uploadclient/go.sum
deleted file mode 100644
index b67b187c..00000000
--- a/examples/upload/uploadclient/go.sum
+++ /dev/null
@@ -1,44 +0,0 @@
-github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
-github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
-github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
-github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
-github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
-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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
-github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI=
-github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
-github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
-github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
-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/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
-github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
-go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
-go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
-golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
-golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
-golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
-golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
-gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
diff --git a/examples/upload/uploadclient/main.go b/examples/upload/uploadclient/main.go
deleted file mode 100644
index e76e0725..00000000
--- a/examples/upload/uploadclient/main.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package main
-
-import (
- "github.com/ennismore/req/v3"
-)
-
-func main() {
- req.EnableDumpAllWithoutRequestBody()
- req.SetFile("files", "../../../README.md").
- SetFile("files", "../../../LICENSE").
- SetFormData(map[string]string{
- "name": "imroc",
- "email": "roc@imroc.cc",
- }).
- Post("http://127.0.0.1:8888/upload")
- /* Output
- POST /upload HTTP/1.1
- Host: 127.0.0.1:8888
- User-Agent: req/v2 (https://github.com/ennismore/req)
- Transfer-Encoding: chunked
- Content-Type: multipart/form-data; boundary=6af1b071a682709355cf5fb15b9cf9e793df7a45e5cd1eb7c413f2e72bf6
- Accept-Encoding: gzip
-
- HTTP/1.1 200 OK
- Content-Type: text/plain; charset=utf-8
- Date: Tue, 25 Jan 2022 09:40:36 GMT
- Content-Length: 76
-
- Uploaded successfully 2 files with fields name=imroc and email=roc@imroc.cc.
- */
-}
diff --git a/examples/upload/uploadserver/go.mod b/examples/upload/uploadserver/go.mod
deleted file mode 100644
index 37279e61..00000000
--- a/examples/upload/uploadserver/go.mod
+++ /dev/null
@@ -1,26 +0,0 @@
-module uploadserver
-
-go 1.18
-
-require github.com/gin-gonic/gin v1.8.1
-
-require (
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/go-playground/locales v0.14.0 // indirect
- github.com/go-playground/universal-translator v0.18.0 // indirect
- github.com/go-playground/validator/v10 v10.11.0 // indirect
- github.com/goccy/go-json v0.9.10 // indirect
- github.com/json-iterator/go v1.1.12 // indirect
- github.com/leodido/go-urn v1.2.1 // indirect
- github.com/mattn/go-isatty v0.0.14 // indirect
- github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/pelletier/go-toml/v2 v2.0.2 // indirect
- github.com/ugorji/go/codec v1.2.7 // indirect
- golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
- golang.org/x/net v0.0.0-20220809012201-f428fae20770 // indirect
- golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect
- golang.org/x/text v0.3.7 // indirect
- google.golang.org/protobuf v1.28.1 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
-)
diff --git a/examples/upload/uploadserver/go.sum b/examples/upload/uploadserver/go.sum
deleted file mode 100644
index eb352356..00000000
--- a/examples/upload/uploadserver/go.sum
+++ /dev/null
@@ -1,92 +0,0 @@
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
-github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
-github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
-github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
-github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
-github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
-github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
-github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
-github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
-github.com/goccy/go-json v0.9.10 h1:hCeNmprSNLB8B8vQKWl6DpuH0t60oEs+TAk9a7CScKc=
-github.com/goccy/go-json v0.9.10/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
-github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
-github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
-github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
-github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
-github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
-github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
-github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
-golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220809012201-f428fae20770 h1:dIi4qVdvjZEjiMDv7vhokAZNGnz3kepwuXqFKYDdDMs=
-golang.org/x/net v0.0.0-20220809012201-f428fae20770/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
-golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-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/examples/upload/uploadserver/main.go b/examples/upload/uploadserver/main.go
deleted file mode 100644
index d9c2c78a..00000000
--- a/examples/upload/uploadserver/main.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package main
-
-import (
- "net/http"
- "path/filepath"
-
- "github.com/gin-gonic/gin"
-)
-
-func main() {
- router := gin.Default()
- router.POST("/upload", func(c *gin.Context) {
- name := c.PostForm("name")
- email := c.PostForm("email")
-
- // Multipart form
- form, err := c.MultipartForm()
- if err != nil {
- c.String(http.StatusBadRequest, "get form err: %s", err.Error())
- return
- }
- files := form.File["files"]
-
- for _, file := range files {
- filename := filepath.Base(file.Filename)
- if err := c.SaveUploadedFile(file, filename); err != nil {
- c.String(http.StatusBadRequest, "upload file err: %s", err.Error())
- return
- }
- }
-
- c.String(http.StatusOK, "Uploaded successfully %d files with fields name=%s and email=%s.", len(files), name, email)
- })
- router.Run(":8888")
-}
diff --git a/examples/uploadcallback/README.md b/examples/uploadcallback/README.md
deleted file mode 100644
index 3c7e97f7..00000000
--- a/examples/uploadcallback/README.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# uploadcallback
-
-This is a upload callback example for `req`
-
-## How to Run
-
-Run `uploadserver`:
-
-```go
-cd uploadserver
-go run .
-```
-
-Run `uploadclient`:
-
-```go
-cd uploadclient
-go run .
-```
\ No newline at end of file
diff --git a/examples/uploadcallback/uploadclient/go.mod b/examples/uploadcallback/uploadclient/go.mod
deleted file mode 100644
index a4ee9c5a..00000000
--- a/examples/uploadcallback/uploadclient/go.mod
+++ /dev/null
@@ -1,27 +0,0 @@
-module uploadclient
-
-go 1.24
-
-toolchain go1.24.4
-
-replace github.com/ennismore/req/v3 => ../../../
-
-require github.com/ennismore/req/v3 v3.0.0
-
-require (
- github.com/andybalholm/brotli v1.2.0 // indirect
- github.com/cloudflare/circl v1.6.1 // indirect
- github.com/icholy/digest v1.1.0 // indirect
- github.com/klauspost/compress v1.18.0 // indirect
- github.com/quic-go/qpack v0.5.1 // indirect
- github.com/quic-go/quic-go v0.53.0 // indirect
- github.com/refraction-networking/utls v1.7.3 // indirect
- go.uber.org/mock v0.5.2 // indirect
- golang.org/x/crypto v0.39.0 // indirect
- golang.org/x/mod v0.25.0 // indirect
- golang.org/x/net v0.41.0 // indirect
- golang.org/x/sync v0.15.0 // indirect
- golang.org/x/sys v0.33.0 // indirect
- golang.org/x/text v0.26.0 // indirect
- golang.org/x/tools v0.34.0 // indirect
-)
diff --git a/examples/uploadcallback/uploadclient/go.sum b/examples/uploadcallback/uploadclient/go.sum
deleted file mode 100644
index b67b187c..00000000
--- a/examples/uploadcallback/uploadclient/go.sum
+++ /dev/null
@@ -1,44 +0,0 @@
-github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
-github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
-github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
-github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
-github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
-github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
-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/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
-github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
-github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI=
-github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
-github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
-github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
-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/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
-github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
-go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
-go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
-golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
-golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
-golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
-golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
-golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
-golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
-golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
-golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
-golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
-golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
-golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
-golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
-golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
-gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
diff --git a/examples/uploadcallback/uploadclient/main.go b/examples/uploadcallback/uploadclient/main.go
deleted file mode 100644
index 9cb48cd8..00000000
--- a/examples/uploadcallback/uploadclient/main.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "time"
-
- "github.com/ennismore/req/v3"
-)
-
-type SlowReader struct {
- Size int
- n int
-}
-
-func (r *SlowReader) Close() error {
- return nil
-}
-
-func (r *SlowReader) Read(p []byte) (int, error) {
- if r.n >= r.Size {
- return 0, io.EOF
- }
- time.Sleep(1 * time.Millisecond)
- n := len(p)
- if r.n+n >= r.Size {
- n = r.Size - r.n
- }
- for i := 0; i < n; i++ {
- p[i] = 'h'
- }
- r.n += n
- return n, nil
-}
-
-func main() {
- size := 10 * 1024 * 1024
- req.SetFileUpload(req.FileUpload{
- ParamName: "file",
- FileName: "test.txt",
- GetFileContent: func() (io.ReadCloser, error) {
- return &SlowReader{Size: size}, nil
- },
- FileSize: int64(size),
- }).SetUploadCallbackWithInterval(func(info req.UploadInfo) {
- fmt.Printf("%s: %.2f%%\n", info.FileName, float64(info.UploadedSize)/float64(info.FileSize)*100.0)
- }, 30*time.Millisecond).Post("http://127.0.0.1:8888/upload")
-}
diff --git a/examples/uploadcallback/uploadserver/go.mod b/examples/uploadcallback/uploadserver/go.mod
deleted file mode 100644
index 37279e61..00000000
--- a/examples/uploadcallback/uploadserver/go.mod
+++ /dev/null
@@ -1,26 +0,0 @@
-module uploadserver
-
-go 1.18
-
-require github.com/gin-gonic/gin v1.8.1
-
-require (
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/go-playground/locales v0.14.0 // indirect
- github.com/go-playground/universal-translator v0.18.0 // indirect
- github.com/go-playground/validator/v10 v10.11.0 // indirect
- github.com/goccy/go-json v0.9.10 // indirect
- github.com/json-iterator/go v1.1.12 // indirect
- github.com/leodido/go-urn v1.2.1 // indirect
- github.com/mattn/go-isatty v0.0.14 // indirect
- github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/pelletier/go-toml/v2 v2.0.2 // indirect
- github.com/ugorji/go/codec v1.2.7 // indirect
- golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
- golang.org/x/net v0.0.0-20220809012201-f428fae20770 // indirect
- golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect
- golang.org/x/text v0.3.7 // indirect
- google.golang.org/protobuf v1.28.1 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
-)
diff --git a/examples/uploadcallback/uploadserver/go.sum b/examples/uploadcallback/uploadserver/go.sum
deleted file mode 100644
index eb352356..00000000
--- a/examples/uploadcallback/uploadserver/go.sum
+++ /dev/null
@@ -1,92 +0,0 @@
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
-github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
-github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
-github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
-github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
-github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
-github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
-github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2BOGlCyvTqsp/xIw=
-github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
-github.com/goccy/go-json v0.9.10 h1:hCeNmprSNLB8B8vQKWl6DpuH0t60oEs+TAk9a7CScKc=
-github.com/goccy/go-json v0.9.10/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
-github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
-github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
-github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
-github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
-github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
-github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
-github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
-github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
-golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220809012201-f428fae20770 h1:dIi4qVdvjZEjiMDv7vhokAZNGnz3kepwuXqFKYDdDMs=
-golang.org/x/net v0.0.0-20220809012201-f428fae20770/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 h1:v1W7bwXHsnLLloWYTVEdvGvA7BHMeBYsPcF0GLDxIRs=
-golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-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/examples/uploadcallback/uploadserver/main.go b/examples/uploadcallback/uploadserver/main.go
deleted file mode 100644
index 62def71d..00000000
--- a/examples/uploadcallback/uploadserver/main.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package main
-
-import (
- "github.com/gin-gonic/gin"
- "io"
- "net/http"
-)
-
-func main() {
- router := gin.Default()
- router.POST("/upload", func(c *gin.Context) {
- body := c.Request.Body
- io.Copy(io.Discard, body)
- c.String(http.StatusOK, "ok")
- })
- router.Run(":8888")
-}
From cb3c244193ae8b698083042b5a41668e88f18531 Mon Sep 17 00:00:00 2001
From: Gary Willoughby
Date: Wed, 18 Mar 2026 12:27:45 +0000
Subject: [PATCH 4/6] Updated dependencies.
---
.github/workflows/ci.yml | 2 +-
go.mod | 16 ++++++++--------
go.sum | 15 +++++++++++++++
3 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2f909beb..eb9ef1cb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,7 +19,7 @@ jobs:
test:
strategy:
matrix:
- go: ['1.24.x', '1.25.x']
+ go: ['1.26.x']
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
diff --git a/go.mod b/go.mod
index cf8e73f8..8b77be6f 100644
--- a/go.mod
+++ b/go.mod
@@ -1,22 +1,22 @@
module github.com/ennismore/req/v3
-go 1.24.0
+go 1.26.0
require (
github.com/andybalholm/brotli v1.2.0
- github.com/google/go-querystring v1.1.0
+ github.com/google/go-querystring v1.2.0
github.com/icholy/digest v1.1.0
- github.com/klauspost/compress v1.18.2
+ github.com/klauspost/compress v1.18.4
github.com/quic-go/qpack v0.6.0
github.com/quic-go/quic-go v0.59.0
- github.com/refraction-networking/utls v1.8.1
- golang.org/x/net v0.48.0
- golang.org/x/text v0.32.0
+ github.com/refraction-networking/utls v1.8.2
+ golang.org/x/net v0.52.0
+ golang.org/x/text v0.35.0
)
require (
github.com/google/go-cmp v0.7.0 // indirect
go.uber.org/mock v0.6.0 // indirect
- golang.org/x/crypto v0.46.0 // indirect
- golang.org/x/sys v0.39.0 // indirect
+ golang.org/x/crypto v0.49.0 // indirect
+ golang.org/x/sys v0.42.0 // indirect
)
diff --git a/go.sum b/go.sum
index ed6aa9ec..5b116efb 100644
--- a/go.sum
+++ b/go.sum
@@ -3,14 +3,19 @@ github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUS
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/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0=
+github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU=
github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
+github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
+github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
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/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
@@ -19,6 +24,8 @@ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SA
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/refraction-networking/utls v1.8.1 h1:yNY1kapmQU8JeM1sSw2H2asfTIwWxIkrMJI0pRUOCAo=
github.com/refraction-networking/utls v1.8.1/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
+github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo=
+github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
@@ -27,12 +34,20 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
+golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
+golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
+golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
+golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
+golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
+golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
+golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
From 1b5f72000d0621c340bbee859ff8941f62801770 Mon Sep 17 00:00:00 2001
From: wkrige
Date: Mon, 8 Jun 2026 16:56:59 +0100
Subject: [PATCH 5/6] Vendor commit
---
.../github.com/andybalholm/brotli/.gitignore | 2 +
vendor/github.com/andybalholm/brotli/LICENSE | 19 +
.../github.com/andybalholm/brotli/README.md | 19 +
.../andybalholm/brotli/backward_references.go | 185 +
.../brotli/backward_references_hq.go | 796 +
.../github.com/andybalholm/brotli/bit_cost.go | 436 +
.../andybalholm/brotli/bit_reader.go | 266 +
.../andybalholm/brotli/bitwriter.go | 56 +
.../andybalholm/brotli/block_splitter.go | 144 +
.../brotli/block_splitter_command.go | 434 +
.../brotli/block_splitter_distance.go | 433 +
.../brotli/block_splitter_literal.go | 433 +
.../andybalholm/brotli/brotli_bit_stream.go | 1435 +
.../github.com/andybalholm/brotli/cluster.go | 30 +
.../andybalholm/brotli/cluster_command.go | 164 +
.../andybalholm/brotli/cluster_distance.go | 326 +
.../andybalholm/brotli/cluster_literal.go | 326 +
.../github.com/andybalholm/brotli/command.go | 254 +
.../andybalholm/brotli/compress_fragment.go | 834 +
.../brotli/compress_fragment_two_pass.go | 775 +
.../andybalholm/brotli/constants.go | 77 +
.../github.com/andybalholm/brotli/context.go | 2176 +
.../github.com/andybalholm/brotli/decode.go | 2581 +
.../andybalholm/brotli/dictionary.go | 122890 +++++++++++++++
.../andybalholm/brotli/dictionary_hash.go | 32779 ++++
.../github.com/andybalholm/brotli/encode.go | 1220 +
.../github.com/andybalholm/brotli/encoder.go | 177 +
.../andybalholm/brotli/encoder_dict.go | 22 +
.../andybalholm/brotli/encoder_fast.go | 197 +
.../andybalholm/brotli/entropy_encode.go | 592 +
.../brotli/entropy_encode_static.go | 4399 +
.../github.com/andybalholm/brotli/fast_log.go | 290 +
.../andybalholm/brotli/find_match_length.go | 45 +
.../andybalholm/brotli/flate/LICENSE | 27 +
.../andybalholm/brotli/flate/README.md | 2 +
.../andybalholm/brotli/flate/gzip.go | 65 +
.../brotli/flate/huffman_bit_writer.go | 517 +
.../andybalholm/brotli/flate/huffman_code.go | 346 +
.../andybalholm/brotli/flate/token.go | 80 +
.../andybalholm/brotli/flate/writer.go | 66 +
vendor/github.com/andybalholm/brotli/h10.go | 287 +
vendor/github.com/andybalholm/brotli/h5.go | 214 +
vendor/github.com/andybalholm/brotli/h6.go | 216 +
vendor/github.com/andybalholm/brotli/hash.go | 342 +
.../andybalholm/brotli/hash_composite.go | 93 +
.../brotli/hash_forgetful_chain.go | 252 +
.../brotli/hash_longest_match_quickly.go | 214 +
.../andybalholm/brotli/hash_rolling.go | 168 +
.../andybalholm/brotli/histogram.go | 226 +
vendor/github.com/andybalholm/brotli/http.go | 189 +
.../github.com/andybalholm/brotli/huffman.go | 653 +
.../andybalholm/brotli/literal_cost.go | 182 +
.../brotli/matchfinder/bargain1.go | 212 +
.../brotli/matchfinder/bargain2.go | 248 +
.../brotli/matchfinder/bargain3.go | 278 +
.../andybalholm/brotli/matchfinder/emitter.go | 34 +
.../andybalholm/brotli/matchfinder/m0.go | 175 +
.../andybalholm/brotli/matchfinder/m4.go | 339 +
.../brotli/matchfinder/matchfinder.go | 103 +
.../brotli/matchfinder/pathfinder.go | 328 +
.../brotli/matchfinder/textencoder.go | 53 +
.../andybalholm/brotli/matchfinder/trio.go | 326 +
.../andybalholm/brotli/matchfinder/zdfast.go | 258 +
.../andybalholm/brotli/matchfinder/zfast.go | 206 +
.../andybalholm/brotli/matchfinder/zm.go | 301 +
.../github.com/andybalholm/brotli/memory.go | 66 +
.../andybalholm/brotli/metablock.go | 574 +
.../andybalholm/brotli/metablock_command.go | 165 +
.../andybalholm/brotli/metablock_distance.go | 165 +
.../andybalholm/brotli/metablock_literal.go | 165 +
.../github.com/andybalholm/brotli/params.go | 37 +
.../github.com/andybalholm/brotli/platform.go | 103 +
.../github.com/andybalholm/brotli/prefix.go | 30 +
.../andybalholm/brotli/prefix_dec.go | 723 +
.../github.com/andybalholm/brotli/quality.go | 196 +
.../github.com/andybalholm/brotli/reader.go | 111 +
.../andybalholm/brotli/ringbuffer.go | 134 +
vendor/github.com/andybalholm/brotli/state.go | 294 +
.../andybalholm/brotli/static_dict.go | 662 +
.../andybalholm/brotli/static_dict_lut.go | 75094 +++++++++
.../andybalholm/brotli/symbol_list.go | 22 +
.../andybalholm/brotli/transform.go | 641 +
.../andybalholm/brotli/utf8_util.go | 70 +
vendor/github.com/andybalholm/brotli/util.go | 7 +
.../andybalholm/brotli/write_bits.go | 52 +
.../github.com/andybalholm/brotli/writer.go | 162 +
.../github.com/google/go-querystring/LICENSE | 27 +
.../google/go-querystring/query/encode.go | 362 +
vendor/github.com/icholy/digest/.gitignore | 1 +
vendor/github.com/icholy/digest/LICENSE | 21 +
vendor/github.com/icholy/digest/README.md | 164 +
vendor/github.com/icholy/digest/challenge.go | 155 +
.../github.com/icholy/digest/credentials.go | 142 +
vendor/github.com/icholy/digest/digest.go | 164 +
.../icholy/digest/internal/param/param.go | 186 +
vendor/github.com/icholy/digest/transport.go | 237 +
.../klauspost/compress/.gitattributes | 3 +
.../github.com/klauspost/compress/.gitignore | 32 +
.../klauspost/compress/.goreleaser.yml | 132 +
vendor/github.com/klauspost/compress/LICENSE | 304 +
.../github.com/klauspost/compress/README.md | 700 +
.../github.com/klauspost/compress/SECURITY.md | 25 +
.../klauspost/compress/compressible.go | 85 +
.../klauspost/compress/fse/README.md | 79 +
.../klauspost/compress/fse/bitreader.go | 122 +
.../klauspost/compress/fse/bitwriter.go | 167 +
.../klauspost/compress/fse/bytereader.go | 47 +
.../klauspost/compress/fse/compress.go | 683 +
.../klauspost/compress/fse/decompress.go | 376 +
.../github.com/klauspost/compress/fse/fse.go | 144 +
vendor/github.com/klauspost/compress/gen.sh | 4 +
.../klauspost/compress/huff0/.gitignore | 1 +
.../klauspost/compress/huff0/README.md | 89 +
.../klauspost/compress/huff0/bitreader.go | 224 +
.../klauspost/compress/huff0/bitwriter.go | 102 +
.../klauspost/compress/huff0/compress.go | 742 +
.../klauspost/compress/huff0/decompress.go | 1161 +
.../compress/huff0/decompress_amd64.go | 222 +
.../compress/huff0/decompress_amd64.s | 830 +
.../compress/huff0/decompress_generic.go | 298 +
.../klauspost/compress/huff0/huff0.go | 337 +
.../compress/internal/cpuinfo/cpuinfo.go | 34 +
.../internal/cpuinfo/cpuinfo_amd64.go | 10 +
.../compress/internal/cpuinfo/cpuinfo_amd64.s | 36 +
.../klauspost/compress/internal/le/le.go | 5 +
.../compress/internal/le/unsafe_disabled.go | 42 +
.../compress/internal/le/unsafe_enabled.go | 52 +
.../compress/internal/snapref/LICENSE | 27 +
.../compress/internal/snapref/decode.go | 264 +
.../compress/internal/snapref/decode_other.go | 113 +
.../compress/internal/snapref/encode.go | 291 +
.../compress/internal/snapref/encode_other.go | 250 +
.../compress/internal/snapref/snappy.go | 98 +
vendor/github.com/klauspost/compress/s2sx.mod | 3 +
vendor/github.com/klauspost/compress/s2sx.sum | 0
.../klauspost/compress/zstd/README.md | 441 +
.../klauspost/compress/zstd/bitreader.go | 135 +
.../klauspost/compress/zstd/bitwriter.go | 112 +
.../klauspost/compress/zstd/blockdec.go | 712 +
.../klauspost/compress/zstd/blockenc.go | 893 +
.../compress/zstd/blocktype_string.go | 85 +
.../klauspost/compress/zstd/bytebuf.go | 131 +
.../klauspost/compress/zstd/bytereader.go | 82 +
.../klauspost/compress/zstd/decodeheader.go | 261 +
.../klauspost/compress/zstd/decoder.go | 957 +
.../compress/zstd/decoder_options.go | 213 +
.../klauspost/compress/zstd/dict.go | 559 +
.../klauspost/compress/zstd/enc_base.go | 171 +
.../klauspost/compress/zstd/enc_best.go | 553 +
.../klauspost/compress/zstd/enc_better.go | 1238 +
.../klauspost/compress/zstd/enc_dfast.go | 1107 +
.../klauspost/compress/zstd/enc_fast.go | 875 +
.../klauspost/compress/zstd/encoder.go | 671 +
.../compress/zstd/encoder_options.go | 378 +
.../klauspost/compress/zstd/framedec.go | 412 +
.../klauspost/compress/zstd/frameenc.go | 137 +
.../klauspost/compress/zstd/fse_decoder.go | 307 +
.../compress/zstd/fse_decoder_amd64.go | 64 +
.../compress/zstd/fse_decoder_amd64.s | 126 +
.../compress/zstd/fse_decoder_generic.go | 72 +
.../klauspost/compress/zstd/fse_encoder.go | 701 +
.../klauspost/compress/zstd/fse_predefined.go | 158 +
.../klauspost/compress/zstd/hash.go | 35 +
.../klauspost/compress/zstd/history.go | 116 +
.../compress/zstd/internal/xxhash/LICENSE.txt | 22 +
.../compress/zstd/internal/xxhash/README.md | 71 +
.../compress/zstd/internal/xxhash/xxhash.go | 230 +
.../zstd/internal/xxhash/xxhash_amd64.s | 210 +
.../zstd/internal/xxhash/xxhash_arm64.s | 184 +
.../zstd/internal/xxhash/xxhash_asm.go | 16 +
.../zstd/internal/xxhash/xxhash_other.go | 75 +
.../zstd/internal/xxhash/xxhash_safe.go | 11 +
.../klauspost/compress/zstd/matchlen_amd64.go | 15 +
.../klauspost/compress/zstd/matchlen_amd64.s | 66 +
.../compress/zstd/matchlen_generic.go | 37 +
.../klauspost/compress/zstd/seqdec.go | 500 +
.../klauspost/compress/zstd/seqdec_amd64.go | 387 +
.../klauspost/compress/zstd/seqdec_amd64.s | 4151 +
.../klauspost/compress/zstd/seqdec_generic.go | 236 +
.../klauspost/compress/zstd/seqenc.go | 112 +
.../klauspost/compress/zstd/simple_go124.go | 56 +
.../klauspost/compress/zstd/snappy.go | 434 +
.../github.com/klauspost/compress/zstd/zip.go | 141 +
.../klauspost/compress/zstd/zstd.go | 126 +
vendor/github.com/quic-go/qpack/.codecov.yml | 7 +
vendor/github.com/quic-go/qpack/.gitignore | 6 +
vendor/github.com/quic-go/qpack/.gitmodules | 3 +
vendor/github.com/quic-go/qpack/.golangci.yml | 22 +
vendor/github.com/quic-go/qpack/LICENSE.md | 7 +
vendor/github.com/quic-go/qpack/README.md | 21 +
vendor/github.com/quic-go/qpack/decoder.go | 183 +
vendor/github.com/quic-go/qpack/encoder.go | 95 +
.../github.com/quic-go/qpack/header_field.go | 16 +
.../github.com/quic-go/qpack/static_table.go | 255 +
vendor/github.com/quic-go/qpack/varint.go | 69 +
vendor/github.com/quic-go/quic-go/.gitignore | 20 +
.../github.com/quic-go/quic-go/.golangci.yml | 99 +
vendor/github.com/quic-go/quic-go/FIPS140.md | 37 +
vendor/github.com/quic-go/quic-go/FUZZING.md | 59 +
vendor/github.com/quic-go/quic-go/LICENSE | 21 +
vendor/github.com/quic-go/quic-go/README.md | 65 +
vendor/github.com/quic-go/quic-go/SECURITY.md | 14 +
.../github.com/quic-go/quic-go/buffer_pool.go | 92 +
vendor/github.com/quic-go/quic-go/client.go | 109 +
.../github.com/quic-go/quic-go/closed_conn.go | 58 +
vendor/github.com/quic-go/quic-go/codecov.yml | 23 +
vendor/github.com/quic-go/quic-go/config.go | 129 +
.../quic-go/quic-go/conn_id_generator.go | 212 +
.../quic-go/quic-go/conn_id_manager.go | 321 +
.../github.com/quic-go/quic-go/connection.go | 3149 +
.../quic-go/quic-go/connection_logging.go | 315 +
.../quic-go/quic-go/crypto_stream.go | 249 +
.../quic-go/quic-go/crypto_stream_manager.go | 73 +
.../quic-go/quic-go/datagram_queue.go | 137 +
vendor/github.com/quic-go/quic-go/errors.go | 105 +
.../quic-go/quic-go/frame_sorter.go | 274 +
vendor/github.com/quic-go/quic-go/framer.go | 295 +
.../quic-go/quic-go/http3/qlog/event.go | 138 +
.../quic-go/quic-go/http3/qlog/frame.go | 220 +
.../quic-go/quic-go/http3/qlog/qlog_dir.go | 15 +
.../github.com/quic-go/quic-go/interface.go | 215 +
.../internal/ackhandler/ack_eliciting.go | 33 +
.../quic-go/internal/ackhandler/ecn.go | 340 +
.../quic-go/internal/ackhandler/frame.go | 21 +
.../quic-go/internal/ackhandler/interfaces.go | 39 +
.../ackhandler/lost_packet_tracker.go | 73 +
.../quic-go/internal/ackhandler/mockgen.go | 6 +
.../quic-go/internal/ackhandler/packet.go | 60 +
.../ackhandler/packet_number_generator.go | 84 +
.../ackhandler/received_packet_handler.go | 119 +
.../ackhandler/received_packet_history.go | 159 +
.../ackhandler/received_packet_tracker.go | 228 +
.../quic-go/internal/ackhandler/send_mode.go | 46 +
.../ackhandler/sent_packet_handler.go | 1143 +
.../ackhandler/sent_packet_history.go | 274 +
.../quic-go/internal/congestion/bandwidth.go | 22 +
.../quic-go/internal/congestion/clock.go | 20 +
.../quic-go/internal/congestion/cubic.go | 214 +
.../internal/congestion/cubic_sender.go | 330 +
.../internal/congestion/hybrid_slow_start.go | 112 +
.../quic-go/internal/congestion/interface.go | 27 +
.../quic-go/internal/congestion/pacer.go | 110 +
.../flowcontrol/base_flow_controller.go | 122 +
.../flowcontrol/connection_flow_controller.go | 113 +
.../quic-go/internal/flowcontrol/interface.go | 46 +
.../flowcontrol/stream_flow_controller.go | 154 +
.../quic-go/internal/handshake/aead.go | 91 +
.../internal/handshake/cipher_suite.go | 114 +
.../handshake/cipher_suite_fips140.go | 48 +
.../internal/handshake/crypto_setup.go | 722 +
.../quic-go/internal/handshake/fake_conn.go | 21 +
.../internal/handshake/fips140_go126.go | 9 +
.../internal/handshake/fips140_legacy.go | 7 +
.../internal/handshake/header_protector.go | 134 +
.../quic-go/internal/handshake/hkdf.go | 26 +
.../internal/handshake/initial_aead.go | 80 +
.../quic-go/internal/handshake/interface.go | 140 +
.../internal/handshake/quic_event_go125.go | 11 +
.../internal/handshake/quic_event_go126.go | 11 +
.../quic-go/internal/handshake/retry_go125.go | 68 +
.../quic-go/internal/handshake/retry_go126.go | 70 +
.../internal/handshake/session_ticket.go | 56 +
.../quic-go/internal/handshake/tls_config.go | 39 +
.../internal/handshake/token_generator.go | 126 +
.../internal/handshake/token_protector.go | 78 +
.../internal/handshake/updatable_aead.go | 372 +
.../quic-go/quic-go/internal/monotime/time.go | 90 +
.../internal/protocol/connection_id.go | 116 +
.../internal/protocol/encryption_level.go | 65 +
.../quic-go/internal/protocol/key_phase.go | 36 +
.../internal/protocol/packet_number.go | 57 +
.../quic-go/internal/protocol/params.go | 169 +
.../quic-go/internal/protocol/perspective.go | 26 +
.../quic-go/internal/protocol/protocol.go | 159 +
.../quic-go/internal/protocol/stream.go | 102 +
.../quic-go/internal/protocol/version.go | 115 +
.../quic-go/internal/qerr/error_codes.go | 87 +
.../quic-go/quic-go/internal/qerr/errors.go | 134 +
.../internal/utils/buffered_write_closer.go | 26 +
.../quic-go/internal/utils/connstats.go | 14 +
.../internal/utils/linkedlist/README.md | 6 +
.../internal/utils/linkedlist/linkedlist.go | 264 +
.../quic-go/quic-go/internal/utils/log.go | 131 +
.../quic-go/quic-go/internal/utils/rand.go | 29 +
.../internal/utils/ringbuffer/ringbuffer.go | 96 +
.../quic-go/internal/utils/rtt_stats.go | 159 +
.../quic-go/internal/wire/ack_frame.go | 298 +
.../internal/wire/ack_frequency_frame.go | 65 +
.../quic-go/internal/wire/ack_range.go | 14 +
.../internal/wire/connection_close_frame.go | 75 +
.../quic-go/internal/wire/crypto_frame.go | 97 +
.../internal/wire/data_blocked_frame.go | 29 +
.../quic-go/internal/wire/datagram_frame.go | 85 +
.../quic-go/internal/wire/extended_header.go | 164 +
.../quic-go/quic-go/internal/wire/frame.go | 33 +
.../quic-go/internal/wire/frame_parser.go | 192 +
.../quic-go/internal/wire/frame_type.go | 81 +
.../internal/wire/handshake_done_frame.go | 17 +
.../quic-go/quic-go/internal/wire/header.go | 302 +
.../internal/wire/immediate_ack_frame.go | 18 +
.../quic-go/quic-go/internal/wire/log.go | 74 +
.../quic-go/internal/wire/max_data_frame.go | 33 +
.../internal/wire/max_stream_data_frame.go | 43 +
.../internal/wire/max_streams_frame.go | 50 +
.../internal/wire/new_connection_id_frame.go | 80 +
.../quic-go/internal/wire/new_token_frame.go | 43 +
.../internal/wire/path_challenge_frame.go | 32 +
.../internal/wire/path_response_frame.go | 32 +
.../quic-go/internal/wire/ping_frame.go | 17 +
.../quic-go/quic-go/internal/wire/pool.go | 33 +
.../internal/wire/reset_stream_frame.go | 79 +
.../wire/retire_connection_id_frame.go | 30 +
.../quic-go/internal/wire/short_header.go | 62 +
.../internal/wire/stop_sending_frame.go | 45 +
.../wire/stream_data_blocked_frame.go | 42 +
.../quic-go/internal/wire/stream_frame.go | 191 +
.../internal/wire/streams_blocked_frame.go | 50 +
.../internal/wire/transport_parameters.go | 583 +
.../internal/wire/version_negotiation.go | 53 +
vendor/github.com/quic-go/quic-go/mockgen.go | 47 +
.../quic-go/quic-go/mtu_discoverer.go | 253 +
vendor/github.com/quic-go/quic-go/oss-fuzz.sh | 52 +
.../quic-go/quic-go/packet_packer.go | 1009 +
.../quic-go/quic-go/packet_unpacker.go | 222 +
.../quic-go/quic-go/path_manager.go | 206 +
.../quic-go/quic-go/path_manager_outgoing.go | 314 +
.../github.com/quic-go/quic-go/qlog/event.go | 849 +
.../github.com/quic-go/quic-go/qlog/frame.go | 481 +
.../quic-go/quic-go/qlog/packet_header.go | 96 +
.../quic-go/quic-go/qlog/qlog_dir.go | 61 +
.../github.com/quic-go/quic-go/qlog/types.go | 304 +
.../quic-go/qlogwriter/jsontext/encoder.go | 324 +
.../quic-go/quic-go/qlogwriter/trace.go | 124 +
.../quic-go/quic-go/qlogwriter/writer.go | 229 +
.../quic-go/quic-go/quicvarint/io.go | 98 +
.../quic-go/quic-go/quicvarint/varint.go | 180 +
.../quic-go/quic-go/receive_stream.go | 528 +
.../quic-go/quic-go/retransmission_queue.go | 158 +
.../github.com/quic-go/quic-go/send_conn.go | 124 +
.../github.com/quic-go/quic-go/send_queue.go | 112 +
.../github.com/quic-go/quic-go/send_stream.go | 768 +
vendor/github.com/quic-go/quic-go/server.go | 1119 +
vendor/github.com/quic-go/quic-go/sni.go | 136 +
.../quic-go/quic-go/stateless_reset.go | 42 +
vendor/github.com/quic-go/quic-go/stream.go | 234 +
.../github.com/quic-go/quic-go/streams_map.go | 354 +
.../quic-go/quic-go/streams_map_incoming.go | 209 +
.../quic-go/quic-go/streams_map_outgoing.go | 253 +
vendor/github.com/quic-go/quic-go/sys_conn.go | 143 +
.../quic-go/quic-go/sys_conn_buffers.go | 68 +
.../quic-go/quic-go/sys_conn_buffers_write.go | 70 +
.../github.com/quic-go/quic-go/sys_conn_df.go | 22 +
.../quic-go/quic-go/sys_conn_df_darwin.go | 90 +
.../quic-go/quic-go/sys_conn_df_linux.go | 42 +
.../quic-go/quic-go/sys_conn_df_windows.go | 52 +
.../quic-go/quic-go/sys_conn_helper_darwin.go | 38 +
.../quic-go/sys_conn_helper_freebsd.go | 33 +
.../quic-go/quic-go/sys_conn_helper_linux.go | 156 +
.../quic-go/sys_conn_helper_nonlinux.go | 10 +
.../quic-go/quic-go/sys_conn_no_oob.go | 21 +
.../quic-go/quic-go/sys_conn_oob.go | 338 +
.../quic-go/quic-go/sys_conn_windows.go | 42 +
.../github.com/quic-go/quic-go/token_store.go | 116 +
.../github.com/quic-go/quic-go/transport.go | 848 +
.../refraction-networking/utls/.travis.yml | 19 +
.../utls/CONTRIBUTING.md | 23 +
.../utls/CONTRIBUTORS_GUIDE.md | 69 +
.../refraction-networking/utls/LICENSE | 27 +
.../refraction-networking/utls/README.md | 315 +
.../refraction-networking/utls/SECURITY.md | 11 +
.../refraction-networking/utls/alert.go | 111 +
.../refraction-networking/utls/auth.go | 295 +
.../refraction-networking/utls/cache.go | 95 +
.../utls/cipher_suites.go | 725 +
.../refraction-networking/utls/common.go | 1819 +
.../utls/common_string.go | 120 +
.../refraction-networking/utls/conn.go | 1701 +
.../refraction-networking/utls/defaults.go | 140 +
.../utls/dicttls/LICENSE | 28 +
.../utls/dicttls/README.md | 12 +
.../utls/dicttls/alerts.go | 118 +
.../dicttls/authorization_data_formats.go | 35 +
.../dicttls/cachedinformationtype_values.go | 19 +
.../certificate_compression_algorithm_ids.go | 22 +
.../utls/dicttls/certificate_status_types.go | 19 +
.../utls/dicttls/certificte_types.go | 25 +
.../utls/dicttls/cipher_suites.go | 1084 +
.../clientcertificatetype_identifiers.go | 49 +
.../utls/dicttls/comp_meth_ids.go | 22 +
.../utls/dicttls/contenttype.go | 34 +
.../utls/dicttls/ec_curve_types.go | 22 +
.../utls/dicttls/ec_point_formats.go | 22 +
.../utls/dicttls/exttype_values.go | 212 +
.../utls/dicttls/handshaketype.go | 96 +
.../utls/dicttls/hashalgorithm.go | 39 +
.../utls/dicttls/heartbeat_message_types.go | 19 +
.../utls/dicttls/heartbeat_mode.go | 19 +
.../utls/dicttls/hpke_aead_identifiers.go | 19 +
.../utls/dicttls/hpke_kdf_identifiers.go | 24 +
.../utls/dicttls/hpke_kem_identifiers.go | 53 +
.../utls/dicttls/psk_key_exchange_mode.go | 19 +
.../utls/dicttls/quic_frame_types.go | 112 +
.../dicttls/quic_transport_error_codes.go | 70 +
.../utls/dicttls/quic_transport_parameters.go | 91 +
.../utls/dicttls/signaturealgorithm.go | 41 +
.../utls/dicttls/signaturescheme.go | 116 +
.../utls/dicttls/supplemental_data_formats.go | 19 +
.../utls/dicttls/supported_groups.go | 157 +
.../utls/dicttls/usermappingtype_values.go | 16 +
.../refraction-networking/utls/ech.go | 646 +
.../utls/handshake_client.go | 1370 +
.../utls/handshake_client_tls13.go | 1079 +
.../utls/handshake_messages.go | 2004 +
.../utls/handshake_server.go | 1009 +
.../utls/handshake_server_tls13.go | 1148 +
.../utls/internal/boring/notboring.go | 20 +
.../utls/internal/byteorder/byteorder.go | 149 +
.../utls/internal/fips140tls/fipstls.go | 5 +
.../utls/internal/helper/typeconv.go | 23 +
.../utls/internal/hkdf/hkdf.go | 24 +
.../utls/internal/hpke/hpke.go | 333 +
.../internal/quicvarint/protocol/protocol.go | 157 +
.../utls/internal/quicvarint/varint.go | 146 +
.../utls/internal/tls12/tls12.go | 69 +
.../utls/internal/tls13/tls13.go | 179 +
.../utls/internal/tls13/u_tls13.go | 31 +
.../utls/key_agreement.go | 366 +
.../utls/key_schedule.go | 101 +
.../refraction-networking/utls/logo.png | Bin 0 -> 23577 bytes
.../refraction-networking/utls/logo_small.png | Bin 0 -> 2028 bytes
.../refraction-networking/utls/prf.go | 297 +
.../refraction-networking/utls/quic.go | 500 +
.../refraction-networking/utls/ticket.go | 441 +
.../refraction-networking/utls/tls.go | 373 +
.../refraction-networking/utls/u_alias.go | 39 +
.../utls/u_clienthello_json.go | 184 +
.../refraction-networking/utls/u_common.go | 821 +
.../refraction-networking/utls/u_conn.go | 984 +
.../refraction-networking/utls/u_ech.go | 306 +
.../utls/u_fingerprinter.go | 74 +
.../utls/u_handshake_client.go | 595 +
.../utls/u_handshake_messages.go | 138 +
.../refraction-networking/utls/u_hpke.go | 35 +
.../utls/u_key_schedule.go | 30 +
.../refraction-networking/utls/u_parrots.go | 3241 +
.../utls/u_pre_shared_key.go | 486 +
.../refraction-networking/utls/u_prng.go | 188 +
.../refraction-networking/utls/u_public.go | 925 +
.../refraction-networking/utls/u_quic.go | 212 +
.../utls/u_quic_transport_parameters.go | 319 +
.../refraction-networking/utls/u_roller.go | 100 +
.../utls/u_session_controller.go | 361 +
.../utls/u_session_ticket.go | 82 +
.../utls/u_tls_extensions.go | 1946 +
vendor/golang.org/x/crypto/LICENSE | 27 +
vendor/golang.org/x/crypto/PATENTS | 22 +
.../x/crypto/chacha20/chacha_arm64.go | 16 +
.../x/crypto/chacha20/chacha_arm64.s | 307 +
.../x/crypto/chacha20/chacha_generic.go | 398 +
.../x/crypto/chacha20/chacha_noasm.go | 13 +
.../x/crypto/chacha20/chacha_ppc64x.go | 16 +
.../x/crypto/chacha20/chacha_ppc64x.s | 501 +
.../x/crypto/chacha20/chacha_s390x.go | 27 +
.../x/crypto/chacha20/chacha_s390x.s | 224 +
vendor/golang.org/x/crypto/chacha20/xor.go | 42 +
.../chacha20poly1305/chacha20poly1305.go | 101 +
.../chacha20poly1305_amd64.go | 92 +
.../chacha20poly1305/chacha20poly1305_amd64.s | 5230 +
.../chacha20poly1305_generic.go | 87 +
.../chacha20poly1305_noasm.go | 15 +
.../chacha20poly1305/fips140only_compat.go | 9 +
.../chacha20poly1305/fips140only_go1.26.go | 11 +
.../chacha20poly1305/xchacha20poly1305.go | 89 +
vendor/golang.org/x/crypto/cryptobyte/asn1.go | 825 +
.../x/crypto/cryptobyte/asn1/asn1.go | 46 +
.../golang.org/x/crypto/cryptobyte/builder.go | 350 +
.../golang.org/x/crypto/cryptobyte/string.go | 183 +
vendor/golang.org/x/crypto/hkdf/hkdf.go | 100 +
.../x/crypto/internal/alias/alias.go | 31 +
.../x/crypto/internal/alias/alias_purego.go | 34 +
.../x/crypto/internal/poly1305/mac_noasm.go | 9 +
.../x/crypto/internal/poly1305/poly1305.go | 99 +
.../x/crypto/internal/poly1305/sum_amd64.s | 93 +
.../x/crypto/internal/poly1305/sum_asm.go | 47 +
.../x/crypto/internal/poly1305/sum_generic.go | 312 +
.../x/crypto/internal/poly1305/sum_loong64.s | 123 +
.../x/crypto/internal/poly1305/sum_ppc64x.s | 187 +
.../x/crypto/internal/poly1305/sum_s390x.go | 76 +
.../x/crypto/internal/poly1305/sum_s390x.s | 503 +
vendor/golang.org/x/crypto/sha3/hashes.go | 95 +
.../golang.org/x/crypto/sha3/legacy_hash.go | 263 +
.../x/crypto/sha3/legacy_keccakf.go | 416 +
vendor/golang.org/x/crypto/sha3/shake.go | 119 +
vendor/golang.org/x/net/LICENSE | 27 +
vendor/golang.org/x/net/PATENTS | 22 +
vendor/golang.org/x/net/bpf/asm.go | 41 +
vendor/golang.org/x/net/bpf/constants.go | 222 +
vendor/golang.org/x/net/bpf/doc.go | 80 +
vendor/golang.org/x/net/bpf/instructions.go | 726 +
vendor/golang.org/x/net/bpf/setter.go | 10 +
vendor/golang.org/x/net/bpf/vm.go | 150 +
.../golang.org/x/net/bpf/vm_instructions.go | 182 +
vendor/golang.org/x/net/html/atom/atom.go | 78 +
vendor/golang.org/x/net/html/atom/table.go | 785 +
.../golang.org/x/net/html/charset/charset.go | 257 +
vendor/golang.org/x/net/html/const.go | 111 +
vendor/golang.org/x/net/html/doc.go | 122 +
vendor/golang.org/x/net/html/doctype.go | 156 +
vendor/golang.org/x/net/html/entity.go | 2253 +
vendor/golang.org/x/net/html/escape.go | 339 +
vendor/golang.org/x/net/html/foreign.go | 221 +
vendor/golang.org/x/net/html/iter.go | 54 +
vendor/golang.org/x/net/html/node.go | 230 +
.../golang.org/x/net/html/nodetype_string.go | 31 +
vendor/golang.org/x/net/html/parse.go | 2493 +
vendor/golang.org/x/net/html/render.go | 316 +
vendor/golang.org/x/net/html/token.go | 1291 +
vendor/golang.org/x/net/http/httpguts/guts.go | 50 +
.../golang.org/x/net/http/httpguts/httplex.go | 347 +
vendor/golang.org/x/net/http2/hpack/encode.go | 245 +
vendor/golang.org/x/net/http2/hpack/hpack.go | 523 +
.../golang.org/x/net/http2/hpack/huffman.go | 226 +
.../x/net/http2/hpack/static_table.go | 188 +
vendor/golang.org/x/net/http2/hpack/tables.go | 403 +
vendor/golang.org/x/net/idna/idna.go | 880 +
vendor/golang.org/x/net/idna/punycode.go | 220 +
vendor/golang.org/x/net/idna/tables15.0.0.go | 5144 +
vendor/golang.org/x/net/idna/tables17.0.0.go | 5302 +
vendor/golang.org/x/net/idna/trie.go | 51 +
vendor/golang.org/x/net/idna/trieval.go | 119 +
.../golang.org/x/net/internal/iana/const.go | 223 +
.../x/net/internal/socket/cmsghdr.go | 11 +
.../x/net/internal/socket/cmsghdr_bsd.go | 13 +
.../internal/socket/cmsghdr_linux_32bit.go | 13 +
.../internal/socket/cmsghdr_linux_64bit.go | 13 +
.../internal/socket/cmsghdr_solaris_64bit.go | 13 +
.../x/net/internal/socket/cmsghdr_stub.go | 27 +
.../x/net/internal/socket/cmsghdr_unix.go | 21 +
.../net/internal/socket/cmsghdr_zos_s390x.go | 11 +
.../net/internal/socket/complete_dontwait.go | 25 +
.../internal/socket/complete_nodontwait.go | 21 +
.../golang.org/x/net/internal/socket/empty.s | 7 +
.../x/net/internal/socket/error_unix.go | 31 +
.../x/net/internal/socket/error_windows.go | 26 +
.../x/net/internal/socket/iovec_32bit.go | 18 +
.../x/net/internal/socket/iovec_64bit.go | 18 +
.../internal/socket/iovec_solaris_64bit.go | 18 +
.../x/net/internal/socket/iovec_stub.go | 11 +
.../x/net/internal/socket/mmsghdr_stub.go | 21 +
.../x/net/internal/socket/mmsghdr_unix.go | 195 +
.../x/net/internal/socket/msghdr_bsd.go | 39 +
.../x/net/internal/socket/msghdr_bsdvar.go | 16 +
.../x/net/internal/socket/msghdr_linux.go | 36 +
.../net/internal/socket/msghdr_linux_32bit.go | 23 +
.../net/internal/socket/msghdr_linux_64bit.go | 23 +
.../x/net/internal/socket/msghdr_openbsd.go | 14 +
.../internal/socket/msghdr_solaris_64bit.go | 38 +
.../x/net/internal/socket/msghdr_stub.go | 14 +
.../x/net/internal/socket/msghdr_zos_s390x.go | 35 +
.../x/net/internal/socket/norace.go | 12 +
.../golang.org/x/net/internal/socket/race.go | 37 +
.../x/net/internal/socket/rawconn.go | 91 +
.../x/net/internal/socket/rawconn_mmsg.go | 53 +
.../x/net/internal/socket/rawconn_msg.go | 59 +
.../x/net/internal/socket/rawconn_nommsg.go | 15 +
.../x/net/internal/socket/rawconn_nomsg.go | 15 +
.../x/net/internal/socket/socket.go | 281 +
.../x/net/internal/socket/sys_bsd.go | 15 +
.../x/net/internal/socket/sys_const_unix.go | 20 +
.../x/net/internal/socket/sys_linux.go | 22 +
.../x/net/internal/socket/sys_linux_386.go | 28 +
.../x/net/internal/socket/sys_linux_386.s | 11 +
.../x/net/internal/socket/sys_linux_amd64.go | 10 +
.../x/net/internal/socket/sys_linux_arm.go | 10 +
.../x/net/internal/socket/sys_linux_arm64.go | 10 +
.../net/internal/socket/sys_linux_loong64.go | 12 +
.../x/net/internal/socket/sys_linux_mips.go | 10 +
.../x/net/internal/socket/sys_linux_mips64.go | 10 +
.../net/internal/socket/sys_linux_mips64le.go | 10 +
.../x/net/internal/socket/sys_linux_mipsle.go | 10 +
.../x/net/internal/socket/sys_linux_ppc.go | 10 +
.../x/net/internal/socket/sys_linux_ppc64.go | 10 +
.../net/internal/socket/sys_linux_ppc64le.go | 10 +
.../net/internal/socket/sys_linux_riscv64.go | 12 +
.../x/net/internal/socket/sys_linux_s390x.go | 28 +
.../x/net/internal/socket/sys_linux_s390x.s | 11 +
.../x/net/internal/socket/sys_netbsd.go | 25 +
.../x/net/internal/socket/sys_posix.go | 184 +
.../x/net/internal/socket/sys_stub.go | 52 +
.../x/net/internal/socket/sys_unix.go | 121 +
.../x/net/internal/socket/sys_windows.go | 55 +
.../x/net/internal/socket/sys_zos_s390x.go | 66 +
.../x/net/internal/socket/sys_zos_s390x.s | 11 +
.../x/net/internal/socket/zsys_aix_ppc64.go | 39 +
.../net/internal/socket/zsys_darwin_amd64.go | 32 +
.../net/internal/socket/zsys_darwin_arm64.go | 32 +
.../internal/socket/zsys_dragonfly_amd64.go | 32 +
.../x/net/internal/socket/zsys_freebsd_386.go | 30 +
.../net/internal/socket/zsys_freebsd_amd64.go | 32 +
.../x/net/internal/socket/zsys_freebsd_arm.go | 30 +
.../net/internal/socket/zsys_freebsd_arm64.go | 32 +
.../internal/socket/zsys_freebsd_riscv64.go | 30 +
.../x/net/internal/socket/zsys_linux_386.go | 35 +
.../x/net/internal/socket/zsys_linux_amd64.go | 38 +
.../x/net/internal/socket/zsys_linux_arm.go | 35 +
.../x/net/internal/socket/zsys_linux_arm64.go | 38 +
.../net/internal/socket/zsys_linux_loong64.go | 39 +
.../x/net/internal/socket/zsys_linux_mips.go | 35 +
.../net/internal/socket/zsys_linux_mips64.go | 38 +
.../internal/socket/zsys_linux_mips64le.go | 38 +
.../net/internal/socket/zsys_linux_mipsle.go | 35 +
.../x/net/internal/socket/zsys_linux_ppc.go | 35 +
.../x/net/internal/socket/zsys_linux_ppc64.go | 38 +
.../net/internal/socket/zsys_linux_ppc64le.go | 38 +
.../net/internal/socket/zsys_linux_riscv64.go | 39 +
.../x/net/internal/socket/zsys_linux_s390x.go | 38 +
.../x/net/internal/socket/zsys_netbsd_386.go | 35 +
.../net/internal/socket/zsys_netbsd_amd64.go | 38 +
.../x/net/internal/socket/zsys_netbsd_arm.go | 35 +
.../net/internal/socket/zsys_netbsd_arm64.go | 38 +
.../x/net/internal/socket/zsys_openbsd_386.go | 30 +
.../net/internal/socket/zsys_openbsd_amd64.go | 32 +
.../x/net/internal/socket/zsys_openbsd_arm.go | 30 +
.../net/internal/socket/zsys_openbsd_arm64.go | 32 +
.../internal/socket/zsys_openbsd_mips64.go | 30 +
.../net/internal/socket/zsys_openbsd_ppc64.go | 30 +
.../internal/socket/zsys_openbsd_riscv64.go | 30 +
.../net/internal/socket/zsys_solaris_amd64.go | 32 +
.../x/net/internal/socket/zsys_zos_s390x.go | 28 +
vendor/golang.org/x/net/ipv4/batch.go | 194 +
vendor/golang.org/x/net/ipv4/control.go | 144 +
vendor/golang.org/x/net/ipv4/control_bsd.go | 43 +
.../golang.org/x/net/ipv4/control_pktinfo.go | 41 +
vendor/golang.org/x/net/ipv4/control_stub.go | 13 +
vendor/golang.org/x/net/ipv4/control_unix.go | 75 +
.../golang.org/x/net/ipv4/control_windows.go | 12 +
vendor/golang.org/x/net/ipv4/control_zos.go | 88 +
vendor/golang.org/x/net/ipv4/dgramopt.go | 264 +
vendor/golang.org/x/net/ipv4/doc.go | 240 +
vendor/golang.org/x/net/ipv4/endpoint.go | 186 +
vendor/golang.org/x/net/ipv4/genericopt.go | 55 +
vendor/golang.org/x/net/ipv4/header.go | 170 +
vendor/golang.org/x/net/ipv4/helper.go | 77 +
vendor/golang.org/x/net/ipv4/iana.go | 38 +
vendor/golang.org/x/net/ipv4/icmp.go | 57 +
vendor/golang.org/x/net/ipv4/icmp_linux.go | 25 +
vendor/golang.org/x/net/ipv4/icmp_stub.go | 25 +
vendor/golang.org/x/net/ipv4/packet.go | 117 +
vendor/golang.org/x/net/ipv4/payload.go | 23 +
vendor/golang.org/x/net/ipv4/payload_cmsg.go | 84 +
.../golang.org/x/net/ipv4/payload_nocmsg.go | 39 +
vendor/golang.org/x/net/ipv4/sockopt.go | 44 +
vendor/golang.org/x/net/ipv4/sockopt_posix.go | 71 +
vendor/golang.org/x/net/ipv4/sockopt_stub.go | 42 +
vendor/golang.org/x/net/ipv4/sys_aix.go | 43 +
vendor/golang.org/x/net/ipv4/sys_asmreq.go | 122 +
.../golang.org/x/net/ipv4/sys_asmreq_stub.go | 25 +
vendor/golang.org/x/net/ipv4/sys_asmreqn.go | 44 +
.../golang.org/x/net/ipv4/sys_asmreqn_stub.go | 21 +
vendor/golang.org/x/net/ipv4/sys_bpf.go | 24 +
vendor/golang.org/x/net/ipv4/sys_bpf_stub.go | 16 +
vendor/golang.org/x/net/ipv4/sys_bsd.go | 41 +
vendor/golang.org/x/net/ipv4/sys_darwin.go | 69 +
vendor/golang.org/x/net/ipv4/sys_dragonfly.go | 39 +
vendor/golang.org/x/net/ipv4/sys_freebsd.go | 80 +
vendor/golang.org/x/net/ipv4/sys_linux.go | 61 +
vendor/golang.org/x/net/ipv4/sys_solaris.go | 61 +
vendor/golang.org/x/net/ipv4/sys_ssmreq.go | 52 +
.../golang.org/x/net/ipv4/sys_ssmreq_stub.go | 21 +
vendor/golang.org/x/net/ipv4/sys_stub.go | 13 +
vendor/golang.org/x/net/ipv4/sys_windows.go | 44 +
vendor/golang.org/x/net/ipv4/sys_zos.go | 57 +
.../golang.org/x/net/ipv4/zsys_aix_ppc64.go | 16 +
vendor/golang.org/x/net/ipv4/zsys_darwin.go | 59 +
.../golang.org/x/net/ipv4/zsys_dragonfly.go | 13 +
.../golang.org/x/net/ipv4/zsys_freebsd_386.go | 52 +
.../x/net/ipv4/zsys_freebsd_amd64.go | 54 +
.../golang.org/x/net/ipv4/zsys_freebsd_arm.go | 54 +
.../x/net/ipv4/zsys_freebsd_arm64.go | 52 +
.../x/net/ipv4/zsys_freebsd_riscv64.go | 52 +
.../golang.org/x/net/ipv4/zsys_linux_386.go | 72 +
.../golang.org/x/net/ipv4/zsys_linux_amd64.go | 74 +
.../golang.org/x/net/ipv4/zsys_linux_arm.go | 72 +
.../golang.org/x/net/ipv4/zsys_linux_arm64.go | 74 +
.../x/net/ipv4/zsys_linux_loong64.go | 76 +
.../golang.org/x/net/ipv4/zsys_linux_mips.go | 72 +
.../x/net/ipv4/zsys_linux_mips64.go | 74 +
.../x/net/ipv4/zsys_linux_mips64le.go | 74 +
.../x/net/ipv4/zsys_linux_mipsle.go | 72 +
.../golang.org/x/net/ipv4/zsys_linux_ppc.go | 72 +
.../golang.org/x/net/ipv4/zsys_linux_ppc64.go | 74 +
.../x/net/ipv4/zsys_linux_ppc64le.go | 74 +
.../x/net/ipv4/zsys_linux_riscv64.go | 76 +
.../golang.org/x/net/ipv4/zsys_linux_s390x.go | 74 +
vendor/golang.org/x/net/ipv4/zsys_netbsd.go | 13 +
vendor/golang.org/x/net/ipv4/zsys_openbsd.go | 13 +
vendor/golang.org/x/net/ipv4/zsys_solaris.go | 57 +
.../golang.org/x/net/ipv4/zsys_zos_s390x.go | 56 +
vendor/golang.org/x/net/ipv6/batch.go | 116 +
vendor/golang.org/x/net/ipv6/control.go | 187 +
.../x/net/ipv6/control_rfc2292_unix.go | 51 +
.../x/net/ipv6/control_rfc3542_unix.go | 97 +
vendor/golang.org/x/net/ipv6/control_stub.go | 13 +
vendor/golang.org/x/net/ipv6/control_unix.go | 55 +
.../golang.org/x/net/ipv6/control_windows.go | 12 +
vendor/golang.org/x/net/ipv6/dgramopt.go | 301 +
vendor/golang.org/x/net/ipv6/doc.go | 239 +
vendor/golang.org/x/net/ipv6/endpoint.go | 127 +
vendor/golang.org/x/net/ipv6/genericopt.go | 56 +
vendor/golang.org/x/net/ipv6/header.go | 55 +
vendor/golang.org/x/net/ipv6/helper.go | 58 +
vendor/golang.org/x/net/ipv6/iana.go | 86 +
vendor/golang.org/x/net/ipv6/icmp.go | 60 +
vendor/golang.org/x/net/ipv6/icmp_bsd.go | 29 +
vendor/golang.org/x/net/ipv6/icmp_linux.go | 27 +
vendor/golang.org/x/net/ipv6/icmp_solaris.go | 27 +
vendor/golang.org/x/net/ipv6/icmp_stub.go | 23 +
vendor/golang.org/x/net/ipv6/icmp_windows.go | 22 +
vendor/golang.org/x/net/ipv6/icmp_zos.go | 29 +
vendor/golang.org/x/net/ipv6/payload.go | 23 +
vendor/golang.org/x/net/ipv6/payload_cmsg.go | 70 +
.../golang.org/x/net/ipv6/payload_nocmsg.go | 38 +
vendor/golang.org/x/net/ipv6/sockopt.go | 43 +
vendor/golang.org/x/net/ipv6/sockopt_posix.go | 89 +
vendor/golang.org/x/net/ipv6/sockopt_stub.go | 46 +
vendor/golang.org/x/net/ipv6/sys_aix.go | 79 +
vendor/golang.org/x/net/ipv6/sys_asmreq.go | 24 +
.../golang.org/x/net/ipv6/sys_asmreq_stub.go | 17 +
vendor/golang.org/x/net/ipv6/sys_bpf.go | 24 +
vendor/golang.org/x/net/ipv6/sys_bpf_stub.go | 16 +
vendor/golang.org/x/net/ipv6/sys_bsd.go | 59 +
vendor/golang.org/x/net/ipv6/sys_darwin.go | 80 +
vendor/golang.org/x/net/ipv6/sys_freebsd.go | 94 +
vendor/golang.org/x/net/ipv6/sys_linux.go | 76 +
vendor/golang.org/x/net/ipv6/sys_solaris.go | 76 +
vendor/golang.org/x/net/ipv6/sys_ssmreq.go | 54 +
.../golang.org/x/net/ipv6/sys_ssmreq_stub.go | 21 +
vendor/golang.org/x/net/ipv6/sys_stub.go | 13 +
vendor/golang.org/x/net/ipv6/sys_windows.go | 68 +
vendor/golang.org/x/net/ipv6/sys_zos.go | 72 +
.../golang.org/x/net/ipv6/zsys_aix_ppc64.go | 68 +
vendor/golang.org/x/net/ipv6/zsys_darwin.go | 64 +
.../golang.org/x/net/ipv6/zsys_dragonfly.go | 42 +
.../golang.org/x/net/ipv6/zsys_freebsd_386.go | 64 +
.../x/net/ipv6/zsys_freebsd_amd64.go | 66 +
.../golang.org/x/net/ipv6/zsys_freebsd_arm.go | 66 +
.../x/net/ipv6/zsys_freebsd_arm64.go | 64 +
.../x/net/ipv6/zsys_freebsd_riscv64.go | 64 +
.../golang.org/x/net/ipv6/zsys_linux_386.go | 72 +
.../golang.org/x/net/ipv6/zsys_linux_amd64.go | 74 +
.../golang.org/x/net/ipv6/zsys_linux_arm.go | 72 +
.../golang.org/x/net/ipv6/zsys_linux_arm64.go | 74 +
.../x/net/ipv6/zsys_linux_loong64.go | 76 +
.../golang.org/x/net/ipv6/zsys_linux_mips.go | 72 +
.../x/net/ipv6/zsys_linux_mips64.go | 74 +
.../x/net/ipv6/zsys_linux_mips64le.go | 74 +
.../x/net/ipv6/zsys_linux_mipsle.go | 72 +
.../golang.org/x/net/ipv6/zsys_linux_ppc.go | 72 +
.../golang.org/x/net/ipv6/zsys_linux_ppc64.go | 74 +
.../x/net/ipv6/zsys_linux_ppc64le.go | 74 +
.../x/net/ipv6/zsys_linux_riscv64.go | 76 +
.../golang.org/x/net/ipv6/zsys_linux_s390x.go | 74 +
vendor/golang.org/x/net/ipv6/zsys_netbsd.go | 42 +
vendor/golang.org/x/net/ipv6/zsys_openbsd.go | 42 +
vendor/golang.org/x/net/ipv6/zsys_solaris.go | 63 +
.../golang.org/x/net/ipv6/zsys_zos_s390x.go | 62 +
vendor/golang.org/x/net/nettest/conntest.go | 467 +
vendor/golang.org/x/net/nettest/nettest.go | 344 +
.../golang.org/x/net/nettest/nettest_stub.go | 11 +
.../golang.org/x/net/nettest/nettest_unix.go | 21 +
.../x/net/nettest/nettest_windows.go | 26 +
.../x/net/publicsuffix/data/children | Bin 0 -> 3744 bytes
.../golang.org/x/net/publicsuffix/data/nodes | Bin 0 -> 52665 bytes
.../golang.org/x/net/publicsuffix/data/text | 1 +
vendor/golang.org/x/net/publicsuffix/list.go | 210 +
vendor/golang.org/x/net/publicsuffix/table.go | 70 +
vendor/golang.org/x/sys/LICENSE | 27 +
vendor/golang.org/x/sys/PATENTS | 22 +
vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 17 +
.../x/sys/cpu/asm_darwin_arm64_gc.s | 12 +
.../golang.org/x/sys/cpu/asm_darwin_x86_gc.s | 17 +
vendor/golang.org/x/sys/cpu/byteorder.go | 66 +
vendor/golang.org/x/sys/cpu/cpu.go | 343 +
vendor/golang.org/x/sys/cpu/cpu_aix.go | 33 +
vendor/golang.org/x/sys/cpu/cpu_arm.go | 73 +
vendor/golang.org/x/sys/cpu/cpu_arm64.go | 191 +
vendor/golang.org/x/sys/cpu/cpu_arm64.s | 35 +
.../golang.org/x/sys/cpu/cpu_darwin_arm64.go | 67 +
.../x/sys/cpu/cpu_darwin_arm64_other.go | 31 +
vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go | 61 +
vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 12 +
vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 21 +
vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 15 +
vendor/golang.org/x/sys/cpu/cpu_gc_x86.s | 26 +
.../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 12 +
.../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 22 +
vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c | 37 +
vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 25 +
vendor/golang.org/x/sys/cpu/cpu_linux.go | 15 +
vendor/golang.org/x/sys/cpu/cpu_linux_arm.go | 39 +
.../golang.org/x/sys/cpu/cpu_linux_arm64.go | 120 +
.../golang.org/x/sys/cpu/cpu_linux_loong64.go | 22 +
.../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 22 +
.../golang.org/x/sys/cpu/cpu_linux_noinit.go | 9 +
.../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 30 +
.../golang.org/x/sys/cpu/cpu_linux_riscv64.go | 162 +
.../golang.org/x/sys/cpu/cpu_linux_s390x.go | 40 +
vendor/golang.org/x/sys/cpu/cpu_loong64.go | 62 +
vendor/golang.org/x/sys/cpu/cpu_loong64.s | 13 +
vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 15 +
vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 11 +
.../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 173 +
.../golang.org/x/sys/cpu/cpu_openbsd_arm64.go | 65 +
.../golang.org/x/sys/cpu/cpu_openbsd_arm64.s | 11 +
vendor/golang.org/x/sys/cpu/cpu_other_arm.go | 9 +
.../golang.org/x/sys/cpu/cpu_other_arm64.go | 11 +
.../golang.org/x/sys/cpu/cpu_other_mips64x.go | 11 +
.../golang.org/x/sys/cpu/cpu_other_ppc64x.go | 12 +
.../golang.org/x/sys/cpu/cpu_other_riscv64.go | 11 +
vendor/golang.org/x/sys/cpu/cpu_other_x86.go | 11 +
vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 16 +
vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 33 +
vendor/golang.org/x/sys/cpu/cpu_s390x.go | 172 +
vendor/golang.org/x/sys/cpu/cpu_s390x.s | 57 +
vendor/golang.org/x/sys/cpu/cpu_wasm.go | 17 +
vendor/golang.org/x/sys/cpu/cpu_windows.go | 26 +
.../golang.org/x/sys/cpu/cpu_windows_arm64.go | 38 +
vendor/golang.org/x/sys/cpu/cpu_x86.go | 236 +
vendor/golang.org/x/sys/cpu/cpu_zos.go | 10 +
vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go | 25 +
vendor/golang.org/x/sys/cpu/endian_big.go | 10 +
vendor/golang.org/x/sys/cpu/endian_little.go | 10 +
vendor/golang.org/x/sys/cpu/hwcap_linux.go | 71 +
vendor/golang.org/x/sys/cpu/parse.go | 43 +
.../x/sys/cpu/proc_cpuinfo_linux.go | 53 +
vendor/golang.org/x/sys/cpu/runtime_auxv.go | 16 +
.../x/sys/cpu/runtime_auxv_go121.go | 18 +
.../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 26 +
.../x/sys/cpu/syscall_aix_ppc64_gc.go | 35 +
.../x/sys/cpu/syscall_darwin_arm64_gc.go | 54 +
.../x/sys/cpu/syscall_darwin_x86_gc.go | 98 +
vendor/golang.org/x/sys/cpu/zcpu_windows.go | 48 +
vendor/golang.org/x/sys/unix/.gitignore | 2 +
vendor/golang.org/x/sys/unix/README.md | 184 +
.../golang.org/x/sys/unix/affinity_linux.go | 189 +
vendor/golang.org/x/sys/unix/aliases.go | 13 +
vendor/golang.org/x/sys/unix/asm_aix_ppc64.s | 17 +
vendor/golang.org/x/sys/unix/asm_bsd_386.s | 27 +
vendor/golang.org/x/sys/unix/asm_bsd_amd64.s | 27 +
vendor/golang.org/x/sys/unix/asm_bsd_arm.s | 27 +
vendor/golang.org/x/sys/unix/asm_bsd_arm64.s | 27 +
vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s | 29 +
.../golang.org/x/sys/unix/asm_bsd_riscv64.s | 27 +
vendor/golang.org/x/sys/unix/asm_linux_386.s | 65 +
.../golang.org/x/sys/unix/asm_linux_amd64.s | 57 +
vendor/golang.org/x/sys/unix/asm_linux_arm.s | 56 +
.../golang.org/x/sys/unix/asm_linux_arm64.s | 50 +
.../golang.org/x/sys/unix/asm_linux_loong64.s | 51 +
.../golang.org/x/sys/unix/asm_linux_mips64x.s | 54 +
.../golang.org/x/sys/unix/asm_linux_mipsx.s | 52 +
.../golang.org/x/sys/unix/asm_linux_ppc64x.s | 42 +
.../golang.org/x/sys/unix/asm_linux_riscv64.s | 47 +
.../golang.org/x/sys/unix/asm_linux_s390x.s | 54 +
.../x/sys/unix/asm_openbsd_mips64.s | 29 +
.../golang.org/x/sys/unix/asm_solaris_amd64.s | 17 +
vendor/golang.org/x/sys/unix/asm_zos_s390x.s | 382 +
vendor/golang.org/x/sys/unix/auxv.go | 36 +
.../golang.org/x/sys/unix/auxv_unsupported.go | 13 +
.../golang.org/x/sys/unix/bluetooth_linux.go | 36 +
vendor/golang.org/x/sys/unix/bpxsvc_zos.go | 657 +
vendor/golang.org/x/sys/unix/bpxsvc_zos.s | 192 +
vendor/golang.org/x/sys/unix/cap_freebsd.go | 195 +
vendor/golang.org/x/sys/unix/constants.go | 13 +
vendor/golang.org/x/sys/unix/dev_aix_ppc.go | 26 +
vendor/golang.org/x/sys/unix/dev_aix_ppc64.go | 28 +
vendor/golang.org/x/sys/unix/dev_darwin.go | 24 +
vendor/golang.org/x/sys/unix/dev_dragonfly.go | 30 +
vendor/golang.org/x/sys/unix/dev_freebsd.go | 30 +
vendor/golang.org/x/sys/unix/dev_linux.go | 42 +
vendor/golang.org/x/sys/unix/dev_netbsd.go | 29 +
vendor/golang.org/x/sys/unix/dev_openbsd.go | 29 +
vendor/golang.org/x/sys/unix/dev_zos.go | 28 +
vendor/golang.org/x/sys/unix/dirent.go | 102 +
vendor/golang.org/x/sys/unix/endian_big.go | 9 +
vendor/golang.org/x/sys/unix/endian_little.go | 9 +
vendor/golang.org/x/sys/unix/env_unix.go | 31 +
vendor/golang.org/x/sys/unix/fcntl.go | 36 +
vendor/golang.org/x/sys/unix/fcntl_darwin.go | 24 +
.../x/sys/unix/fcntl_linux_32bit.go | 13 +
vendor/golang.org/x/sys/unix/fdset.go | 27 +
vendor/golang.org/x/sys/unix/gccgo.go | 59 +
vendor/golang.org/x/sys/unix/gccgo_c.c | 44 +
.../x/sys/unix/gccgo_linux_amd64.go | 20 +
vendor/golang.org/x/sys/unix/ifreq_linux.go | 139 +
vendor/golang.org/x/sys/unix/ioctl_linux.go | 334 +
vendor/golang.org/x/sys/unix/ioctl_signed.go | 74 +
.../golang.org/x/sys/unix/ioctl_unsigned.go | 74 +
vendor/golang.org/x/sys/unix/ioctl_zos.go | 71 +
vendor/golang.org/x/sys/unix/mkall.sh | 250 +
vendor/golang.org/x/sys/unix/mkerrors.sh | 814 +
vendor/golang.org/x/sys/unix/mmap_nomremap.go | 13 +
vendor/golang.org/x/sys/unix/mremap.go | 57 +
vendor/golang.org/x/sys/unix/pagesize_unix.go | 15 +
.../golang.org/x/sys/unix/pledge_openbsd.go | 111 +
vendor/golang.org/x/sys/unix/ptrace_darwin.go | 11 +
vendor/golang.org/x/sys/unix/ptrace_ios.go | 11 +
vendor/golang.org/x/sys/unix/race.go | 30 +
vendor/golang.org/x/sys/unix/race0.go | 25 +
.../x/sys/unix/readdirent_getdents.go | 12 +
.../x/sys/unix/readdirent_getdirentries.go | 19 +
vendor/golang.org/x/sys/unix/readv_unix.go | 103 +
.../x/sys/unix/sockcmsg_dragonfly.go | 16 +
.../golang.org/x/sys/unix/sockcmsg_linux.go | 85 +
vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 106 +
.../x/sys/unix/sockcmsg_unix_other.go | 46 +
vendor/golang.org/x/sys/unix/sockcmsg_zos.go | 58 +
.../golang.org/x/sys/unix/symaddr_zos_s390x.s | 75 +
vendor/golang.org/x/sys/unix/syscall.go | 86 +
vendor/golang.org/x/sys/unix/syscall_aix.go | 582 +
.../golang.org/x/sys/unix/syscall_aix_ppc.go | 52 +
.../x/sys/unix/syscall_aix_ppc64.go | 83 +
vendor/golang.org/x/sys/unix/syscall_bsd.go | 609 +
.../golang.org/x/sys/unix/syscall_darwin.go | 711 +
.../x/sys/unix/syscall_darwin_amd64.go | 50 +
.../x/sys/unix/syscall_darwin_arm64.go | 50 +
.../x/sys/unix/syscall_darwin_libSystem.go | 26 +
.../x/sys/unix/syscall_dragonfly.go | 359 +
.../x/sys/unix/syscall_dragonfly_amd64.go | 56 +
.../golang.org/x/sys/unix/syscall_freebsd.go | 455 +
.../x/sys/unix/syscall_freebsd_386.go | 64 +
.../x/sys/unix/syscall_freebsd_amd64.go | 64 +
.../x/sys/unix/syscall_freebsd_arm.go | 60 +
.../x/sys/unix/syscall_freebsd_arm64.go | 60 +
.../x/sys/unix/syscall_freebsd_riscv64.go | 60 +
vendor/golang.org/x/sys/unix/syscall_hurd.go | 30 +
.../golang.org/x/sys/unix/syscall_hurd_386.go | 28 +
.../golang.org/x/sys/unix/syscall_illumos.go | 78 +
vendor/golang.org/x/sys/unix/syscall_linux.go | 2573 +
.../x/sys/unix/syscall_linux_386.go | 314 +
.../x/sys/unix/syscall_linux_alarm.go | 12 +
.../x/sys/unix/syscall_linux_amd64.go | 145 +
.../x/sys/unix/syscall_linux_amd64_gc.go | 12 +
.../x/sys/unix/syscall_linux_arm.go | 219 +
.../x/sys/unix/syscall_linux_arm64.go | 189 +
.../golang.org/x/sys/unix/syscall_linux_gc.go | 14 +
.../x/sys/unix/syscall_linux_gc_386.go | 16 +
.../x/sys/unix/syscall_linux_gc_arm.go | 13 +
.../x/sys/unix/syscall_linux_gccgo_386.go | 30 +
.../x/sys/unix/syscall_linux_gccgo_arm.go | 20 +
.../x/sys/unix/syscall_linux_loong64.go | 221 +
.../x/sys/unix/syscall_linux_mips64x.go | 188 +
.../x/sys/unix/syscall_linux_mipsx.go | 174 +
.../x/sys/unix/syscall_linux_ppc.go | 204 +
.../x/sys/unix/syscall_linux_ppc64x.go | 115 +
.../x/sys/unix/syscall_linux_riscv64.go | 194 +
.../x/sys/unix/syscall_linux_s390x.go | 296 +
.../x/sys/unix/syscall_linux_sparc64.go | 112 +
.../golang.org/x/sys/unix/syscall_netbsd.go | 388 +
.../x/sys/unix/syscall_netbsd_386.go | 37 +
.../x/sys/unix/syscall_netbsd_amd64.go | 37 +
.../x/sys/unix/syscall_netbsd_arm.go | 37 +
.../x/sys/unix/syscall_netbsd_arm64.go | 37 +
.../golang.org/x/sys/unix/syscall_openbsd.go | 346 +
.../x/sys/unix/syscall_openbsd_386.go | 41 +
.../x/sys/unix/syscall_openbsd_amd64.go | 41 +
.../x/sys/unix/syscall_openbsd_arm.go | 41 +
.../x/sys/unix/syscall_openbsd_arm64.go | 41 +
.../x/sys/unix/syscall_openbsd_libc.go | 26 +
.../x/sys/unix/syscall_openbsd_mips64.go | 39 +
.../x/sys/unix/syscall_openbsd_ppc64.go | 41 +
.../x/sys/unix/syscall_openbsd_riscv64.go | 41 +
.../golang.org/x/sys/unix/syscall_solaris.go | 1183 +
.../x/sys/unix/syscall_solaris_amd64.go | 27 +
vendor/golang.org/x/sys/unix/syscall_unix.go | 619 +
.../golang.org/x/sys/unix/syscall_unix_gc.go | 14 +
.../x/sys/unix/syscall_unix_gc_ppc64x.go | 22 +
.../x/sys/unix/syscall_zos_s390x.go | 3213 +
vendor/golang.org/x/sys/unix/sysvshm_linux.go | 20 +
vendor/golang.org/x/sys/unix/sysvshm_unix.go | 51 +
.../x/sys/unix/sysvshm_unix_other.go | 13 +
vendor/golang.org/x/sys/unix/timestruct.go | 76 +
.../golang.org/x/sys/unix/unveil_openbsd.go | 51 +
.../golang.org/x/sys/unix/vgetrandom_linux.go | 13 +
.../x/sys/unix/vgetrandom_unsupported.go | 11 +
vendor/golang.org/x/sys/unix/xattr_bsd.go | 280 +
.../golang.org/x/sys/unix/zerrors_aix_ppc.go | 1384 +
.../x/sys/unix/zerrors_aix_ppc64.go | 1385 +
.../x/sys/unix/zerrors_darwin_amd64.go | 1922 +
.../x/sys/unix/zerrors_darwin_arm64.go | 1922 +
.../x/sys/unix/zerrors_dragonfly_amd64.go | 1737 +
.../x/sys/unix/zerrors_freebsd_386.go | 2042 +
.../x/sys/unix/zerrors_freebsd_amd64.go | 2039 +
.../x/sys/unix/zerrors_freebsd_arm.go | 2033 +
.../x/sys/unix/zerrors_freebsd_arm64.go | 2033 +
.../x/sys/unix/zerrors_freebsd_riscv64.go | 2147 +
vendor/golang.org/x/sys/unix/zerrors_linux.go | 4201 +
.../x/sys/unix/zerrors_linux_386.go | 883 +
.../x/sys/unix/zerrors_linux_amd64.go | 883 +
.../x/sys/unix/zerrors_linux_arm.go | 888 +
.../x/sys/unix/zerrors_linux_arm64.go | 885 +
.../x/sys/unix/zerrors_linux_loong64.go | 875 +
.../x/sys/unix/zerrors_linux_mips.go | 889 +
.../x/sys/unix/zerrors_linux_mips64.go | 889 +
.../x/sys/unix/zerrors_linux_mips64le.go | 889 +
.../x/sys/unix/zerrors_linux_mipsle.go | 889 +
.../x/sys/unix/zerrors_linux_ppc.go | 941 +
.../x/sys/unix/zerrors_linux_ppc64.go | 945 +
.../x/sys/unix/zerrors_linux_ppc64le.go | 945 +
.../x/sys/unix/zerrors_linux_riscv64.go | 885 +
.../x/sys/unix/zerrors_linux_s390x.go | 944 +
.../x/sys/unix/zerrors_linux_sparc64.go | 987 +
.../x/sys/unix/zerrors_netbsd_386.go | 1779 +
.../x/sys/unix/zerrors_netbsd_amd64.go | 1769 +
.../x/sys/unix/zerrors_netbsd_arm.go | 1758 +
.../x/sys/unix/zerrors_netbsd_arm64.go | 1769 +
.../x/sys/unix/zerrors_openbsd_386.go | 1905 +
.../x/sys/unix/zerrors_openbsd_amd64.go | 1905 +
.../x/sys/unix/zerrors_openbsd_arm.go | 1905 +
.../x/sys/unix/zerrors_openbsd_arm64.go | 1905 +
.../x/sys/unix/zerrors_openbsd_mips64.go | 1905 +
.../x/sys/unix/zerrors_openbsd_ppc64.go | 1904 +
.../x/sys/unix/zerrors_openbsd_riscv64.go | 1903 +
.../x/sys/unix/zerrors_solaris_amd64.go | 1556 +
.../x/sys/unix/zerrors_zos_s390x.go | 990 +
.../x/sys/unix/zptrace_armnn_linux.go | 40 +
.../x/sys/unix/zptrace_linux_arm64.go | 17 +
.../x/sys/unix/zptrace_mipsnn_linux.go | 49 +
.../x/sys/unix/zptrace_mipsnnle_linux.go | 49 +
.../x/sys/unix/zptrace_x86_linux.go | 79 +
.../x/sys/unix/zsymaddr_zos_s390x.s | 364 +
.../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 1461 +
.../x/sys/unix/zsyscall_aix_ppc64.go | 1420 +
.../x/sys/unix/zsyscall_aix_ppc64_gc.go | 1188 +
.../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 1069 +
.../x/sys/unix/zsyscall_darwin_amd64.go | 2728 +
.../x/sys/unix/zsyscall_darwin_amd64.s | 799 +
.../x/sys/unix/zsyscall_darwin_arm64.go | 2728 +
.../x/sys/unix/zsyscall_darwin_arm64.s | 799 +
.../x/sys/unix/zsyscall_dragonfly_amd64.go | 1666 +
.../x/sys/unix/zsyscall_freebsd_386.go | 1886 +
.../x/sys/unix/zsyscall_freebsd_amd64.go | 1886 +
.../x/sys/unix/zsyscall_freebsd_arm.go | 1886 +
.../x/sys/unix/zsyscall_freebsd_arm64.go | 1886 +
.../x/sys/unix/zsyscall_freebsd_riscv64.go | 1886 +
.../x/sys/unix/zsyscall_illumos_amd64.go | 101 +
.../golang.org/x/sys/unix/zsyscall_linux.go | 2250 +
.../x/sys/unix/zsyscall_linux_386.go | 486 +
.../x/sys/unix/zsyscall_linux_amd64.go | 653 +
.../x/sys/unix/zsyscall_linux_arm.go | 601 +
.../x/sys/unix/zsyscall_linux_arm64.go | 552 +
.../x/sys/unix/zsyscall_linux_loong64.go | 486 +
.../x/sys/unix/zsyscall_linux_mips.go | 653 +
.../x/sys/unix/zsyscall_linux_mips64.go | 647 +
.../x/sys/unix/zsyscall_linux_mips64le.go | 636 +
.../x/sys/unix/zsyscall_linux_mipsle.go | 653 +
.../x/sys/unix/zsyscall_linux_ppc.go | 658 +
.../x/sys/unix/zsyscall_linux_ppc64.go | 704 +
.../x/sys/unix/zsyscall_linux_ppc64le.go | 704 +
.../x/sys/unix/zsyscall_linux_riscv64.go | 548 +
.../x/sys/unix/zsyscall_linux_s390x.go | 495 +
.../x/sys/unix/zsyscall_linux_sparc64.go | 648 +
.../x/sys/unix/zsyscall_netbsd_386.go | 1848 +
.../x/sys/unix/zsyscall_netbsd_amd64.go | 1848 +
.../x/sys/unix/zsyscall_netbsd_arm.go | 1848 +
.../x/sys/unix/zsyscall_netbsd_arm64.go | 1848 +
.../x/sys/unix/zsyscall_openbsd_386.go | 2407 +
.../x/sys/unix/zsyscall_openbsd_386.s | 719 +
.../x/sys/unix/zsyscall_openbsd_amd64.go | 2407 +
.../x/sys/unix/zsyscall_openbsd_amd64.s | 719 +
.../x/sys/unix/zsyscall_openbsd_arm.go | 2407 +
.../x/sys/unix/zsyscall_openbsd_arm.s | 719 +
.../x/sys/unix/zsyscall_openbsd_arm64.go | 2407 +
.../x/sys/unix/zsyscall_openbsd_arm64.s | 719 +
.../x/sys/unix/zsyscall_openbsd_mips64.go | 2407 +
.../x/sys/unix/zsyscall_openbsd_mips64.s | 719 +
.../x/sys/unix/zsyscall_openbsd_ppc64.go | 2407 +
.../x/sys/unix/zsyscall_openbsd_ppc64.s | 862 +
.../x/sys/unix/zsyscall_openbsd_riscv64.go | 2407 +
.../x/sys/unix/zsyscall_openbsd_riscv64.s | 719 +
.../x/sys/unix/zsyscall_solaris_amd64.go | 2217 +
.../x/sys/unix/zsyscall_zos_s390x.go | 3458 +
.../x/sys/unix/zsysctl_openbsd_386.go | 280 +
.../x/sys/unix/zsysctl_openbsd_amd64.go | 280 +
.../x/sys/unix/zsysctl_openbsd_arm.go | 280 +
.../x/sys/unix/zsysctl_openbsd_arm64.go | 280 +
.../x/sys/unix/zsysctl_openbsd_mips64.go | 280 +
.../x/sys/unix/zsysctl_openbsd_ppc64.go | 280 +
.../x/sys/unix/zsysctl_openbsd_riscv64.go | 281 +
.../x/sys/unix/zsysnum_darwin_amd64.go | 439 +
.../x/sys/unix/zsysnum_darwin_arm64.go | 437 +
.../x/sys/unix/zsysnum_dragonfly_amd64.go | 316 +
.../x/sys/unix/zsysnum_freebsd_386.go | 393 +
.../x/sys/unix/zsysnum_freebsd_amd64.go | 393 +
.../x/sys/unix/zsysnum_freebsd_arm.go | 393 +
.../x/sys/unix/zsysnum_freebsd_arm64.go | 393 +
.../x/sys/unix/zsysnum_freebsd_riscv64.go | 393 +
.../x/sys/unix/zsysnum_linux_386.go | 470 +
.../x/sys/unix/zsysnum_linux_amd64.go | 394 +
.../x/sys/unix/zsysnum_linux_arm.go | 434 +
.../x/sys/unix/zsysnum_linux_arm64.go | 337 +
.../x/sys/unix/zsysnum_linux_loong64.go | 334 +
.../x/sys/unix/zsysnum_linux_mips.go | 454 +
.../x/sys/unix/zsysnum_linux_mips64.go | 384 +
.../x/sys/unix/zsysnum_linux_mips64le.go | 384 +
.../x/sys/unix/zsysnum_linux_mipsle.go | 454 +
.../x/sys/unix/zsysnum_linux_ppc.go | 461 +
.../x/sys/unix/zsysnum_linux_ppc64.go | 433 +
.../x/sys/unix/zsysnum_linux_ppc64le.go | 433 +
.../x/sys/unix/zsysnum_linux_riscv64.go | 338 +
.../x/sys/unix/zsysnum_linux_s390x.go | 399 +
.../x/sys/unix/zsysnum_linux_sparc64.go | 413 +
.../x/sys/unix/zsysnum_netbsd_386.go | 274 +
.../x/sys/unix/zsysnum_netbsd_amd64.go | 274 +
.../x/sys/unix/zsysnum_netbsd_arm.go | 274 +
.../x/sys/unix/zsysnum_netbsd_arm64.go | 274 +
.../x/sys/unix/zsysnum_openbsd_386.go | 219 +
.../x/sys/unix/zsysnum_openbsd_amd64.go | 219 +
.../x/sys/unix/zsysnum_openbsd_arm.go | 219 +
.../x/sys/unix/zsysnum_openbsd_arm64.go | 218 +
.../x/sys/unix/zsysnum_openbsd_mips64.go | 221 +
.../x/sys/unix/zsysnum_openbsd_ppc64.go | 217 +
.../x/sys/unix/zsysnum_openbsd_riscv64.go | 218 +
.../x/sys/unix/zsysnum_zos_s390x.go | 2852 +
.../golang.org/x/sys/unix/ztypes_aix_ppc.go | 353 +
.../golang.org/x/sys/unix/ztypes_aix_ppc64.go | 357 +
.../x/sys/unix/ztypes_darwin_amd64.go | 878 +
.../x/sys/unix/ztypes_darwin_arm64.go | 878 +
.../x/sys/unix/ztypes_dragonfly_amd64.go | 473 +
.../x/sys/unix/ztypes_freebsd_386.go | 651 +
.../x/sys/unix/ztypes_freebsd_amd64.go | 656 +
.../x/sys/unix/ztypes_freebsd_arm.go | 642 +
.../x/sys/unix/ztypes_freebsd_arm64.go | 636 +
.../x/sys/unix/ztypes_freebsd_riscv64.go | 638 +
vendor/golang.org/x/sys/unix/ztypes_linux.go | 6475 +
.../golang.org/x/sys/unix/ztypes_linux_386.go | 717 +
.../x/sys/unix/ztypes_linux_amd64.go | 731 +
.../golang.org/x/sys/unix/ztypes_linux_arm.go | 711 +
.../x/sys/unix/ztypes_linux_arm64.go | 710 +
.../x/sys/unix/ztypes_linux_loong64.go | 711 +
.../x/sys/unix/ztypes_linux_mips.go | 716 +
.../x/sys/unix/ztypes_linux_mips64.go | 713 +
.../x/sys/unix/ztypes_linux_mips64le.go | 713 +
.../x/sys/unix/ztypes_linux_mipsle.go | 716 +
.../golang.org/x/sys/unix/ztypes_linux_ppc.go | 724 +
.../x/sys/unix/ztypes_linux_ppc64.go | 719 +
.../x/sys/unix/ztypes_linux_ppc64le.go | 719 +
.../x/sys/unix/ztypes_linux_riscv64.go | 798 +
.../x/sys/unix/ztypes_linux_s390x.go | 733 +
.../x/sys/unix/ztypes_linux_sparc64.go | 714 +
.../x/sys/unix/ztypes_netbsd_386.go | 585 +
.../x/sys/unix/ztypes_netbsd_amd64.go | 593 +
.../x/sys/unix/ztypes_netbsd_arm.go | 590 +
.../x/sys/unix/ztypes_netbsd_arm64.go | 593 +
.../x/sys/unix/ztypes_openbsd_386.go | 568 +
.../x/sys/unix/ztypes_openbsd_amd64.go | 568 +
.../x/sys/unix/ztypes_openbsd_arm.go | 575 +
.../x/sys/unix/ztypes_openbsd_arm64.go | 568 +
.../x/sys/unix/ztypes_openbsd_mips64.go | 568 +
.../x/sys/unix/ztypes_openbsd_ppc64.go | 570 +
.../x/sys/unix/ztypes_openbsd_riscv64.go | 570 +
.../x/sys/unix/ztypes_solaris_amd64.go | 516 +
.../golang.org/x/sys/unix/ztypes_zos_s390x.go | 552 +
vendor/golang.org/x/sys/windows/aliases.go | 13 +
.../golang.org/x/sys/windows/dll_windows.go | 380 +
.../golang.org/x/sys/windows/env_windows.go | 57 +
vendor/golang.org/x/sys/windows/eventlog.go | 20 +
.../golang.org/x/sys/windows/exec_windows.go | 248 +
.../x/sys/windows/memory_windows.go | 48 +
vendor/golang.org/x/sys/windows/mkerrors.bash | 70 +
.../x/sys/windows/mkknownfolderids.bash | 27 +
vendor/golang.org/x/sys/windows/mksyscall.go | 9 +
vendor/golang.org/x/sys/windows/race.go | 30 +
vendor/golang.org/x/sys/windows/race0.go | 25 +
.../x/sys/windows/security_windows.go | 1501 +
vendor/golang.org/x/sys/windows/service.go | 257 +
.../x/sys/windows/setupapi_windows.go | 1425 +
vendor/golang.org/x/sys/windows/str.go | 22 +
vendor/golang.org/x/sys/windows/syscall.go | 104 +
.../x/sys/windows/syscall_windows.go | 1948 +
.../golang.org/x/sys/windows/types_windows.go | 4056 +
.../x/sys/windows/types_windows_386.go | 35 +
.../x/sys/windows/types_windows_amd64.go | 34 +
.../x/sys/windows/types_windows_arm.go | 35 +
.../x/sys/windows/types_windows_arm64.go | 34 +
.../x/sys/windows/zerrors_windows.go | 9468 ++
.../x/sys/windows/zknownfolderids_windows.go | 149 +
.../x/sys/windows/zsyscall_windows.go | 4828 +
vendor/golang.org/x/text/LICENSE | 27 +
vendor/golang.org/x/text/PATENTS | 22 +
.../x/text/encoding/charmap/charmap.go | 249 +
.../x/text/encoding/charmap/tables.go | 7410 +
vendor/golang.org/x/text/encoding/encoding.go | 335 +
.../x/text/encoding/htmlindex/htmlindex.go | 86 +
.../x/text/encoding/htmlindex/map.go | 105 +
.../x/text/encoding/htmlindex/tables.go | 362 +
.../x/text/encoding/ianaindex/ascii.go | 74 +
.../x/text/encoding/ianaindex/ianaindex.go | 214 +
.../x/text/encoding/ianaindex/tables.go | 2355 +
.../internal/identifier/identifier.go | 81 +
.../text/encoding/internal/identifier/mib.go | 1627 +
.../x/text/encoding/internal/internal.go | 75 +
.../x/text/encoding/japanese/all.go | 12 +
.../x/text/encoding/japanese/eucjp.go | 225 +
.../x/text/encoding/japanese/iso2022jp.go | 299 +
.../x/text/encoding/japanese/shiftjis.go | 189 +
.../x/text/encoding/japanese/tables.go | 26971 ++++
.../x/text/encoding/korean/euckr.go | 177 +
.../x/text/encoding/korean/tables.go | 34152 ++++
.../x/text/encoding/simplifiedchinese/all.go | 12 +
.../x/text/encoding/simplifiedchinese/gbk.go | 273 +
.../encoding/simplifiedchinese/hzgb2312.go | 245 +
.../text/encoding/simplifiedchinese/tables.go | 43999 ++++++
.../text/encoding/traditionalchinese/big5.go | 199 +
.../encoding/traditionalchinese/tables.go | 37142 +++++
.../x/text/encoding/unicode/override.go | 82 +
.../x/text/encoding/unicode/unicode.go | 512 +
.../x/text/internal/language/common.go | 16 +
.../x/text/internal/language/compact.go | 29 +
.../text/internal/language/compact/compact.go | 61 +
.../internal/language/compact/language.go | 260 +
.../text/internal/language/compact/parents.go | 120 +
.../text/internal/language/compact/tables.go | 1015 +
.../x/text/internal/language/compact/tags.go | 91 +
.../x/text/internal/language/compose.go | 167 +
.../x/text/internal/language/coverage.go | 28 +
.../x/text/internal/language/language.go | 627 +
.../x/text/internal/language/lookup.go | 412 +
.../x/text/internal/language/match.go | 226 +
.../x/text/internal/language/parse.go | 608 +
.../x/text/internal/language/tables.go | 3494 +
.../x/text/internal/language/tags.go | 48 +
vendor/golang.org/x/text/internal/tag/tag.go | 100 +
.../internal/utf8internal/utf8internal.go | 87 +
vendor/golang.org/x/text/language/coverage.go | 187 +
vendor/golang.org/x/text/language/doc.go | 98 +
vendor/golang.org/x/text/language/language.go | 605 +
vendor/golang.org/x/text/language/match.go | 735 +
vendor/golang.org/x/text/language/parse.go | 256 +
vendor/golang.org/x/text/language/tables.go | 298 +
vendor/golang.org/x/text/language/tags.go | 145 +
vendor/golang.org/x/text/runes/cond.go | 187 +
vendor/golang.org/x/text/runes/runes.go | 355 +
.../x/text/secure/bidirule/bidirule.go | 340 +
.../golang.org/x/text/transform/transform.go | 709 +
vendor/golang.org/x/text/unicode/bidi/bidi.go | 359 +
.../golang.org/x/text/unicode/bidi/bracket.go | 335 +
vendor/golang.org/x/text/unicode/bidi/core.go | 1064 +
vendor/golang.org/x/text/unicode/bidi/prop.go | 206 +
.../x/text/unicode/bidi/tables15.0.0.go | 2042 +
.../x/text/unicode/bidi/tables17.0.0.go | 2135 +
.../golang.org/x/text/unicode/bidi/trieval.go | 48 +
.../x/text/unicode/norm/composition.go | 512 +
.../x/text/unicode/norm/forminfo.go | 289 +
.../golang.org/x/text/unicode/norm/input.go | 109 +
vendor/golang.org/x/text/unicode/norm/iter.go | 458 +
.../x/text/unicode/norm/normalize.go | 610 +
.../x/text/unicode/norm/readwriter.go | 125 +
.../x/text/unicode/norm/tables15.0.0.go | 7907 +
.../x/text/unicode/norm/tables17.0.0.go | 8104 +
.../x/text/unicode/norm/transform.go | 88 +
vendor/golang.org/x/text/unicode/norm/trie.go | 54 +
vendor/modules.txt | 115 +
1262 files changed, 817274 insertions(+)
create mode 100644 vendor/github.com/andybalholm/brotli/.gitignore
create mode 100644 vendor/github.com/andybalholm/brotli/LICENSE
create mode 100644 vendor/github.com/andybalholm/brotli/README.md
create mode 100644 vendor/github.com/andybalholm/brotli/backward_references.go
create mode 100644 vendor/github.com/andybalholm/brotli/backward_references_hq.go
create mode 100644 vendor/github.com/andybalholm/brotli/bit_cost.go
create mode 100644 vendor/github.com/andybalholm/brotli/bit_reader.go
create mode 100644 vendor/github.com/andybalholm/brotli/bitwriter.go
create mode 100644 vendor/github.com/andybalholm/brotli/block_splitter.go
create mode 100644 vendor/github.com/andybalholm/brotli/block_splitter_command.go
create mode 100644 vendor/github.com/andybalholm/brotli/block_splitter_distance.go
create mode 100644 vendor/github.com/andybalholm/brotli/block_splitter_literal.go
create mode 100644 vendor/github.com/andybalholm/brotli/brotli_bit_stream.go
create mode 100644 vendor/github.com/andybalholm/brotli/cluster.go
create mode 100644 vendor/github.com/andybalholm/brotli/cluster_command.go
create mode 100644 vendor/github.com/andybalholm/brotli/cluster_distance.go
create mode 100644 vendor/github.com/andybalholm/brotli/cluster_literal.go
create mode 100644 vendor/github.com/andybalholm/brotli/command.go
create mode 100644 vendor/github.com/andybalholm/brotli/compress_fragment.go
create mode 100644 vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go
create mode 100644 vendor/github.com/andybalholm/brotli/constants.go
create mode 100644 vendor/github.com/andybalholm/brotli/context.go
create mode 100644 vendor/github.com/andybalholm/brotli/decode.go
create mode 100644 vendor/github.com/andybalholm/brotli/dictionary.go
create mode 100644 vendor/github.com/andybalholm/brotli/dictionary_hash.go
create mode 100644 vendor/github.com/andybalholm/brotli/encode.go
create mode 100644 vendor/github.com/andybalholm/brotli/encoder.go
create mode 100644 vendor/github.com/andybalholm/brotli/encoder_dict.go
create mode 100644 vendor/github.com/andybalholm/brotli/encoder_fast.go
create mode 100644 vendor/github.com/andybalholm/brotli/entropy_encode.go
create mode 100644 vendor/github.com/andybalholm/brotli/entropy_encode_static.go
create mode 100644 vendor/github.com/andybalholm/brotli/fast_log.go
create mode 100644 vendor/github.com/andybalholm/brotli/find_match_length.go
create mode 100644 vendor/github.com/andybalholm/brotli/flate/LICENSE
create mode 100644 vendor/github.com/andybalholm/brotli/flate/README.md
create mode 100644 vendor/github.com/andybalholm/brotli/flate/gzip.go
create mode 100644 vendor/github.com/andybalholm/brotli/flate/huffman_bit_writer.go
create mode 100644 vendor/github.com/andybalholm/brotli/flate/huffman_code.go
create mode 100644 vendor/github.com/andybalholm/brotli/flate/token.go
create mode 100644 vendor/github.com/andybalholm/brotli/flate/writer.go
create mode 100644 vendor/github.com/andybalholm/brotli/h10.go
create mode 100644 vendor/github.com/andybalholm/brotli/h5.go
create mode 100644 vendor/github.com/andybalholm/brotli/h6.go
create mode 100644 vendor/github.com/andybalholm/brotli/hash.go
create mode 100644 vendor/github.com/andybalholm/brotli/hash_composite.go
create mode 100644 vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go
create mode 100644 vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go
create mode 100644 vendor/github.com/andybalholm/brotli/hash_rolling.go
create mode 100644 vendor/github.com/andybalholm/brotli/histogram.go
create mode 100644 vendor/github.com/andybalholm/brotli/http.go
create mode 100644 vendor/github.com/andybalholm/brotli/huffman.go
create mode 100644 vendor/github.com/andybalholm/brotli/literal_cost.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/bargain1.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/bargain2.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/bargain3.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/emitter.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/m0.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/m4.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/matchfinder.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/pathfinder.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/textencoder.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/trio.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/zdfast.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/zfast.go
create mode 100644 vendor/github.com/andybalholm/brotli/matchfinder/zm.go
create mode 100644 vendor/github.com/andybalholm/brotli/memory.go
create mode 100644 vendor/github.com/andybalholm/brotli/metablock.go
create mode 100644 vendor/github.com/andybalholm/brotli/metablock_command.go
create mode 100644 vendor/github.com/andybalholm/brotli/metablock_distance.go
create mode 100644 vendor/github.com/andybalholm/brotli/metablock_literal.go
create mode 100644 vendor/github.com/andybalholm/brotli/params.go
create mode 100644 vendor/github.com/andybalholm/brotli/platform.go
create mode 100644 vendor/github.com/andybalholm/brotli/prefix.go
create mode 100644 vendor/github.com/andybalholm/brotli/prefix_dec.go
create mode 100644 vendor/github.com/andybalholm/brotli/quality.go
create mode 100644 vendor/github.com/andybalholm/brotli/reader.go
create mode 100644 vendor/github.com/andybalholm/brotli/ringbuffer.go
create mode 100644 vendor/github.com/andybalholm/brotli/state.go
create mode 100644 vendor/github.com/andybalholm/brotli/static_dict.go
create mode 100644 vendor/github.com/andybalholm/brotli/static_dict_lut.go
create mode 100644 vendor/github.com/andybalholm/brotli/symbol_list.go
create mode 100644 vendor/github.com/andybalholm/brotli/transform.go
create mode 100644 vendor/github.com/andybalholm/brotli/utf8_util.go
create mode 100644 vendor/github.com/andybalholm/brotli/util.go
create mode 100644 vendor/github.com/andybalholm/brotli/write_bits.go
create mode 100644 vendor/github.com/andybalholm/brotli/writer.go
create mode 100644 vendor/github.com/google/go-querystring/LICENSE
create mode 100644 vendor/github.com/google/go-querystring/query/encode.go
create mode 100644 vendor/github.com/icholy/digest/.gitignore
create mode 100644 vendor/github.com/icholy/digest/LICENSE
create mode 100644 vendor/github.com/icholy/digest/README.md
create mode 100644 vendor/github.com/icholy/digest/challenge.go
create mode 100644 vendor/github.com/icholy/digest/credentials.go
create mode 100644 vendor/github.com/icholy/digest/digest.go
create mode 100644 vendor/github.com/icholy/digest/internal/param/param.go
create mode 100644 vendor/github.com/icholy/digest/transport.go
create mode 100644 vendor/github.com/klauspost/compress/.gitattributes
create mode 100644 vendor/github.com/klauspost/compress/.gitignore
create mode 100644 vendor/github.com/klauspost/compress/.goreleaser.yml
create mode 100644 vendor/github.com/klauspost/compress/LICENSE
create mode 100644 vendor/github.com/klauspost/compress/README.md
create mode 100644 vendor/github.com/klauspost/compress/SECURITY.md
create mode 100644 vendor/github.com/klauspost/compress/compressible.go
create mode 100644 vendor/github.com/klauspost/compress/fse/README.md
create mode 100644 vendor/github.com/klauspost/compress/fse/bitreader.go
create mode 100644 vendor/github.com/klauspost/compress/fse/bitwriter.go
create mode 100644 vendor/github.com/klauspost/compress/fse/bytereader.go
create mode 100644 vendor/github.com/klauspost/compress/fse/compress.go
create mode 100644 vendor/github.com/klauspost/compress/fse/decompress.go
create mode 100644 vendor/github.com/klauspost/compress/fse/fse.go
create mode 100644 vendor/github.com/klauspost/compress/gen.sh
create mode 100644 vendor/github.com/klauspost/compress/huff0/.gitignore
create mode 100644 vendor/github.com/klauspost/compress/huff0/README.md
create mode 100644 vendor/github.com/klauspost/compress/huff0/bitreader.go
create mode 100644 vendor/github.com/klauspost/compress/huff0/bitwriter.go
create mode 100644 vendor/github.com/klauspost/compress/huff0/compress.go
create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress.go
create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_generic.go
create mode 100644 vendor/github.com/klauspost/compress/huff0/huff0.go
create mode 100644 vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go
create mode 100644 vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
create mode 100644 vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s
create mode 100644 vendor/github.com/klauspost/compress/internal/le/le.go
create mode 100644 vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
create mode 100644 vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/LICENSE
create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/decode.go
create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/decode_other.go
create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/encode.go
create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/encode_other.go
create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/snappy.go
create mode 100644 vendor/github.com/klauspost/compress/s2sx.mod
create mode 100644 vendor/github.com/klauspost/compress/s2sx.sum
create mode 100644 vendor/github.com/klauspost/compress/zstd/README.md
create mode 100644 vendor/github.com/klauspost/compress/zstd/bitreader.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/bitwriter.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/blockdec.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/blockenc.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/blocktype_string.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/bytebuf.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/bytereader.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/decodeheader.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/decoder.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/decoder_options.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/dict.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_base.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_best.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_better.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_dfast.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_fast.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/encoder.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/encoder_options.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/framedec.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/frameenc.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_encoder.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_predefined.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/hash.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/history.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s
create mode 100644 vendor/github.com/klauspost/compress/zstd/matchlen_generic.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_generic.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/seqenc.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/simple_go124.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/snappy.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/zip.go
create mode 100644 vendor/github.com/klauspost/compress/zstd/zstd.go
create mode 100644 vendor/github.com/quic-go/qpack/.codecov.yml
create mode 100644 vendor/github.com/quic-go/qpack/.gitignore
create mode 100644 vendor/github.com/quic-go/qpack/.gitmodules
create mode 100644 vendor/github.com/quic-go/qpack/.golangci.yml
create mode 100644 vendor/github.com/quic-go/qpack/LICENSE.md
create mode 100644 vendor/github.com/quic-go/qpack/README.md
create mode 100644 vendor/github.com/quic-go/qpack/decoder.go
create mode 100644 vendor/github.com/quic-go/qpack/encoder.go
create mode 100644 vendor/github.com/quic-go/qpack/header_field.go
create mode 100644 vendor/github.com/quic-go/qpack/static_table.go
create mode 100644 vendor/github.com/quic-go/qpack/varint.go
create mode 100644 vendor/github.com/quic-go/quic-go/.gitignore
create mode 100644 vendor/github.com/quic-go/quic-go/.golangci.yml
create mode 100644 vendor/github.com/quic-go/quic-go/FIPS140.md
create mode 100644 vendor/github.com/quic-go/quic-go/FUZZING.md
create mode 100644 vendor/github.com/quic-go/quic-go/LICENSE
create mode 100644 vendor/github.com/quic-go/quic-go/README.md
create mode 100644 vendor/github.com/quic-go/quic-go/SECURITY.md
create mode 100644 vendor/github.com/quic-go/quic-go/buffer_pool.go
create mode 100644 vendor/github.com/quic-go/quic-go/client.go
create mode 100644 vendor/github.com/quic-go/quic-go/closed_conn.go
create mode 100644 vendor/github.com/quic-go/quic-go/codecov.yml
create mode 100644 vendor/github.com/quic-go/quic-go/config.go
create mode 100644 vendor/github.com/quic-go/quic-go/conn_id_generator.go
create mode 100644 vendor/github.com/quic-go/quic-go/conn_id_manager.go
create mode 100644 vendor/github.com/quic-go/quic-go/connection.go
create mode 100644 vendor/github.com/quic-go/quic-go/connection_logging.go
create mode 100644 vendor/github.com/quic-go/quic-go/crypto_stream.go
create mode 100644 vendor/github.com/quic-go/quic-go/crypto_stream_manager.go
create mode 100644 vendor/github.com/quic-go/quic-go/datagram_queue.go
create mode 100644 vendor/github.com/quic-go/quic-go/errors.go
create mode 100644 vendor/github.com/quic-go/quic-go/frame_sorter.go
create mode 100644 vendor/github.com/quic-go/quic-go/framer.go
create mode 100644 vendor/github.com/quic-go/quic-go/http3/qlog/event.go
create mode 100644 vendor/github.com/quic-go/quic-go/http3/qlog/frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/http3/qlog/qlog_dir.go
create mode 100644 vendor/github.com/quic-go/quic-go/interface.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/lost_packet_tracker.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_history.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/clock.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/cubic.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/hybrid_slow_start.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/interface.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/base_flow_controller.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/interface.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite_fips140.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/fake_conn.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/fips140_go126.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/fips140_legacy.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/hkdf.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/interface.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go125.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go126.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/retry_go125.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/retry_go126.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/tls_config.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/monotime/time.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/connection_id.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/encryption_level.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/key_phase.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/packet_number.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/params.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/perspective.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/stream.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/protocol/version.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/qerr/errors.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/connstats.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/README.md
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/linkedlist.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/log.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/rand.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/ack_frequency_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/ack_range.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/connection_close_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/crypto_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/data_blocked_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/frame_type.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/handshake_done_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/header.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/immediate_ack_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/log.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/max_data_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/max_stream_data_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/max_streams_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/new_token_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/path_challenge_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/path_response_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/ping_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/pool.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/retire_connection_id_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/short_header.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/stop_sending_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/stream_data_blocked_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/stream_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/streams_blocked_frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go
create mode 100644 vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go
create mode 100644 vendor/github.com/quic-go/quic-go/mockgen.go
create mode 100644 vendor/github.com/quic-go/quic-go/mtu_discoverer.go
create mode 100644 vendor/github.com/quic-go/quic-go/oss-fuzz.sh
create mode 100644 vendor/github.com/quic-go/quic-go/packet_packer.go
create mode 100644 vendor/github.com/quic-go/quic-go/packet_unpacker.go
create mode 100644 vendor/github.com/quic-go/quic-go/path_manager.go
create mode 100644 vendor/github.com/quic-go/quic-go/path_manager_outgoing.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlog/event.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlog/frame.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlog/packet_header.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlog/qlog_dir.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlog/types.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlogwriter/jsontext/encoder.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlogwriter/trace.go
create mode 100644 vendor/github.com/quic-go/quic-go/qlogwriter/writer.go
create mode 100644 vendor/github.com/quic-go/quic-go/quicvarint/io.go
create mode 100644 vendor/github.com/quic-go/quic-go/quicvarint/varint.go
create mode 100644 vendor/github.com/quic-go/quic-go/receive_stream.go
create mode 100644 vendor/github.com/quic-go/quic-go/retransmission_queue.go
create mode 100644 vendor/github.com/quic-go/quic-go/send_conn.go
create mode 100644 vendor/github.com/quic-go/quic-go/send_queue.go
create mode 100644 vendor/github.com/quic-go/quic-go/send_stream.go
create mode 100644 vendor/github.com/quic-go/quic-go/server.go
create mode 100644 vendor/github.com/quic-go/quic-go/sni.go
create mode 100644 vendor/github.com/quic-go/quic-go/stateless_reset.go
create mode 100644 vendor/github.com/quic-go/quic-go/stream.go
create mode 100644 vendor/github.com/quic-go/quic-go/streams_map.go
create mode 100644 vendor/github.com/quic-go/quic-go/streams_map_incoming.go
create mode 100644 vendor/github.com/quic-go/quic-go/streams_map_outgoing.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_buffers.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df_darwin.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df_linux.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_df_windows.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_darwin.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_freebsd.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_oob.go
create mode 100644 vendor/github.com/quic-go/quic-go/sys_conn_windows.go
create mode 100644 vendor/github.com/quic-go/quic-go/token_store.go
create mode 100644 vendor/github.com/quic-go/quic-go/transport.go
create mode 100644 vendor/github.com/refraction-networking/utls/.travis.yml
create mode 100644 vendor/github.com/refraction-networking/utls/CONTRIBUTING.md
create mode 100644 vendor/github.com/refraction-networking/utls/CONTRIBUTORS_GUIDE.md
create mode 100644 vendor/github.com/refraction-networking/utls/LICENSE
create mode 100644 vendor/github.com/refraction-networking/utls/README.md
create mode 100644 vendor/github.com/refraction-networking/utls/SECURITY.md
create mode 100644 vendor/github.com/refraction-networking/utls/alert.go
create mode 100644 vendor/github.com/refraction-networking/utls/auth.go
create mode 100644 vendor/github.com/refraction-networking/utls/cache.go
create mode 100644 vendor/github.com/refraction-networking/utls/cipher_suites.go
create mode 100644 vendor/github.com/refraction-networking/utls/common.go
create mode 100644 vendor/github.com/refraction-networking/utls/common_string.go
create mode 100644 vendor/github.com/refraction-networking/utls/conn.go
create mode 100644 vendor/github.com/refraction-networking/utls/defaults.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/LICENSE
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/README.md
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/alerts.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/authorization_data_formats.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/cachedinformationtype_values.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/certificate_compression_algorithm_ids.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/certificate_status_types.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/certificte_types.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/cipher_suites.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/clientcertificatetype_identifiers.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/comp_meth_ids.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/contenttype.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/ec_curve_types.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/ec_point_formats.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/exttype_values.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/handshaketype.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/hashalgorithm.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/heartbeat_message_types.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/heartbeat_mode.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/hpke_aead_identifiers.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/hpke_kdf_identifiers.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/hpke_kem_identifiers.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/psk_key_exchange_mode.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/quic_frame_types.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/quic_transport_error_codes.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/quic_transport_parameters.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/signaturealgorithm.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/signaturescheme.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/supplemental_data_formats.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/supported_groups.go
create mode 100644 vendor/github.com/refraction-networking/utls/dicttls/usermappingtype_values.go
create mode 100644 vendor/github.com/refraction-networking/utls/ech.go
create mode 100644 vendor/github.com/refraction-networking/utls/handshake_client.go
create mode 100644 vendor/github.com/refraction-networking/utls/handshake_client_tls13.go
create mode 100644 vendor/github.com/refraction-networking/utls/handshake_messages.go
create mode 100644 vendor/github.com/refraction-networking/utls/handshake_server.go
create mode 100644 vendor/github.com/refraction-networking/utls/handshake_server_tls13.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/boring/notboring.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/byteorder/byteorder.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/fips140tls/fipstls.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/helper/typeconv.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/hkdf/hkdf.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/hpke/hpke.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/quicvarint/protocol/protocol.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/quicvarint/varint.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/tls12/tls12.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/tls13/tls13.go
create mode 100644 vendor/github.com/refraction-networking/utls/internal/tls13/u_tls13.go
create mode 100644 vendor/github.com/refraction-networking/utls/key_agreement.go
create mode 100644 vendor/github.com/refraction-networking/utls/key_schedule.go
create mode 100644 vendor/github.com/refraction-networking/utls/logo.png
create mode 100644 vendor/github.com/refraction-networking/utls/logo_small.png
create mode 100644 vendor/github.com/refraction-networking/utls/prf.go
create mode 100644 vendor/github.com/refraction-networking/utls/quic.go
create mode 100644 vendor/github.com/refraction-networking/utls/ticket.go
create mode 100644 vendor/github.com/refraction-networking/utls/tls.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_alias.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_clienthello_json.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_common.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_conn.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_ech.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_fingerprinter.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_handshake_client.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_handshake_messages.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_hpke.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_key_schedule.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_parrots.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_pre_shared_key.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_prng.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_public.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_quic.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_quic_transport_parameters.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_roller.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_session_controller.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_session_ticket.go
create mode 100644 vendor/github.com/refraction-networking/utls/u_tls_extensions.go
create mode 100644 vendor/golang.org/x/crypto/LICENSE
create mode 100644 vendor/golang.org/x/crypto/PATENTS
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.go
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_arm64.s
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_generic.go
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_noasm.go
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.go
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.s
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.go
create mode 100644 vendor/golang.org/x/crypto/chacha20/chacha_s390x.s
create mode 100644 vendor/golang.org/x/crypto/chacha20/xor.go
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/fips140only_compat.go
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/fips140only_go1.26.go
create mode 100644 vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1.go
create mode 100644 vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go
create mode 100644 vendor/golang.org/x/crypto/cryptobyte/builder.go
create mode 100644 vendor/golang.org/x/crypto/cryptobyte/string.go
create mode 100644 vendor/golang.org/x/crypto/hkdf/hkdf.go
create mode 100644 vendor/golang.org/x/crypto/internal/alias/alias.go
create mode 100644 vendor/golang.org/x/crypto/internal/alias/alias_purego.go
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/poly1305.go
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go
create mode 100644 vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s
create mode 100644 vendor/golang.org/x/crypto/sha3/hashes.go
create mode 100644 vendor/golang.org/x/crypto/sha3/legacy_hash.go
create mode 100644 vendor/golang.org/x/crypto/sha3/legacy_keccakf.go
create mode 100644 vendor/golang.org/x/crypto/sha3/shake.go
create mode 100644 vendor/golang.org/x/net/LICENSE
create mode 100644 vendor/golang.org/x/net/PATENTS
create mode 100644 vendor/golang.org/x/net/bpf/asm.go
create mode 100644 vendor/golang.org/x/net/bpf/constants.go
create mode 100644 vendor/golang.org/x/net/bpf/doc.go
create mode 100644 vendor/golang.org/x/net/bpf/instructions.go
create mode 100644 vendor/golang.org/x/net/bpf/setter.go
create mode 100644 vendor/golang.org/x/net/bpf/vm.go
create mode 100644 vendor/golang.org/x/net/bpf/vm_instructions.go
create mode 100644 vendor/golang.org/x/net/html/atom/atom.go
create mode 100644 vendor/golang.org/x/net/html/atom/table.go
create mode 100644 vendor/golang.org/x/net/html/charset/charset.go
create mode 100644 vendor/golang.org/x/net/html/const.go
create mode 100644 vendor/golang.org/x/net/html/doc.go
create mode 100644 vendor/golang.org/x/net/html/doctype.go
create mode 100644 vendor/golang.org/x/net/html/entity.go
create mode 100644 vendor/golang.org/x/net/html/escape.go
create mode 100644 vendor/golang.org/x/net/html/foreign.go
create mode 100644 vendor/golang.org/x/net/html/iter.go
create mode 100644 vendor/golang.org/x/net/html/node.go
create mode 100644 vendor/golang.org/x/net/html/nodetype_string.go
create mode 100644 vendor/golang.org/x/net/html/parse.go
create mode 100644 vendor/golang.org/x/net/html/render.go
create mode 100644 vendor/golang.org/x/net/html/token.go
create mode 100644 vendor/golang.org/x/net/http/httpguts/guts.go
create mode 100644 vendor/golang.org/x/net/http/httpguts/httplex.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/encode.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/hpack.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/huffman.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/static_table.go
create mode 100644 vendor/golang.org/x/net/http2/hpack/tables.go
create mode 100644 vendor/golang.org/x/net/idna/idna.go
create mode 100644 vendor/golang.org/x/net/idna/punycode.go
create mode 100644 vendor/golang.org/x/net/idna/tables15.0.0.go
create mode 100644 vendor/golang.org/x/net/idna/tables17.0.0.go
create mode 100644 vendor/golang.org/x/net/idna/trie.go
create mode 100644 vendor/golang.org/x/net/idna/trieval.go
create mode 100644 vendor/golang.org/x/net/internal/iana/const.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_bsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_linux_32bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_solaris_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/cmsghdr_zos_s390x.go
create mode 100644 vendor/golang.org/x/net/internal/socket/complete_dontwait.go
create mode 100644 vendor/golang.org/x/net/internal/socket/complete_nodontwait.go
create mode 100644 vendor/golang.org/x/net/internal/socket/empty.s
create mode 100644 vendor/golang.org/x/net/internal/socket/error_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/error_windows.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_32bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/iovec_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/mmsghdr_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_bsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/msghdr_zos_s390x.go
create mode 100644 vendor/golang.org/x/net/internal/socket/norace.go
create mode 100644 vendor/golang.org/x/net/internal/socket/race.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_msg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_nommsg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/rawconn_nomsg.go
create mode 100644 vendor/golang.org/x/net/internal/socket/socket.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_bsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_const_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_386.s
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_loong64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_riscv64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_linux_s390x.s
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_netbsd.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_posix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_stub.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_unix.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_windows.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_zos_s390x.go
create mode 100644 vendor/golang.org/x/net/internal/socket/sys_zos_s390x.s
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_aix_ppc64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_loong64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_riscv64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_386.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_mips64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_ppc64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_openbsd_riscv64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_solaris_amd64.go
create mode 100644 vendor/golang.org/x/net/internal/socket/zsys_zos_s390x.go
create mode 100644 vendor/golang.org/x/net/ipv4/batch.go
create mode 100644 vendor/golang.org/x/net/ipv4/control.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_pktinfo.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_unix.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_windows.go
create mode 100644 vendor/golang.org/x/net/ipv4/control_zos.go
create mode 100644 vendor/golang.org/x/net/ipv4/dgramopt.go
create mode 100644 vendor/golang.org/x/net/ipv4/doc.go
create mode 100644 vendor/golang.org/x/net/ipv4/endpoint.go
create mode 100644 vendor/golang.org/x/net/ipv4/genericopt.go
create mode 100644 vendor/golang.org/x/net/ipv4/header.go
create mode 100644 vendor/golang.org/x/net/ipv4/helper.go
create mode 100644 vendor/golang.org/x/net/ipv4/iana.go
create mode 100644 vendor/golang.org/x/net/ipv4/icmp.go
create mode 100644 vendor/golang.org/x/net/ipv4/icmp_linux.go
create mode 100644 vendor/golang.org/x/net/ipv4/icmp_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/packet.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload_cmsg.go
create mode 100644 vendor/golang.org/x/net/ipv4/payload_nocmsg.go
create mode 100644 vendor/golang.org/x/net/ipv4/sockopt.go
create mode 100644 vendor/golang.org/x/net/ipv4/sockopt_posix.go
create mode 100644 vendor/golang.org/x/net/ipv4/sockopt_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_aix.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreq.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreqn.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_asmreqn_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_bpf.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_bpf_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_freebsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_linux.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_ssmreq.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_ssmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_stub.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_windows.go
create mode 100644 vendor/golang.org/x/net/ipv4/sys_zos.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_aix_ppc64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_386.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_arm.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_386.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_loong64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_riscv64.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_netbsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_openbsd.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv4/zsys_zos_s390x.go
create mode 100644 vendor/golang.org/x/net/ipv6/batch.go
create mode 100644 vendor/golang.org/x/net/ipv6/control.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_rfc2292_unix.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_rfc3542_unix.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_unix.go
create mode 100644 vendor/golang.org/x/net/ipv6/control_windows.go
create mode 100644 vendor/golang.org/x/net/ipv6/dgramopt.go
create mode 100644 vendor/golang.org/x/net/ipv6/doc.go
create mode 100644 vendor/golang.org/x/net/ipv6/endpoint.go
create mode 100644 vendor/golang.org/x/net/ipv6/genericopt.go
create mode 100644 vendor/golang.org/x/net/ipv6/header.go
create mode 100644 vendor/golang.org/x/net/ipv6/helper.go
create mode 100644 vendor/golang.org/x/net/ipv6/iana.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_linux.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_windows.go
create mode 100644 vendor/golang.org/x/net/ipv6/icmp_zos.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload_cmsg.go
create mode 100644 vendor/golang.org/x/net/ipv6/payload_nocmsg.go
create mode 100644 vendor/golang.org/x/net/ipv6/sockopt.go
create mode 100644 vendor/golang.org/x/net/ipv6/sockopt_posix.go
create mode 100644 vendor/golang.org/x/net/ipv6/sockopt_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_aix.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_asmreq.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_asmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_bpf.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_bpf_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_bsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_freebsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_linux.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_ssmreq.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_ssmreq_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_stub.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_windows.go
create mode 100644 vendor/golang.org/x/net/ipv6/sys_zos.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_aix_ppc64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_darwin.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_dragonfly.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_386.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_arm.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_386.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_amd64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_arm.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_arm64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_loong64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mips64le.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_mipsle.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_riscv64.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_linux_s390x.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_netbsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_openbsd.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_solaris.go
create mode 100644 vendor/golang.org/x/net/ipv6/zsys_zos_s390x.go
create mode 100644 vendor/golang.org/x/net/nettest/conntest.go
create mode 100644 vendor/golang.org/x/net/nettest/nettest.go
create mode 100644 vendor/golang.org/x/net/nettest/nettest_stub.go
create mode 100644 vendor/golang.org/x/net/nettest/nettest_unix.go
create mode 100644 vendor/golang.org/x/net/nettest/nettest_windows.go
create mode 100644 vendor/golang.org/x/net/publicsuffix/data/children
create mode 100644 vendor/golang.org/x/net/publicsuffix/data/nodes
create mode 100644 vendor/golang.org/x/net/publicsuffix/data/text
create mode 100644 vendor/golang.org/x/net/publicsuffix/list.go
create mode 100644 vendor/golang.org/x/net/publicsuffix/table.go
create mode 100644 vendor/golang.org/x/sys/LICENSE
create mode 100644 vendor/golang.org/x/sys/PATENTS
create mode 100644 vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s
create mode 100644 vendor/golang.org/x/sys/cpu/asm_darwin_arm64_gc.s
create mode 100644 vendor/golang.org/x/sys/cpu/asm_darwin_x86_gc.s
create mode 100644 vendor/golang.org/x/sys/cpu/byteorder.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_aix.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_arm64.s
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_darwin_arm64_other.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gc_x86.s
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_loong64.s
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mips64x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_mipsx.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_x86.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_ppc64x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_riscv64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_s390x.s
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_wasm.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_windows.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_windows_arm64.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_x86.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos.go
create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go
create mode 100644 vendor/golang.org/x/sys/cpu/endian_big.go
create mode 100644 vendor/golang.org/x/sys/cpu/endian_little.go
create mode 100644 vendor/golang.org/x/sys/cpu/hwcap_linux.go
create mode 100644 vendor/golang.org/x/sys/cpu/parse.go
create mode 100644 vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go
create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv.go
create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go
create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go
create mode 100644 vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go
create mode 100644 vendor/golang.org/x/sys/cpu/syscall_darwin_arm64_gc.go
create mode 100644 vendor/golang.org/x/sys/cpu/syscall_darwin_x86_gc.go
create mode 100644 vendor/golang.org/x/sys/cpu/zcpu_windows.go
create mode 100644 vendor/golang.org/x/sys/unix/.gitignore
create mode 100644 vendor/golang.org/x/sys/unix/README.md
create mode 100644 vendor/golang.org/x/sys/unix/affinity_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/aliases.go
create mode 100644 vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_bsd_386.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_bsd_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_bsd_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_bsd_arm64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_386.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_arm64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_loong64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_s390x.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/asm_zos_s390x.s
create mode 100644 vendor/golang.org/x/sys/unix/auxv.go
create mode 100644 vendor/golang.org/x/sys/unix/auxv_unsupported.go
create mode 100644 vendor/golang.org/x/sys/unix/bluetooth_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/bpxsvc_zos.go
create mode 100644 vendor/golang.org/x/sys/unix/bpxsvc_zos.s
create mode 100644 vendor/golang.org/x/sys/unix/cap_freebsd.go
create mode 100644 vendor/golang.org/x/sys/unix/constants.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_aix_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_darwin.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_dragonfly.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_freebsd.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_netbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_openbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/dev_zos.go
create mode 100644 vendor/golang.org/x/sys/unix/dirent.go
create mode 100644 vendor/golang.org/x/sys/unix/endian_big.go
create mode 100644 vendor/golang.org/x/sys/unix/endian_little.go
create mode 100644 vendor/golang.org/x/sys/unix/env_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/fcntl.go
create mode 100644 vendor/golang.org/x/sys/unix/fcntl_darwin.go
create mode 100644 vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
create mode 100644 vendor/golang.org/x/sys/unix/fdset.go
create mode 100644 vendor/golang.org/x/sys/unix/gccgo.go
create mode 100644 vendor/golang.org/x/sys/unix/gccgo_c.c
create mode 100644 vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ifreq_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/ioctl_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/ioctl_signed.go
create mode 100644 vendor/golang.org/x/sys/unix/ioctl_unsigned.go
create mode 100644 vendor/golang.org/x/sys/unix/ioctl_zos.go
create mode 100644 vendor/golang.org/x/sys/unix/mkall.sh
create mode 100644 vendor/golang.org/x/sys/unix/mkerrors.sh
create mode 100644 vendor/golang.org/x/sys/unix/mmap_nomremap.go
create mode 100644 vendor/golang.org/x/sys/unix/mremap.go
create mode 100644 vendor/golang.org/x/sys/unix/pagesize_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/pledge_openbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/ptrace_darwin.go
create mode 100644 vendor/golang.org/x/sys/unix/ptrace_ios.go
create mode 100644 vendor/golang.org/x/sys/unix/race.go
create mode 100644 vendor/golang.org/x/sys/unix/race0.go
create mode 100644 vendor/golang.org/x/sys/unix/readdirent_getdents.go
create mode 100644 vendor/golang.org/x/sys/unix/readdirent_getdirentries.go
create mode 100644 vendor/golang.org/x/sys/unix/readv_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_dragonfly.go
create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_unix_other.go
create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_zos.go
create mode 100644 vendor/golang.org/x/sys/unix/symaddr_zos_s390x.s
create mode 100644 vendor/golang.org/x/sys/unix/syscall.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_aix.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_aix_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_bsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_hurd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_hurd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_illumos.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_alarm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_amd64_gc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_libc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_gc.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go
create mode 100644 vendor/golang.org/x/sys/unix/syscall_zos_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/sysvshm_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/sysvshm_unix.go
create mode 100644 vendor/golang.org/x/sys/unix/sysvshm_unix_other.go
create mode 100644 vendor/golang.org/x/sys/unix/timestruct.go
create mode 100644 vendor/golang.org/x/sys/unix/unveil_openbsd.go
create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go
create mode 100644 vendor/golang.org/x/sys/unix/xattr_bsd.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_aix_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_openbsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zptrace_armnn_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zptrace_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zptrace_mipsnn_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zptrace_mipsnnle_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zptrace_x86_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zsymaddr_zos_s390x.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_illumos_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_zos_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_aix_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_aix_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_freebsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_ppc64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_riscv64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_solaris_amd64.go
create mode 100644 vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go
create mode 100644 vendor/golang.org/x/sys/windows/aliases.go
create mode 100644 vendor/golang.org/x/sys/windows/dll_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/env_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/eventlog.go
create mode 100644 vendor/golang.org/x/sys/windows/exec_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/memory_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/mkerrors.bash
create mode 100644 vendor/golang.org/x/sys/windows/mkknownfolderids.bash
create mode 100644 vendor/golang.org/x/sys/windows/mksyscall.go
create mode 100644 vendor/golang.org/x/sys/windows/race.go
create mode 100644 vendor/golang.org/x/sys/windows/race0.go
create mode 100644 vendor/golang.org/x/sys/windows/security_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/service.go
create mode 100644 vendor/golang.org/x/sys/windows/setupapi_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/str.go
create mode 100644 vendor/golang.org/x/sys/windows/syscall.go
create mode 100644 vendor/golang.org/x/sys/windows/syscall_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows_386.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows_amd64.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows_arm.go
create mode 100644 vendor/golang.org/x/sys/windows/types_windows_arm64.go
create mode 100644 vendor/golang.org/x/sys/windows/zerrors_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/zknownfolderids_windows.go
create mode 100644 vendor/golang.org/x/sys/windows/zsyscall_windows.go
create mode 100644 vendor/golang.org/x/text/LICENSE
create mode 100644 vendor/golang.org/x/text/PATENTS
create mode 100644 vendor/golang.org/x/text/encoding/charmap/charmap.go
create mode 100644 vendor/golang.org/x/text/encoding/charmap/tables.go
create mode 100644 vendor/golang.org/x/text/encoding/encoding.go
create mode 100644 vendor/golang.org/x/text/encoding/htmlindex/htmlindex.go
create mode 100644 vendor/golang.org/x/text/encoding/htmlindex/map.go
create mode 100644 vendor/golang.org/x/text/encoding/htmlindex/tables.go
create mode 100644 vendor/golang.org/x/text/encoding/ianaindex/ascii.go
create mode 100644 vendor/golang.org/x/text/encoding/ianaindex/ianaindex.go
create mode 100644 vendor/golang.org/x/text/encoding/ianaindex/tables.go
create mode 100644 vendor/golang.org/x/text/encoding/internal/identifier/identifier.go
create mode 100644 vendor/golang.org/x/text/encoding/internal/identifier/mib.go
create mode 100644 vendor/golang.org/x/text/encoding/internal/internal.go
create mode 100644 vendor/golang.org/x/text/encoding/japanese/all.go
create mode 100644 vendor/golang.org/x/text/encoding/japanese/eucjp.go
create mode 100644 vendor/golang.org/x/text/encoding/japanese/iso2022jp.go
create mode 100644 vendor/golang.org/x/text/encoding/japanese/shiftjis.go
create mode 100644 vendor/golang.org/x/text/encoding/japanese/tables.go
create mode 100644 vendor/golang.org/x/text/encoding/korean/euckr.go
create mode 100644 vendor/golang.org/x/text/encoding/korean/tables.go
create mode 100644 vendor/golang.org/x/text/encoding/simplifiedchinese/all.go
create mode 100644 vendor/golang.org/x/text/encoding/simplifiedchinese/gbk.go
create mode 100644 vendor/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go
create mode 100644 vendor/golang.org/x/text/encoding/simplifiedchinese/tables.go
create mode 100644 vendor/golang.org/x/text/encoding/traditionalchinese/big5.go
create mode 100644 vendor/golang.org/x/text/encoding/traditionalchinese/tables.go
create mode 100644 vendor/golang.org/x/text/encoding/unicode/override.go
create mode 100644 vendor/golang.org/x/text/encoding/unicode/unicode.go
create mode 100644 vendor/golang.org/x/text/internal/language/common.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/compact.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/language.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/parents.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/tables.go
create mode 100644 vendor/golang.org/x/text/internal/language/compact/tags.go
create mode 100644 vendor/golang.org/x/text/internal/language/compose.go
create mode 100644 vendor/golang.org/x/text/internal/language/coverage.go
create mode 100644 vendor/golang.org/x/text/internal/language/language.go
create mode 100644 vendor/golang.org/x/text/internal/language/lookup.go
create mode 100644 vendor/golang.org/x/text/internal/language/match.go
create mode 100644 vendor/golang.org/x/text/internal/language/parse.go
create mode 100644 vendor/golang.org/x/text/internal/language/tables.go
create mode 100644 vendor/golang.org/x/text/internal/language/tags.go
create mode 100644 vendor/golang.org/x/text/internal/tag/tag.go
create mode 100644 vendor/golang.org/x/text/internal/utf8internal/utf8internal.go
create mode 100644 vendor/golang.org/x/text/language/coverage.go
create mode 100644 vendor/golang.org/x/text/language/doc.go
create mode 100644 vendor/golang.org/x/text/language/language.go
create mode 100644 vendor/golang.org/x/text/language/match.go
create mode 100644 vendor/golang.org/x/text/language/parse.go
create mode 100644 vendor/golang.org/x/text/language/tables.go
create mode 100644 vendor/golang.org/x/text/language/tags.go
create mode 100644 vendor/golang.org/x/text/runes/cond.go
create mode 100644 vendor/golang.org/x/text/runes/runes.go
create mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule.go
create mode 100644 vendor/golang.org/x/text/transform/transform.go
create mode 100644 vendor/golang.org/x/text/unicode/bidi/bidi.go
create mode 100644 vendor/golang.org/x/text/unicode/bidi/bracket.go
create mode 100644 vendor/golang.org/x/text/unicode/bidi/core.go
create mode 100644 vendor/golang.org/x/text/unicode/bidi/prop.go
create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go
create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables17.0.0.go
create mode 100644 vendor/golang.org/x/text/unicode/bidi/trieval.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/composition.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/forminfo.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/input.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/iter.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/normalize.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/readwriter.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/tables15.0.0.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/tables17.0.0.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/transform.go
create mode 100644 vendor/golang.org/x/text/unicode/norm/trie.go
create mode 100644 vendor/modules.txt
diff --git a/vendor/github.com/andybalholm/brotli/.gitignore b/vendor/github.com/andybalholm/brotli/.gitignore
new file mode 100644
index 00000000..7fd17523
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/.gitignore
@@ -0,0 +1,2 @@
+cpu.out
+brotli.test
diff --git a/vendor/github.com/andybalholm/brotli/LICENSE b/vendor/github.com/andybalholm/brotli/LICENSE
new file mode 100644
index 00000000..33b7cdd2
--- /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 00000000..3494ec47
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/README.md
@@ -0,0 +1,19 @@
+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.
+
+## Roadmap
+
+I have been working on new compression algorithms (not translated from C)
+in the matchfinder package.
+You can use them with the NewWriterV2 function.
+Currently they give better results than the old implementation
+(at least for compressing my test file, Newton’s *Opticks*)
+on levels 0 to 9.
+
+The new APIs are currently considered experimental,
+and are not covered by any SemVer compatibility guarantees.
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 00000000..008c054d
--- /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 00000000..21629c1c
--- /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 00000000..0005fc15
--- /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 00000000..fba8687c
--- /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/bitwriter.go b/vendor/github.com/andybalholm/brotli/bitwriter.go
new file mode 100644
index 00000000..dfc60360
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/bitwriter.go
@@ -0,0 +1,56 @@
+package brotli
+
+/* 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. */
+
+type bitWriter struct {
+ dst []byte
+
+ // Data waiting to be written is the low nbits of bits.
+ bits uint64
+ nbits uint
+}
+
+func (w *bitWriter) writeBits(nb uint, b uint64) {
+ w.bits |= b << w.nbits
+ w.nbits += nb
+ if w.nbits >= 32 {
+ bits := w.bits
+ w.bits >>= 32
+ w.nbits -= 32
+ w.dst = append(w.dst,
+ byte(bits),
+ byte(bits>>8),
+ byte(bits>>16),
+ byte(bits>>24),
+ )
+ }
+}
+
+func (w *bitWriter) writeSingleBit(bit bool) {
+ if bit {
+ w.writeBits(1, 1)
+ } else {
+ w.writeBits(1, 0)
+ }
+}
+
+func (w *bitWriter) jumpToByteBoundary() {
+ dst := w.dst
+ for w.nbits != 0 {
+ dst = append(dst, byte(w.bits))
+ w.bits >>= 8
+ if w.nbits > 8 { // Avoid underflow
+ w.nbits -= 8
+ } else {
+ w.nbits = 0
+ }
+ }
+ w.bits = 0
+ w.dst = dst
+}
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 00000000..978a1314
--- /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 00000000..9dec13e4
--- /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 00000000..953530d5
--- /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 00000000..1c895cf3
--- /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 00000000..d098d320
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/brotli_bit_stream.go
@@ -0,0 +1,1435 @@
+package brotli
+
+import (
+ "slices"
+ "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 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
+ }
+
+ chooseBitDepths(histogram[:length], depth[:length], 14)
+
+ 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
+ }
+ }
+ }
+}
+
+type symbolAndCount struct {
+ symbol uint32
+ count uint32
+}
+
+func chooseBitDepths(histogram []uint32, depth []byte, maxBits int) {
+ totalCodeSpace := 1 << maxBits
+ symbols := make([]symbolAndCount, 0, 704 /* static capacity so that it will be stack allocated */)
+ var totalCount uint32 = 0
+ for i, n := range histogram {
+ if n != 0 {
+ symbols = append(symbols, symbolAndCount{
+ symbol: uint32(i),
+ count: n,
+ })
+ totalCount += n
+ }
+ }
+ slices.SortFunc(symbols, func(a, b symbolAndCount) int {
+ return int(b.count) - int(a.count)
+ })
+
+ // boundaries contains indexes into symbols such that (for example)
+ // boundaries[8] is the index of the first 8-bit symbol.
+ boundaries := make([]int, maxBits+1, 20 /* static capacity for stack allocation */)
+
+ codeSpaceUsed := 0
+
+ // Assign initial boundaries conservatively, making sure no symbol uses more
+ // than its share of code space.
+ totalRatio := float64(totalCount) / float64(totalCodeSpace)
+ currentDepth := 1
+ for i, symbol := range symbols {
+ for currentDepth < maxBits && float64(symbol.count)/float64(int(1)<<(maxBits-currentDepth)) < totalRatio {
+ currentDepth++
+ boundaries[currentDepth] = i
+ }
+ codeSpaceUsed += 1 << (maxBits - currentDepth)
+ }
+ for i := currentDepth + 1; i <= maxBits; i++ {
+ boundaries[i] = len(symbols)
+ }
+
+ // Move the boundaries till the code space is filled.
+ for codeSpaceUsed < totalCodeSpace {
+ available := totalCodeSpace - codeSpaceUsed
+ // Find the most efficient boundary to move, based on the ratio of how
+ // many times the symbol was used to how much code space will be consumed.
+ bestRatio := 0.0
+ bestBoundary := 0
+ for i := 2; i <= maxBits; i++ {
+ cost := 1 << (maxBits - i) // code space that would be used by moving this boundary
+ if cost > available {
+ continue
+ }
+ if boundaries[i] == len(symbols) {
+ continue
+ }
+ if i < maxBits && boundaries[i] == boundaries[i+1] {
+ continue
+ }
+ ratio := float64(symbols[boundaries[i]].count) / float64(cost)
+ if ratio > bestRatio {
+ bestRatio = ratio
+ bestBoundary = i
+ }
+ }
+ boundaries[bestBoundary]++
+ codeSpaceUsed += 1 << (maxBits - bestBoundary)
+ }
+
+ for i := range depth {
+ depth[i] = 0
+ }
+ for i := 1; i < maxBits; i++ {
+ for j := boundaries[i]; j < boundaries[i+1]; j++ {
+ depth[symbols[j].symbol] = byte(i)
+ }
+ }
+ for j := boundaries[maxBits]; j < len(symbols); j++ {
+ depth[symbols[j].symbol] = byte(maxBits)
+ }
+}
+
+func buildAndStoreHuffmanTreeFastBW(histogram []uint32, histogram_total uint, max_bits uint, depth []byte, bits []uint16, bw *bitWriter) {
+ 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 {
+ bw.writeBits(4, 1)
+ bw.writeBits(max_bits, uint64(symbols[0]))
+ depth[symbols[0]] = 0
+ bits[symbols[0]] = 0
+ return
+ }
+
+ chooseBitDepths(histogram[:length], depth[:length], 14)
+
+ convertBitDepthsToSymbols(depth, length, bits)
+ if count <= 4 {
+ var i uint
+
+ /* value of 1 indicates a simple Huffman code */
+ bw.writeBits(2, 1)
+
+ bw.writeBits(2, uint64(count)-1) /* 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 {
+ bw.writeBits(max_bits, uint64(symbols[0]))
+ bw.writeBits(max_bits, uint64(symbols[1]))
+ } else if count == 3 {
+ bw.writeBits(max_bits, uint64(symbols[0]))
+ bw.writeBits(max_bits, uint64(symbols[1]))
+ bw.writeBits(max_bits, uint64(symbols[2]))
+ } else {
+ bw.writeBits(max_bits, uint64(symbols[0]))
+ bw.writeBits(max_bits, uint64(symbols[1]))
+ bw.writeBits(max_bits, uint64(symbols[2]))
+ bw.writeBits(max_bits, uint64(symbols[3]))
+
+ /* tree-select */
+ bw.writeSingleBit(depth[symbols[0]] == 1)
+ }
+ } else {
+ var previous_value byte = 8
+ var i uint
+
+ /* Complex Huffman Tree */
+ storeStaticCodeLengthCodeBW(bw)
+
+ /* 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 {
+ bw.writeBits(uint(kZeroRepsDepth[reps]), kZeroRepsBits[reps])
+ } else {
+ if previous_value != value {
+ bw.writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]))
+ reps--
+ }
+
+ if reps < 3 {
+ for reps != 0 {
+ reps--
+ bw.writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]))
+ }
+ } else {
+ reps -= 3
+ bw.writeBits(uint(kNonZeroRepsDepth[reps]), kNonZeroRepsBits[reps])
+ }
+
+ 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 00000000..df8a3282
--- /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 00000000..45b569bb
--- /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 00000000..1aaa86e6
--- /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 00000000..6ba66f31
--- /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 00000000..b1662a55
--- /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 00000000..c9bd0577
--- /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 00000000..c5c663a5
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go
@@ -0,0 +1,775 @@
+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 storeMetaBlockHeaderBW(len uint, is_uncompressed bool, bw *bitWriter) {
+ var nibbles uint = 6
+
+ /* ISLAST */
+ bw.writeBits(1, 0)
+
+ if len <= 1<<16 {
+ nibbles = 4
+ } else if len <= 1<<20 {
+ nibbles = 5
+ } else if len > 1<<24 {
+ panic("metablock too long")
+ }
+
+ bw.writeBits(2, uint64(nibbles)-4)
+ bw.writeBits(nibbles*4, uint64(len)-1)
+
+ /* ISUNCOMPRESSED */
+ bw.writeSingleBit(is_uncompressed)
+}
+
+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 00000000..a880dff7
--- /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 00000000..884ff8a2
--- /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 00000000..9d9513b7
--- /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.go b/vendor/github.com/andybalholm/brotli/encoder.go
new file mode 100644
index 00000000..cd541b35
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/encoder.go
@@ -0,0 +1,177 @@
+package brotli
+
+import "github.com/andybalholm/brotli/matchfinder"
+
+// An Encoder implements the matchfinder.Encoder interface, writing in Brotli format.
+type Encoder struct {
+ wroteHeader bool
+ bw bitWriter
+ distCache []distanceCode
+}
+
+func (e *Encoder) Reset() {
+ e.wroteHeader = false
+ e.bw = bitWriter{}
+}
+
+func (e *Encoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {
+ e.bw.dst = dst
+ if !e.wroteHeader {
+ e.bw.writeBits(4, 15)
+ e.wroteHeader = true
+ }
+
+ if len(src) == 0 {
+ if lastBlock {
+ e.bw.writeBits(2, 3) // islast + isempty
+ e.bw.jumpToByteBoundary()
+ return e.bw.dst
+ }
+ return dst
+ }
+
+ var literalHisto [256]uint32
+ var commandHisto [704]uint32
+ var distanceHisto [64]uint32
+ literalCount := 0
+ commandCount := 0
+ distanceCount := 0
+
+ if len(e.distCache) < len(matches) {
+ e.distCache = make([]distanceCode, len(matches))
+ }
+
+ // first pass: build the histograms
+ pos := 0
+
+ // d is the ring buffer of the last 4 distances.
+ d := [4]int{-10, -10, -10, -10}
+ for i, m := range matches {
+ if m.Unmatched > 0 {
+ for _, c := range src[pos : pos+m.Unmatched] {
+ literalHisto[c]++
+ }
+ literalCount += m.Unmatched
+ }
+
+ insertCode := getInsertLengthCode(uint(m.Unmatched))
+ copyCode := getCopyLengthCode(uint(m.Length))
+ if m.Length == 0 {
+ // If the stream ends with unmatched bytes, we need a dummy copy length.
+ copyCode = 2
+ }
+ command := combineLengthCodes(insertCode, copyCode, i > 0 && m.Distance == matches[i-1].Distance)
+ commandHisto[command]++
+ commandCount++
+
+ if command >= 128 && m.Length != 0 {
+ var distCode distanceCode
+ switch m.Distance {
+ case d[3]:
+ distCode.code = 0
+ case d[2]:
+ distCode.code = 1
+ case d[1]:
+ distCode.code = 2
+ case d[0]:
+ distCode.code = 3
+ case d[3] - 1:
+ distCode.code = 4
+ case d[3] + 1:
+ distCode.code = 5
+ case d[3] - 2:
+ distCode.code = 6
+ case d[3] + 2:
+ distCode.code = 7
+ case d[3] - 3:
+ distCode.code = 8
+ case d[3] + 3:
+ distCode.code = 9
+
+ // In my testing, codes 10–15 actually reduced the compression ratio.
+
+ default:
+ distCode = getDistanceCode(m.Distance)
+ }
+ e.distCache[i] = distCode
+ distanceHisto[distCode.code]++
+ distanceCount++
+ if distCode.code != 0 {
+ d[0], d[1], d[2], d[3] = d[1], d[2], d[3], m.Distance
+ }
+ }
+
+ pos += m.Unmatched + m.Length
+ }
+
+ storeMetaBlockHeaderBW(uint(len(src)), false, &e.bw)
+ e.bw.writeBits(13, 0)
+
+ var literalDepths [256]byte
+ var literalBits [256]uint16
+ buildAndStoreHuffmanTreeFastBW(literalHisto[:], uint(literalCount), 8, literalDepths[:], literalBits[:], &e.bw)
+
+ var commandDepths [704]byte
+ var commandBits [704]uint16
+ buildAndStoreHuffmanTreeFastBW(commandHisto[:], uint(commandCount), 10, commandDepths[:], commandBits[:], &e.bw)
+
+ var distanceDepths [64]byte
+ var distanceBits [64]uint16
+ buildAndStoreHuffmanTreeFastBW(distanceHisto[:], uint(distanceCount), 6, distanceDepths[:], distanceBits[:], &e.bw)
+
+ pos = 0
+ for i, m := range matches {
+ insertCode := getInsertLengthCode(uint(m.Unmatched))
+ copyCode := getCopyLengthCode(uint(m.Length))
+ if m.Length == 0 {
+ // If the stream ends with unmatched bytes, we need a dummy copy length.
+ copyCode = 2
+ }
+ command := combineLengthCodes(insertCode, copyCode, i > 0 && m.Distance == matches[i-1].Distance)
+ e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+ if kInsExtra[insertCode] > 0 {
+ e.bw.writeBits(uint(kInsExtra[insertCode]), uint64(m.Unmatched)-uint64(kInsBase[insertCode]))
+ }
+ if kCopyExtra[copyCode] > 0 {
+ e.bw.writeBits(uint(kCopyExtra[copyCode]), uint64(m.Length)-uint64(kCopyBase[copyCode]))
+ }
+
+ if m.Unmatched > 0 {
+ for _, c := range src[pos : pos+m.Unmatched] {
+ e.bw.writeBits(uint(literalDepths[c]), uint64(literalBits[c]))
+ }
+ }
+
+ if command >= 128 && m.Length != 0 {
+ distCode := e.distCache[i]
+ e.bw.writeBits(uint(distanceDepths[distCode.code]), uint64(distanceBits[distCode.code]))
+ if distCode.nExtra > 0 {
+ e.bw.writeBits(distCode.nExtra, distCode.extraBits)
+ }
+ }
+
+ pos += m.Unmatched + m.Length
+ }
+
+ if lastBlock {
+ e.bw.writeBits(2, 3) // islast + isempty
+ e.bw.jumpToByteBoundary()
+ }
+ return e.bw.dst
+}
+
+type distanceCode struct {
+ code int
+ nExtra uint
+ extraBits uint64
+}
+
+func getDistanceCode(distance int) distanceCode {
+ d := distance + 3
+ nbits := log2FloorNonZero(uint(d)) - 1
+ prefix := (d >> nbits) & 1
+ offset := (2 + prefix) << nbits
+ distcode := int(2*(nbits-1)) + prefix + 16
+ extra := d - offset
+ return distanceCode{distcode, uint(nbits), uint64(extra)}
+}
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 00000000..55c051c6
--- /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/encoder_fast.go b/vendor/github.com/andybalholm/brotli/encoder_fast.go
new file mode 100644
index 00000000..36a41737
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/encoder_fast.go
@@ -0,0 +1,197 @@
+package brotli
+
+import (
+ "math"
+
+ "github.com/andybalholm/brotli/matchfinder"
+)
+
+func gaussianProbability(x, mean, stdDev float64) float64 {
+ return math.Exp(-(x-mean)*(x-mean)/(2*stdDev*stdDev)) / math.Sqrt(2*math.Pi*stdDev*stdDev)
+}
+
+// A FastEncoder implements the matchfinder.Encoder interface, writing in Brotli
+// format. It uses a simplified encoding (like level 0 in the reference
+// implementation) to save time.
+type FastEncoder struct {
+ wroteHeader bool
+ bw bitWriter
+ commandHisto [704]uint32
+ distanceHisto [64]uint32
+}
+
+func (e *FastEncoder) Reset() {
+ e.wroteHeader = false
+ e.bw = bitWriter{}
+}
+
+func (e *FastEncoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {
+ e.bw.dst = dst
+ if !e.wroteHeader {
+ e.bw.writeBits(4, 15)
+ e.wroteHeader = true
+
+ // Fill the histograms with default statistics.
+
+ // For the command codes we're using for insert lengths (insert + 2-byte copy),
+ // fill the histogram with a Zipf-squared distribution.
+ for i := range 24 {
+ e.commandHisto[combineLengthCodes(uint16(i), 0, false)] = uint32(2000 / (i + 1) / (i + 1))
+ }
+
+ // For the command codes we're using for copy lengths (0 insert + copy
+ // (length - 2), with repeat distance),
+ // fill the histogram with Zipf distribution starting at code 1 (match length 5),
+ // but a smaller frequency for code 0.
+ e.commandHisto[combineLengthCodes(0, 0, true)] = 50
+ for i := 1; i < 24; i++ {
+ e.commandHisto[combineLengthCodes(0, uint16(i), i < 16)] = uint32(800 / i)
+ }
+
+ // Fill in the combined codes for short insert and copy lengths.
+ for insertCode := range 6 {
+ copyCode := 2
+ e.commandHisto[128+insertCode<<3+copyCode] = uint32(100 / (insertCode + 1) / (insertCode + 1) / copyCode)
+ for copyCode := 3; copyCode < 8; copyCode++ {
+ e.commandHisto[128+insertCode<<3+copyCode] = uint32(343 / (insertCode + 1) / (insertCode + 1) / copyCode)
+ }
+ }
+
+ // Fill e.distanceHisto with a normal distribution.
+ e.distanceHisto[0] = 100
+ for i := 16; i < 64; i++ {
+ e.distanceHisto[i] = max(uint32(gaussianProbability(float64(i), 32, 8)*10000), 1)
+ }
+ }
+
+ if len(src) == 0 {
+ if lastBlock {
+ e.bw.writeBits(2, 3) // islast + isempty
+ e.bw.jumpToByteBoundary()
+ return e.bw.dst
+ }
+ return dst
+ }
+
+ var literalHisto [256]uint32
+ for _, c := range src {
+ literalHisto[c]++
+ }
+
+ storeMetaBlockHeaderBW(uint(len(src)), false, &e.bw)
+ e.bw.writeBits(13, 0)
+
+ var literalDepths [256]byte
+ var literalBits [256]uint16
+ buildAndStoreHuffmanTreeFastBW(literalHisto[:], uint(len(src)), 8, literalDepths[:], literalBits[:], &e.bw)
+
+ var commandDepths [704]byte
+ var commandBits [704]uint16
+ commandCount := 0
+ for _, n := range e.commandHisto {
+ commandCount += int(n)
+ }
+ buildAndStoreHuffmanTreeFastBW(e.commandHisto[:], uint(commandCount), 10, commandDepths[:], commandBits[:], &e.bw)
+
+ var distanceDepths [64]byte
+ var distanceBits [64]uint16
+ distanceCount := 0
+ for _, n := range e.distanceHisto {
+ distanceCount += int(n)
+ }
+ buildAndStoreHuffmanTreeFastBW(e.distanceHisto[:], uint(distanceCount), 6, distanceDepths[:], distanceBits[:], &e.bw)
+
+ // Reset the statistics, starting with a count of 1 for each symbol we might use.
+ for i := range 24 {
+ e.commandHisto[combineLengthCodes(uint16(i), 0, false)] = 1
+ }
+ for i := range 24 {
+ e.commandHisto[combineLengthCodes(0, uint16(i), i < 16)] = 1
+ }
+ for insertCode := range 6 {
+ for copyCode := 2; copyCode < 8; copyCode++ {
+ e.commandHisto[128+insertCode<<3+copyCode] = 1
+ }
+ }
+ e.distanceHisto[0] = 1
+ for i := 16; i < 64; i++ {
+ e.distanceHisto[i] = 1
+ }
+
+ pos := 0
+ for i, m := range matches {
+ lengthFinished := false
+ // Write a command with the appropriate insert length, and a copy length of 2.
+ if m.Unmatched < 6 {
+ var command int
+ if m.Length < 10 && m.Length != 0 {
+ // We can use a combined insert/copy code with no extra bits.
+ command = m.Unmatched<<3 + m.Length - 2 + 128
+ lengthFinished = true
+ } else {
+ command = m.Unmatched<<3 + 128
+ }
+ e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+ e.commandHisto[command]++
+ } else {
+ insertCode := getInsertLengthCode(uint(m.Unmatched))
+ command := combineLengthCodes(insertCode, 0, false)
+ e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+ e.bw.writeBits(uint(kInsExtra[insertCode]), uint64(m.Unmatched)-uint64(kInsBase[insertCode]))
+ e.commandHisto[command]++
+ }
+
+ // Write the literals, if any.
+ if m.Unmatched > 0 {
+ for _, c := range src[pos : pos+m.Unmatched] {
+ e.bw.writeBits(uint(literalDepths[c]), uint64(literalBits[c]))
+ }
+ }
+
+ if m.Length != 0 {
+ // Write the distance code.
+ var distCode distanceCode
+ if i == 0 || m.Distance != matches[i-1].Distance {
+ distCode = getDistanceCode(m.Distance)
+ }
+ e.bw.writeBits(uint(distanceDepths[distCode.code]), uint64(distanceBits[distCode.code]))
+ if distCode.nExtra > 0 {
+ e.bw.writeBits(distCode.nExtra, distCode.extraBits)
+ }
+ e.distanceHisto[distCode.code]++
+
+ // Write a command for the remainder of the match (after the first two bytes
+ // from before), using the previous distance.
+ switch {
+ case lengthFinished:
+ // We don't need to finish the length.
+ case m.Length < 12:
+ command := m.Length - 4
+ e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+ e.commandHisto[command]++
+ case m.Length < 72:
+ copyCode := getCopyLengthCode(uint(m.Length - 2))
+ command := combineLengthCodes(0, copyCode, true)
+ e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+ e.bw.writeBits(uint(kCopyExtra[copyCode]), uint64(m.Length-2)-uint64(kCopyBase[copyCode]))
+ e.commandHisto[command]++
+ default:
+ copyCode := getCopyLengthCode(uint(m.Length - 2))
+ command := combineLengthCodes(0, copyCode, false)
+ e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+ e.bw.writeBits(uint(kCopyExtra[copyCode]), uint64(m.Length-2)-uint64(kCopyBase[copyCode]))
+ e.bw.writeBits(uint(distanceDepths[0]), uint64(distanceBits[0]))
+ e.commandHisto[command]++
+ e.distanceHisto[0]++
+ }
+ }
+
+ pos += m.Unmatched + m.Length
+ }
+
+ if lastBlock {
+ e.bw.writeBits(2, 3) // islast + isempty
+ e.bw.jumpToByteBoundary()
+ }
+ return e.bw.dst
+}
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 00000000..3f469a3d
--- /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 00000000..294aff4f
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/entropy_encode_static.go
@@ -0,0 +1,4399 @@
+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)
+}
+
+func storeStaticCodeLengthCodeBW(bw *bitWriter) {
+ bw.writeBits(32, 0x55555554)
+ bw.writeBits(8, 0xFF)
+}
+
+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 00000000..9d6607f7
--- /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 00000000..b46f88e8
--- /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", "arm64":
+ // 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/flate/LICENSE b/vendor/github.com/andybalholm/brotli/flate/LICENSE
new file mode 100644
index 00000000..6a66aea5
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/flate/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/github.com/andybalholm/brotli/flate/README.md b/vendor/github.com/andybalholm/brotli/flate/README.md
new file mode 100644
index 00000000..0603ba1f
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/flate/README.md
@@ -0,0 +1,2 @@
+This package is a flate/gzip compressor that reuses the matchfinder package that I’ve been developing for brotli.
+It is copied and adapted from the standard library compress/flate package.
diff --git a/vendor/github.com/andybalholm/brotli/flate/gzip.go b/vendor/github.com/andybalholm/brotli/flate/gzip.go
new file mode 100644
index 00000000..16c62871
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/flate/gzip.go
@@ -0,0 +1,65 @@
+package flate
+
+import (
+ "hash/crc32"
+ "time"
+
+ "github.com/andybalholm/brotli/matchfinder"
+)
+
+func NewGZIPEncoder() matchfinder.Encoder {
+ return &gzipEncoder{
+ f: NewEncoder(),
+ }
+}
+
+type gzipEncoder struct {
+ f matchfinder.Encoder
+ length uint32
+ crc uint32
+ wroteHeader bool
+}
+
+func (g *gzipEncoder) Reset() {
+ g.f.Reset()
+ g.length = 0
+ g.crc = 0
+ g.wroteHeader = false
+}
+
+func appendUint32(dst []byte, n uint32) []byte {
+ return append(dst,
+ byte(n),
+ byte(n>>8),
+ byte(n>>16),
+ byte(n>>24),
+ )
+}
+
+func (g *gzipEncoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {
+ if !g.wroteHeader {
+ dst = append(dst,
+ 0x1f, 0x8b, // magic number
+ 8, // CM = flate
+ 0, // FLG
+ )
+ dst = appendUint32(dst, uint32(time.Now().Unix()))
+ dst = append(dst,
+ 0, // XFL
+ 255, // OS (unspecified)
+ )
+ g.wroteHeader = true
+ }
+
+ dst = g.f.Encode(dst, src, matches, lastBlock)
+
+ g.length += uint32(len(src))
+ g.crc = crc32.Update(g.crc, crc32.IEEETable, src)
+
+ if lastBlock {
+ dst = appendUint32(dst, g.crc)
+ dst = appendUint32(dst, g.length)
+ }
+
+ return dst
+}
diff --git a/vendor/github.com/andybalholm/brotli/flate/huffman_bit_writer.go b/vendor/github.com/andybalholm/brotli/flate/huffman_bit_writer.go
new file mode 100644
index 00000000..c60dfd44
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/flate/huffman_bit_writer.go
@@ -0,0 +1,517 @@
+// 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 (
+ "github.com/andybalholm/brotli/matchfinder"
+)
+
+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
+
+ maxNumLit = 286
+ maxStoreBlockSize = 65535
+ baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5
+ baseMatchOffset = 1 // The smallest match offset
+)
+
+// The number of extra bits needed by length code X - LENGTH_CODES_START.
+var lengthExtraBits = []int8{
+ /* 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 = []int{
+ 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,
+}
+
+// offset code word extra bits.
+var offsetExtraBits = []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,
+}
+
+var offsetBase = []int{
+ 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,
+}
+
+// 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 {
+ dst []byte
+
+ // Data waiting to be written is the low nbits of bits.
+ bits uint64
+ nbits uint
+ codegenFreq [codegenCodeCount]int32
+ literalFreq []int32
+ offsetFreq []int32
+ codegen []uint8
+ literalEncoding *huffmanEncoder
+ offsetEncoding *huffmanEncoder
+ codegenEncoding *huffmanEncoder
+}
+
+func NewEncoder() matchfinder.Encoder {
+ return &huffmanBitWriter{
+ literalFreq: make([]int32, maxNumLit),
+ offsetFreq: make([]int32, offsetCodeCount),
+ codegen: make([]uint8, maxNumLit+offsetCodeCount+1),
+ literalEncoding: newHuffmanEncoder(maxNumLit),
+ codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+ offsetEncoding: newHuffmanEncoder(offsetCodeCount),
+ }
+}
+
+func (w *huffmanBitWriter) Reset() {
+ w.bits, w.nbits = 0, 0
+}
+
+func (w *huffmanBitWriter) flush() {
+ dst := w.dst
+ for w.nbits != 0 {
+ dst = append(dst, byte(w.bits))
+ w.bits >>= 8
+ if w.nbits > 8 { // Avoid underflow
+ w.nbits -= 8
+ } else {
+ w.nbits = 0
+ }
+ }
+ w.bits = 0
+ w.dst = dst
+}
+
+func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
+ w.bits |= uint64(b) << w.nbits
+ w.nbits += nb
+ if w.nbits >= 48 {
+ bits := w.bits
+ w.bits >>= 48
+ w.nbits -= 48
+ w.dst = append(w.dst,
+ byte(bits),
+ byte(bits>>8),
+ byte(bits>>16),
+ byte(bits>>24),
+ byte(bits>>32),
+ byte(bits>>40),
+ )
+ }
+}
+
+func (w *huffmanBitWriter) writeBytes(bytes []byte) {
+ if w.nbits&7 != 0 {
+ panic("writeBytes with unfinished bits")
+ }
+ for w.nbits != 0 {
+ w.dst = append(w.dst, byte(w.bits))
+ w.bits >>= 8
+ w.nbits -= 8
+ }
+ w.dst = append(w.dst, 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] = uint8(litEnc.codes[i].len)
+ }
+
+ cgnl = codegen[numLiterals : numLiterals+numOffsets]
+ for i := range cgnl {
+ cgnl[i] = uint8(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
+}
+
+// dynamicSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) {
+ numCodegens = len(w.codegenFreq)
+ for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+ numCodegens--
+ }
+ header := 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
+ size = header +
+ litEnc.bitLength(w.literalFreq) +
+ offEnc.bitLength(w.offsetFreq) +
+ extraBits
+
+ return size, numCodegens
+}
+
+// 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) {
+ w.bits |= uint64(c.code) << w.nbits
+ w.nbits += uint(c.len)
+ if w.nbits >= 48 {
+ bits := w.bits
+ w.bits >>= 48
+ w.nbits -= 48
+ w.dst = append(w.dst,
+ byte(bits),
+ byte(bits>>8),
+ byte(bits>>16),
+ byte(bits>>24),
+ byte(bits>>32),
+ byte(bits>>40),
+ )
+ }
+}
+
+// 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) {
+ 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 int = int(w.codegen[i])
+ i++
+ if codeWord == badCode {
+ break
+ }
+ w.writeCode(w.codegenEncoding.codes[uint32(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++
+ }
+ }
+}
+
+func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) {
+ 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) {
+ // 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.
+func (w *huffmanBitWriter) writeBlock(matches []matchfinder.Match, eof bool, input []byte) {
+ numLiterals, numOffsets := w.makeStatistics(matches, input)
+
+ var extraBits int
+ storedSize, storable := w.storedSize(input)
+ if storable {
+ // We only bother calculating the costs of the extra bits required by
+ // the length of offset fields (which will be the same for both fixed
+ // and dynamic encoding), if we need to compare those two encodings
+ // against stored encoding.
+ for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
+ // First eight length codes have extra size = 0.
+ extraBits += int(w.literalFreq[lengthCode]) * int(lengthExtraBits[lengthCode-lengthCodesStart])
+ }
+ for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
+ // First four offset codes have extra size = 0.
+ extraBits += int(w.offsetFreq[offsetCode]) * int(offsetExtraBits[offsetCode])
+ }
+ }
+
+ // Figure out smallest code.
+ // Fixed Huffman baseline.
+ var literalEncoding = fixedLiteralEncoding
+ var offsetEncoding = fixedOffsetEncoding
+ var 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(matches, input, literalEncoding.codes, offsetEncoding.codes)
+ w.writeCode(literalEncoding.codes[endBlockMarker])
+}
+
+// makeStatistics 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) makeStatistics(matches []matchfinder.Match, input []byte) (numLiterals, numOffsets int) {
+ for i := range w.literalFreq {
+ w.literalFreq[i] = 0
+ }
+ for i := range w.offsetFreq {
+ w.offsetFreq[i] = 0
+ }
+
+ pos := 0
+ for _, m := range matches {
+ for _, c := range input[pos : pos+m.Unmatched] {
+ w.literalFreq[c]++
+ }
+ pos += m.Unmatched
+
+ if m.Length == 0 {
+ continue
+ }
+ w.literalFreq[lengthCodesStart+lengthCode(m.Length)]++
+ w.offsetFreq[offsetCode(m.Distance)]++
+ pos += m.Length
+ }
+ w.literalFreq[endBlockMarker]++
+
+ // 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
+ }
+ w.literalEncoding.generate(w.literalFreq, 15)
+ w.offsetEncoding.generate(w.offsetFreq, 15)
+ return
+}
+
+// writeTokens writes a slice of tokens to the output.
+// codes for literal and offset encoding must be supplied.
+func (w *huffmanBitWriter) writeTokens(matches []matchfinder.Match, input []byte, leCodes, oeCodes []hcode) {
+ pos := 0
+ for _, m := range matches {
+ for _, c := range input[pos : pos+m.Unmatched] {
+ w.writeCode(leCodes[c])
+ }
+ pos += m.Unmatched
+
+ // Write the length
+ length := m.Length
+ if length == 0 {
+ continue
+ }
+ lengthCode := lengthCode(length)
+ w.writeCode(leCodes[lengthCode+lengthCodesStart])
+ extraLengthBits := uint(lengthExtraBits[lengthCode])
+ if extraLengthBits > 0 {
+ extraLength := int32(length - baseMatchLength - lengthBase[lengthCode])
+ w.writeBits(extraLength, extraLengthBits)
+ }
+
+ // Write the offset
+ offset := m.Distance
+ offsetCode := offsetCode(offset)
+ w.writeCode(oeCodes[offsetCode])
+ extraOffsetBits := uint(offsetExtraBits[offsetCode])
+ if extraOffsetBits > 0 {
+ extraOffset := int32(offset - baseMatchOffset - offsetBase[offsetCode])
+ w.writeBits(extraOffset, extraOffsetBits)
+ }
+ pos += m.Length
+ }
+}
+
+func (w *huffmanBitWriter) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {
+ w.dst = dst
+
+ w.writeBlock(matches, lastBlock, src)
+ if lastBlock {
+ w.flush()
+ }
+
+ dst = w.dst
+ w.dst = nil
+ return dst
+}
diff --git a/vendor/github.com/andybalholm/brotli/flate/huffman_code.go b/vendor/github.com/andybalholm/brotli/flate/huffman_code.go
new file mode 100644
index 00000000..1d73f47d
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/flate/huffman_code.go
@@ -0,0 +1,346 @@
+// 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"
+ "sort"
+)
+
+// hcode is a huffman code with a bit code and bit length.
+type hcode struct {
+ code, len uint16
+}
+
+type huffmanEncoder struct {
+ codes []hcode
+ freqcache []literalNode
+ bitCount [17]int32
+ lns byLiteral // stored to avoid repeated allocation in generate
+ lfs byFreq // stored to avoid repeated allocation in generate
+}
+
+type literalNode struct {
+ literal uint16
+ freq int32
+}
+
+// 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 uint16) {
+ h.len = length
+ h.code = code
+}
+
+func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }
+
+func newHuffmanEncoder(size int) *huffmanEncoder {
+ return &huffmanEncoder{codes: make([]hcode, size)}
+}
+
+// Generates a HuffmanCode corresponding to the fixed literal table
+func generateFixedLiteralEncoding() *huffmanEncoder {
+ h := newHuffmanEncoder(maxNumLit)
+ codes := h.codes
+ var ch uint16
+ for ch = 0; ch < maxNumLit; ch++ {
+ var bits uint16
+ var size uint16
+ switch {
+ case ch < 144:
+ // size 8, 000110000 .. 10111111
+ bits = ch + 48
+ size = 8
+ case ch < 256:
+ // size 9, 110010000 .. 111111111
+ bits = ch + 400 - 144
+ size = 9
+ case ch < 280:
+ // size 7, 0000000 .. 0010111
+ bits = ch - 256
+ size = 7
+ default:
+ // size 8, 11000000 .. 11000111
+ bits = ch + 192 - 280
+ size = 8
+ }
+ codes[ch] = hcode{code: reverseBits(bits, byte(size)), len: size}
+ }
+ return h
+}
+
+func generateFixedOffsetEncoding() *huffmanEncoder {
+ h := newHuffmanEncoder(30)
+ codes := h.codes
+ for ch := range codes {
+ codes[ch] = hcode{code: reverseBits(uint16(ch), 5), len: 5}
+ }
+ return h
+}
+
+var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
+var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()
+
+func (h *huffmanEncoder) bitLength(freq []int32) int {
+ var total int
+ for i, f := range freq {
+ if f != 0 {
+ total += int(f) * int(h.codes[i].len)
+ }
+ }
+ return total
+}
+
+const maxBitsLimit = 16
+
+// Return the number of literals assigned to each bit size in the Huffman encoding
+//
+// This method is only called when list.length >= 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
+
+ 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: list[1].freq,
+ nextCharFreq: list[2].freq,
+ nextPairFreq: list[0].freq + list[1].freq,
+ }
+ 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 := maxBits
+ for {
+ 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
+ l.nextCharFreq = list[n].freq
+ } 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.
+ 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):]
+
+ h.lns.sort(chunk)
+ for _, node := range chunk {
+ h.codes[node.literal] = hcode{code: reverseBits(code, uint8(n)), len: uint16(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 []int32, maxBits int32) {
+ if h.freqcache == nil {
+ // Allocate a reusable buffer with the longest possible frequency table.
+ // Possible lengths are codegenCodeCount, offsetCodeCount and maxNumLit.
+ // The largest of these is maxNumLit, so we allocate for that case.
+ h.freqcache = make([]literalNode, maxNumLit+1)
+ }
+ list := h.freqcache[:len(freq)+1]
+ // 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 {
+ list[count] = literalNode{}
+ h.codes[i].len = 0
+ }
+ }
+ list[len(freq)] = 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
+ }
+ h.lfs.sort(list)
+
+ // Get the number of literals for each bit count
+ bitCount := h.bitCounts(list, maxBits)
+ // And do the assignment
+ h.assignEncodingAndSize(bitCount, list)
+}
+
+type byLiteral []literalNode
+
+func (s *byLiteral) sort(a []literalNode) {
+ *s = byLiteral(a)
+ sort.Sort(s)
+}
+
+func (s byLiteral) Len() int { return len(s) }
+
+func (s byLiteral) Less(i, j int) bool {
+ return s[i].literal < s[j].literal
+}
+
+func (s byLiteral) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+type byFreq []literalNode
+
+func (s *byFreq) sort(a []literalNode) {
+ *s = byFreq(a)
+ sort.Sort(s)
+}
+
+func (s byFreq) Len() int { return len(s) }
+
+func (s byFreq) Less(i, j int) bool {
+ if s[i].freq == s[j].freq {
+ return s[i].literal < s[j].literal
+ }
+ return s[i].freq < s[j].freq
+}
+
+func (s byFreq) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func reverseBits(number uint16, bitLength byte) uint16 {
+ return bits.Reverse16(number << (16 - bitLength))
+}
diff --git a/vendor/github.com/andybalholm/brotli/flate/token.go b/vendor/github.com/andybalholm/brotli/flate/token.go
new file mode 100644
index 00000000..415b1b5e
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/flate/token.go
@@ -0,0 +1,80 @@
+// 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 "log"
+
+// The length code for length X (MIN_MATCH_LENGTH <= X <= MAX_MATCH_LENGTH)
+// is lengthCodes[length - MIN_MATCH_LENGTH]
+var lengthCodes = [...]uint32{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+ 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
+ 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+ 19, 19, 19, 19, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 28,
+}
+
+var offsetCodes = [...]uint32{
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 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, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+}
+
+func lengthCode(len int) uint32 {
+ if len > 258 {
+ panic("match too long")
+ }
+ return lengthCodes[len-baseMatchLength]
+}
+
+// Returns the offset code corresponding to a specific offset
+func offsetCode(off int) uint32 {
+ if off > 32768 {
+ log.Println(off)
+ panic("match distance too high")
+ }
+ off -= baseMatchOffset
+ if off < len(offsetCodes) {
+ return offsetCodes[off]
+ }
+ if off>>7 < len(offsetCodes) {
+ return offsetCodes[off>>7] + 14
+ }
+ return offsetCodes[off>>14] + 28
+}
diff --git a/vendor/github.com/andybalholm/brotli/flate/writer.go b/vendor/github.com/andybalholm/brotli/flate/writer.go
new file mode 100644
index 00000000..1e49d489
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/flate/writer.go
@@ -0,0 +1,66 @@
+package flate
+
+import (
+ "io"
+
+ "github.com/andybalholm/brotli/matchfinder"
+)
+
+// NewWriter returns a new matchfinder.Writer that compresses data at the given level,
+// in flate encoding. Levels 1–9 are available; levels outside this range will
+// be replaced with the closest level available.
+func NewWriter(w io.Writer, level int) *matchfinder.Writer {
+ return newWriter(w, level, NewEncoder())
+}
+
+// NewGZIPWriter returns a new matchfinder.Writer that compresses data at the given
+// level, in gzip encoding. Levels 1–9 are available; levels outside this range
+// will be replaced by the closest level available.
+func NewGZIPWriter(w io.Writer, level int) *matchfinder.Writer {
+ return newWriter(w, level, NewGZIPEncoder())
+}
+
+func newWriter(w io.Writer, level int, e matchfinder.Encoder) *matchfinder.Writer {
+ var mf matchfinder.MatchFinder
+ if level < 2 {
+ mf = &matchfinder.ZFast{MaxDistance: 1 << 15}
+ } else if level == 2 {
+ mf = &matchfinder.ZDFast{MaxDistance: 1 << 15}
+ } else if level == 3 {
+ mf = &matchfinder.ZM{MaxDistance: 1 << 15}
+ } else if level == 4 {
+ mf = &matchfinder.Trio{MaxDistance: 1 << 15}
+ } else if level < 8 {
+ chainLen := 32
+ switch level {
+ case 5:
+ chainLen = 8
+ case 6:
+ chainLen = 16
+ }
+ mf = &matchfinder.M4{
+ MaxDistance: 1 << 15,
+ ChainLength: chainLen,
+ HashLen: 5,
+ DistanceBitCost: 66,
+ }
+ } else {
+ chainLen := 32
+ hashLen := 5
+ if level == 8 {
+ chainLen = 4
+ }
+ mf = &matchfinder.Pathfinder{
+ MaxDistance: 1 << 15,
+ ChainLength: chainLen,
+ HashLen: hashLen,
+ }
+ }
+
+ return &matchfinder.Writer{
+ Dest: w,
+ MatchFinder: mf,
+ Encoder: e,
+ BlockSize: 1 << 16,
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/h10.go b/vendor/github.com/andybalholm/brotli/h10.go
new file mode 100644
index 00000000..5662fbbb
--- /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 00000000..f391b73f
--- /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 00000000..80bb224a
--- /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 00000000..00f812e8
--- /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 00000000..a65fe2e6
--- /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 00000000..306e46d3
--- /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 00000000..9375dc15
--- /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 00000000..6630fc07
--- /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 00000000..0346622b
--- /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 00000000..182f3d2a
--- /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 00000000..5a9ace94
--- /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/matchfinder/bargain1.go b/vendor/github.com/andybalholm/brotli/matchfinder/bargain1.go
new file mode 100644
index 00000000..bdafbd64
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/bargain1.go
@@ -0,0 +1,212 @@
+package matchfinder
+
+import (
+ "encoding/binary"
+ "math"
+ "math/bits"
+ "slices"
+)
+
+const (
+ bargain1TableBits = 18
+ bargain1TableSize = 1 << bargain1TableBits
+)
+
+// Bargain1 is a MatchFinder that attempts to find the encoding with the lowest
+// "bit cost", using 1 hash length (6).
+type Bargain1 struct {
+ MaxDistance int
+
+ // Skip is whether to look for matches at every other byte instead of every
+ // byte (to increase speed but decrease compression).
+ Skip bool
+
+ history []byte
+ table6 [bargain1TableSize]tableEntry
+
+ // holding onto buffers to reduce allocations:
+
+ arrivals []arrival
+ matches []Match
+}
+
+func (z *Bargain1) Reset() {
+ z.table6 = [bargain1TableSize]tableEntry{}
+ z.history = z.history[:0]
+}
+
+func (z *Bargain1) FindMatches(dst []Match, src []byte) []Match {
+ if z.MaxDistance == 0 {
+ z.MaxDistance = 1 << 16
+ }
+
+ var histogram [256]uint32
+ for _, b := range src {
+ histogram[b]++
+ }
+ var byteCost [256]float32
+ for b, n := range histogram {
+ cost := max(math.Log2(float64(len(src))/float64(n)), 1)
+ byteCost[b] = float32(cost)
+ }
+
+ // Each element in arrivals corresponds to the position just after
+ // the corresponding byte in src.
+ arrivals := z.arrivals
+ if len(arrivals) < len(src) {
+ arrivals = make([]arrival, len(src))
+ z.arrivals = arrivals
+ } else {
+ arrivals = arrivals[:len(src)]
+ for i := range arrivals {
+ arrivals[i] = arrival{}
+ }
+ }
+
+ if len(z.history) > z.MaxDistance*2 {
+ delta := len(z.history) - z.MaxDistance
+ copy(z.history, z.history[delta:])
+ z.history = z.history[:z.MaxDistance]
+
+ for i := range z.table6 {
+ v := z.table6[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table6[i] = tableEntry{}
+ } else {
+ z.table6[i].offset = v
+ }
+ }
+ }
+
+ historyLen := len(z.history)
+ z.history = append(z.history, src...)
+ src = z.history
+
+ addMatch := func(m absoluteMatch, unmatched int, repeat bool) {
+ var startCost float32
+ if m.Start > historyLen {
+ startCost = arrivals[m.Start-historyLen-1].cost
+ }
+ insertCost := float32(bits.Len(uint(unmatched)))
+ var distanceCost float32
+ if !repeat {
+ distanceCost = float32(bits.Len(uint(m.Start - m.Match)))
+ }
+ cost := startCost + baseMatchCost + insertCost + distanceCost
+ for j := m.End; j >= m.Start+3; j-- {
+ a := &arrivals[j-historyLen-1]
+ if a.cost > 0 && a.cost <= cost {
+ break
+ }
+ *a = arrival{
+ length: uint32(j - m.Start),
+ distance: uint32(m.Start - m.Match),
+ cost: cost,
+ }
+ }
+ }
+
+ var nextOverlapSearch int
+
+ for i := historyLen; i < len(src); i++ {
+ var arrivedHere arrival
+ if i > historyLen {
+ arrivedHere = arrivals[i-historyLen-1]
+ }
+
+ unmatched := 0
+ if arrivedHere.distance == 0 {
+ unmatched = int(arrivedHere.length)
+ }
+ prevDistance := 0
+ if unmatched != 0 && i-unmatched > historyLen {
+ prevDistance = int(arrivals[i-historyLen-1-unmatched].distance)
+ }
+
+ literalCost := byteCost[src[i]]
+ nextArrival := &arrivals[i-historyLen]
+ if nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {
+ *nextArrival = arrival{
+ cost: arrivedHere.cost + literalCost,
+ length: uint32(unmatched + 1),
+ }
+ }
+
+ if i > len(src)-8 {
+ // There's no room to check hashes.
+ continue
+ }
+
+ cv := binary.LittleEndian.Uint64(src[i:])
+ nextHash6 := z.hash6(cv)
+ candidate6 := z.table6[nextHash6]
+
+ entry := tableEntry{offset: int32(i), val: uint32(cv)}
+ z.table6[nextHash6] = entry
+
+ // Look for a repeat match, unless there is no previous distance, or a match at
+ // that distance has already been found.
+ if prevDistance != 0 && prevDistance != int(arrivals[i-historyLen-1+4].distance) {
+ repIndex := i - prevDistance
+ if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv) {
+ // We have a repeat of the previous match distance.
+ m := extendMatch2(src, i, repIndex, i)
+ addMatch(m, unmatched, true)
+ }
+ }
+
+ if z.Skip && i%2 != 0 {
+ continue
+ }
+
+ nextByteIsUnmatched := arrivals[i-historyLen-1+1].distance == 0
+
+ if unmatched > 0 || i >= nextOverlapSearch || nextByteIsUnmatched {
+ if int(candidate6.offset) < i && i-int(candidate6.offset) < z.MaxDistance && uint32(cv) == candidate6.val &&
+ binary.LittleEndian.Uint32(src[candidate6.offset:]) == uint32(cv) {
+ m := extendMatch2(src, i, int(candidate6.offset), historyLen)
+ delta := i - m.Start
+ if delta == 0 {
+ addMatch(m, unmatched, false)
+ } else {
+ // The match was extended backwards. Add it with and without the extra.
+ addMatch(m, max(unmatched-delta, 0), false)
+ m.Start += delta
+ m.Match += delta
+ addMatch(m, unmatched, false)
+ }
+ nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-4)
+ }
+ }
+ }
+
+ // We've found the shortest path; now walk it backward and store the matches.
+ matches := z.matches[:0]
+ i := len(arrivals) - 1
+ for i >= 0 {
+ a := arrivals[i]
+ if a.distance > 0 {
+ matches = append(matches, Match{
+ Length: int(a.length),
+ Distance: int(a.distance),
+ })
+ i -= int(a.length)
+ } else {
+ if len(matches) == 0 {
+ matches = append(matches, Match{})
+ }
+ matches[len(matches)-1].Unmatched = int(a.length)
+ i -= int(a.length)
+ }
+ }
+ z.matches = matches
+
+ slices.Reverse(matches)
+
+ return append(dst, matches...)
+}
+
+func (z *Bargain1) hash6(u uint64) uint32 {
+ return uint32(((u << 16) * 227718039650203) >> (64 - bargain1TableBits))
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/bargain2.go b/vendor/github.com/andybalholm/brotli/matchfinder/bargain2.go
new file mode 100644
index 00000000..020a0003
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/bargain2.go
@@ -0,0 +1,248 @@
+package matchfinder
+
+import (
+ "encoding/binary"
+ "math"
+ "math/bits"
+ "slices"
+)
+
+const (
+ bargain2TableBits = 18
+ bargain2TableSize = 1 << bargain2TableBits
+)
+
+// Bargain2 is a MatchFinder that attempts to find the encoding with the lowest
+// "bit cost", using 2 hash lengths (5 and 8).
+type Bargain2 struct {
+ MaxDistance int
+
+ // Skip is whether to look for matches at every other byte instead of every
+ // byte (to increase speed but decrease compression).
+ Skip bool
+
+ history []byte
+ table5 [bargain2TableSize]tableEntry
+ table8 [bargain2TableSize]tableEntry
+
+ // holding onto buffers to reduce allocations:
+
+ arrivals []arrival
+ matches []Match
+}
+
+func (z *Bargain2) Reset() {
+ z.table5 = [bargain2TableSize]tableEntry{}
+ z.table8 = [bargain2TableSize]tableEntry{}
+ z.history = z.history[:0]
+}
+
+func (z *Bargain2) FindMatches(dst []Match, src []byte) []Match {
+ if z.MaxDistance == 0 {
+ z.MaxDistance = 1 << 16
+ }
+
+ var histogram [256]uint32
+ for _, b := range src {
+ histogram[b]++
+ }
+ var byteCost [256]float32
+ for b, n := range histogram {
+ cost := max(math.Log2(float64(len(src))/float64(n)), 1)
+ byteCost[b] = float32(cost)
+ }
+
+ // Each element in arrivals corresponds to the position just after
+ // the corresponding byte in src.
+ arrivals := z.arrivals
+ if len(arrivals) < len(src) {
+ arrivals = make([]arrival, len(src))
+ z.arrivals = arrivals
+ } else {
+ arrivals = arrivals[:len(src)]
+ for i := range arrivals {
+ arrivals[i] = arrival{}
+ }
+ }
+
+ if len(z.history) > z.MaxDistance*2 {
+ delta := len(z.history) - z.MaxDistance
+ copy(z.history, z.history[delta:])
+ z.history = z.history[:z.MaxDistance]
+
+ for i := range z.table5 {
+ v := z.table5[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table5[i] = tableEntry{}
+ } else {
+ z.table5[i].offset = v
+ }
+ }
+ for i := range z.table8 {
+ v := z.table8[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table8[i] = tableEntry{}
+ } else {
+ z.table8[i].offset = v
+ }
+ }
+ }
+
+ historyLen := len(z.history)
+ z.history = append(z.history, src...)
+ src = z.history
+
+ addMatch := func(m absoluteMatch, unmatched int, repeat bool) {
+ var startCost float32
+ if m.Start > historyLen {
+ startCost = arrivals[m.Start-historyLen-1].cost
+ }
+ insertCost := float32(bits.Len(uint(unmatched)))
+ var distanceCost float32
+ if !repeat {
+ distanceCost = float32(bits.Len(uint(m.Start - m.Match)))
+ }
+ cost := startCost + baseMatchCost + insertCost + distanceCost
+ for j := m.End; j >= m.Start+3; j-- {
+ a := &arrivals[j-historyLen-1]
+ if a.cost > 0 && a.cost <= cost {
+ break
+ }
+ *a = arrival{
+ length: uint32(j - m.Start),
+ distance: uint32(m.Start - m.Match),
+ cost: cost,
+ }
+ }
+ }
+
+ var nextOverlapSearch int
+
+ for i := historyLen; i < len(src); i++ {
+ var arrivedHere arrival
+ if i > historyLen {
+ arrivedHere = arrivals[i-historyLen-1]
+ }
+
+ unmatched := 0
+ if arrivedHere.distance == 0 {
+ unmatched = int(arrivedHere.length)
+ }
+ prevDistance := 0
+ if unmatched != 0 && i-unmatched > historyLen {
+ prevDistance = int(arrivals[i-historyLen-1-unmatched].distance)
+ }
+
+ literalCost := byteCost[src[i]]
+ nextArrival := &arrivals[i-historyLen]
+ if nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {
+ *nextArrival = arrival{
+ cost: arrivedHere.cost + literalCost,
+ length: uint32(unmatched + 1),
+ }
+ }
+
+ if i > len(src)-8 {
+ // There's no room to check hashes.
+ continue
+ }
+
+ cv := binary.LittleEndian.Uint64(src[i:])
+ nextHash5 := z.hash5(cv)
+ nextHash8 := z.hash8(cv)
+ candidate5 := z.table5[nextHash5]
+ candidate8 := z.table8[nextHash8]
+
+ entry := tableEntry{offset: int32(i), val: uint32(cv)}
+ z.table5[nextHash5] = entry
+ z.table8[nextHash8] = entry
+
+ // Look for a repeat match, unless there is no previous distance, or a match at
+ // that distance has already been found.
+ if prevDistance != 0 && prevDistance != int(arrivals[i-historyLen-1+4].distance) {
+ repIndex := i - prevDistance
+ if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv) {
+ // We have a repeat of the previous match distance.
+ m := extendMatch2(src, i, repIndex, i)
+ addMatch(m, unmatched, true)
+ }
+ }
+
+ if z.Skip {
+ if i%2 != 0 {
+ continue
+ }
+ }
+
+ nextByteIsUnmatched := arrivals[i-historyLen-1+1].distance == 0
+
+ if unmatched > 0 || i >= nextOverlapSearch || nextByteIsUnmatched {
+ if int(candidate5.offset) < i && i-int(candidate5.offset) < z.MaxDistance && uint32(cv) == candidate5.val &&
+ binary.LittleEndian.Uint32(src[candidate5.offset:]) == uint32(cv) {
+ m := extendMatch2(src, i, int(candidate5.offset), historyLen)
+ delta := i - m.Start
+ if delta == 0 {
+ addMatch(m, unmatched, false)
+ } else {
+ // The match was extended backwards. Add it with and without the extra.
+ addMatch(m, max(unmatched-delta, 0), false)
+ m.Start += delta
+ m.Match += delta
+ addMatch(m, unmatched, false)
+ }
+ nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+ }
+
+ if int(candidate8.offset) < i && i-int(candidate8.offset) < z.MaxDistance && uint32(cv) == candidate8.val &&
+ binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+ m := extendMatch2(src, i, int(candidate8.offset), historyLen)
+ delta := i - m.Start
+ if delta == 0 {
+ addMatch(m, unmatched, false)
+ } else {
+ // The match was extended backwards. Add it with and without the extra.
+ addMatch(m, max(unmatched-delta, 0), false)
+ m.Start += delta
+ m.Match += delta
+ addMatch(m, unmatched, false)
+ }
+ nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+ }
+ }
+ }
+
+ // We've found the shortest path; now walk it backward and store the matches.
+ matches := z.matches[:0]
+ i := len(arrivals) - 1
+ for i >= 0 {
+ a := arrivals[i]
+ if a.distance > 0 {
+ matches = append(matches, Match{
+ Length: int(a.length),
+ Distance: int(a.distance),
+ })
+ i -= int(a.length)
+ } else {
+ if len(matches) == 0 {
+ matches = append(matches, Match{})
+ }
+ matches[len(matches)-1].Unmatched = int(a.length)
+ i -= int(a.length)
+ }
+ }
+ z.matches = matches
+
+ slices.Reverse(matches)
+
+ return append(dst, matches...)
+}
+
+func (z *Bargain2) hash5(u uint64) uint32 {
+ return uint32(((u << 24) * 889523592379) >> (64 - bargain2TableBits))
+}
+
+func (z *Bargain2) hash8(u uint64) uint32 {
+ return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - bargain2TableBits))
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/bargain3.go b/vendor/github.com/andybalholm/brotli/matchfinder/bargain3.go
new file mode 100644
index 00000000..24acd1ca
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/bargain3.go
@@ -0,0 +1,278 @@
+package matchfinder
+
+import (
+ "encoding/binary"
+ "math"
+ "math/bits"
+ "slices"
+)
+
+// Bargain3 is a MatchFinder that attempts to find the encoding with the lowest
+// "bit cost", using 3 hash lengths (5, 8, and 12).
+type Bargain3 struct {
+ MaxDistance int
+
+ // Skip is whether to look for matches at every other byte instead of every
+ // byte (to increase speed but decrease compression).
+ Skip bool
+
+ history []byte
+ table5 [1 << 17]tableEntry
+ table8 [1 << 18]tableEntry
+ table12 [1 << 19]tableEntry
+
+ // holding onto buffers to reduce allocations:
+
+ arrivals []arrival
+ matches []Match
+}
+
+func (z *Bargain3) Reset() {
+ z.table5 = [len(z.table5)]tableEntry{}
+ z.table8 = [len(z.table8)]tableEntry{}
+ z.table12 = [len(z.table12)]tableEntry{}
+ z.history = z.history[:0]
+}
+
+func (z *Bargain3) FindMatches(dst []Match, src []byte) []Match {
+ if z.MaxDistance == 0 {
+ z.MaxDistance = 1 << 16
+ }
+
+ var histogram [256]uint32
+ for _, b := range src {
+ histogram[b]++
+ }
+ var byteCost [256]float32
+ for b, n := range histogram {
+ cost := max(math.Log2(float64(len(src))/float64(n)), 1)
+ byteCost[b] = float32(cost)
+ }
+
+ // Each element in arrivals corresponds to the position just after
+ // the corresponding byte in src.
+ arrivals := z.arrivals
+ if len(arrivals) < len(src) {
+ arrivals = make([]arrival, len(src))
+ z.arrivals = arrivals
+ } else {
+ arrivals = arrivals[:len(src)]
+ for i := range arrivals {
+ arrivals[i] = arrival{}
+ }
+ }
+
+ if len(z.history) > z.MaxDistance*2 {
+ delta := len(z.history) - z.MaxDistance
+ copy(z.history, z.history[delta:])
+ z.history = z.history[:z.MaxDistance]
+
+ for i := range z.table5 {
+ v := z.table5[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table5[i] = tableEntry{}
+ } else {
+ z.table5[i].offset = v
+ }
+ }
+ for i := range z.table8 {
+ v := z.table8[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table8[i] = tableEntry{}
+ } else {
+ z.table8[i].offset = v
+ }
+ }
+ for i := range z.table12 {
+ v := z.table12[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table12[i] = tableEntry{}
+ } else {
+ z.table12[i].offset = v
+ }
+ }
+ }
+
+ historyLen := len(z.history)
+ z.history = append(z.history, src...)
+ src = z.history
+
+ addMatch := func(m absoluteMatch, unmatched int, repeat bool) {
+ var startCost float32
+ if m.Start > historyLen {
+ startCost = arrivals[m.Start-historyLen-1].cost
+ }
+ insertCost := float32(bits.Len(uint(unmatched)))
+ var distanceCost float32
+ if !repeat {
+ distanceCost = float32(bits.Len(uint(m.Start - m.Match)))
+ }
+ cost := startCost + baseMatchCost + insertCost + distanceCost
+ for j := m.End; j >= m.Start+3; j-- {
+ a := &arrivals[j-historyLen-1]
+ if a.cost > 0 && a.cost <= cost {
+ break
+ }
+ *a = arrival{
+ length: uint32(j - m.Start),
+ distance: uint32(m.Start - m.Match),
+ cost: cost,
+ }
+ }
+ }
+
+ var nextOverlapSearch int
+
+ for i := historyLen; i < len(src); i++ {
+ var arrivedHere arrival
+ if i > historyLen {
+ arrivedHere = arrivals[i-historyLen-1]
+ }
+
+ unmatched := 0
+ if arrivedHere.distance == 0 {
+ unmatched = int(arrivedHere.length)
+ }
+ prevDistance := 0
+ if unmatched != 0 && i-unmatched > historyLen {
+ prevDistance = int(arrivals[i-historyLen-1-unmatched].distance)
+ }
+
+ literalCost := byteCost[src[i]]
+ nextArrival := &arrivals[i-historyLen]
+ if nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {
+ *nextArrival = arrival{
+ cost: arrivedHere.cost + literalCost,
+ length: uint32(unmatched + 1),
+ }
+ }
+
+ if i > len(src)-12 {
+ // There's no room to check hashes.
+ continue
+ }
+
+ cv := binary.LittleEndian.Uint64(src[i:])
+ extra := binary.LittleEndian.Uint32(src[i+8:])
+ nextHash5 := z.hash5(cv)
+ nextHash8 := z.hash8(cv)
+ nextHash12 := z.hash12(cv, extra)
+ candidate5 := z.table5[nextHash5]
+ candidate8 := z.table8[nextHash8]
+ candidate12 := z.table12[nextHash12]
+
+ entry := tableEntry{offset: int32(i), val: uint32(cv)}
+ z.table5[nextHash5] = entry
+ z.table8[nextHash8] = entry
+ z.table12[nextHash12] = entry
+
+ // Look for a repeat match, unless there is no previous distance, or a match at
+ // that distance has already been found.
+ if prevDistance != 0 && prevDistance != int(arrivals[i-historyLen-1+4].distance) {
+ repIndex := i - prevDistance
+ if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv) {
+ // We have a repeat of the previous match distance.
+ m := extendMatch2(src, i, repIndex, i)
+ addMatch(m, unmatched, true)
+ }
+ }
+
+ if z.Skip {
+ if i%2 != 0 {
+ continue
+ }
+ }
+
+ nextByteIsUnmatched := arrivals[i-historyLen-1+1].distance == 0
+
+ if unmatched > 0 || i >= nextOverlapSearch || nextByteIsUnmatched {
+ if int(candidate5.offset) < i && i-int(candidate5.offset) < z.MaxDistance && uint32(cv) == candidate5.val &&
+ binary.LittleEndian.Uint32(src[candidate5.offset:]) == uint32(cv) {
+ m := extendMatch2(src, i, int(candidate5.offset), historyLen)
+ delta := i - m.Start
+ if delta == 0 {
+ addMatch(m, unmatched, false)
+ } else {
+ // The match was extended backwards. Add it with and without the extra.
+ addMatch(m, max(unmatched-delta, 0), false)
+ m.Start += delta
+ m.Match += delta
+ addMatch(m, unmatched, false)
+ }
+ nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+ }
+
+ if int(candidate8.offset) < i && i-int(candidate8.offset) < z.MaxDistance && uint32(cv) == candidate8.val &&
+ binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+ m := extendMatch2(src, i, int(candidate8.offset), historyLen)
+ delta := i - m.Start
+ if delta == 0 {
+ addMatch(m, unmatched, false)
+ } else {
+ // The match was extended backwards. Add it with and without the extra.
+ addMatch(m, max(unmatched-delta, 0), false)
+ m.Start += delta
+ m.Match += delta
+ addMatch(m, unmatched, false)
+ }
+ nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+ }
+
+ if int(candidate12.offset) < i && i-int(candidate12.offset) < z.MaxDistance && uint32(cv) == candidate12.val &&
+ binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+ m := extendMatch2(src, i, int(candidate12.offset), historyLen)
+ delta := i - m.Start
+ if delta == 0 {
+ addMatch(m, unmatched, false)
+ } else {
+ // The match was extended backwards. Add it with and without the extra.
+ addMatch(m, max(unmatched-delta, 0), false)
+ m.Start += delta
+ m.Match += delta
+ addMatch(m, unmatched, false)
+ }
+ nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+ }
+ }
+ }
+
+ // We've found the shortest path; now walk it backward and store the matches.
+ matches := z.matches[:0]
+ i := len(arrivals) - 1
+ for i >= 0 {
+ a := arrivals[i]
+ if a.distance > 0 {
+ matches = append(matches, Match{
+ Length: int(a.length),
+ Distance: int(a.distance),
+ })
+ i -= int(a.length)
+ } else {
+ if len(matches) == 0 {
+ matches = append(matches, Match{})
+ }
+ matches[len(matches)-1].Unmatched = int(a.length)
+ i -= int(a.length)
+ }
+ }
+ z.matches = matches
+
+ slices.Reverse(matches)
+
+ return append(dst, matches...)
+}
+
+func (z *Bargain3) hash5(u uint64) uint32 {
+ return uint32(((u << 24) * 889523592379) >> (64 - 17))
+}
+
+func (z *Bargain3) hash8(u uint64) uint32 {
+ return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - 18))
+}
+
+func (z *Bargain3) hash12(u uint64, e uint32) uint32 {
+ return uint32((u*0xcf1bbcdcb7a56463 + uint64(e)*(2654435761<<32)) >> (64 - 19))
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/emitter.go b/vendor/github.com/andybalholm/brotli/matchfinder/emitter.go
new file mode 100644
index 00000000..507d1cae
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/emitter.go
@@ -0,0 +1,34 @@
+package matchfinder
+
+// An absoluteMatch is like a Match, but it stores indexes into the byte
+// stream instead of lengths.
+type absoluteMatch struct {
+ // Start is the index of the first byte.
+ Start int
+
+ // End is the index of the byte after the last byte
+ // (so that End - Start = Length).
+ End int
+
+ // Match is the index of the previous data that matches
+ // (Start - Match = Distance).
+ Match int
+}
+
+// A matchEmitter manages the output of matches for a MatchFinder.
+type matchEmitter struct {
+ // Dst is the destination slice that Matches are added to.
+ Dst []Match
+
+ // NextEmit is the index of the next byte to emit.
+ NextEmit int
+}
+
+func (e *matchEmitter) emit(m absoluteMatch) {
+ e.Dst = append(e.Dst, Match{
+ Unmatched: m.Start - e.NextEmit,
+ Length: m.End - m.Start,
+ Distance: m.Start - m.Match,
+ })
+ e.NextEmit = m.End
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/m0.go b/vendor/github.com/andybalholm/brotli/matchfinder/m0.go
new file mode 100644
index 00000000..a37e3b46
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/m0.go
@@ -0,0 +1,175 @@
+package matchfinder
+
+import (
+ "encoding/binary"
+)
+
+// M0 is an implementation of the MatchFinder interface based
+// on the algorithm used by snappy, but modified to be more like the algorithm
+// used by compression level 0 of the brotli reference implementation.
+//
+// It has a maximum block size of 65536 bytes.
+type M0 struct {
+ // Lazy turns on "lazy matching," for higher compression but less speed.
+ Lazy bool
+
+ MaxDistance int
+ MaxLength int
+}
+
+func (M0) Reset() {}
+
+const (
+ m0HashLen = 5
+
+ m0TableBits = 16
+ m0TableSize = 1 << m0TableBits
+ m0Shift = 32 - m0TableBits
+ // m0TableMask is redundant, but helps the compiler eliminate bounds
+ // checks.
+ m0TableMask = m0TableSize - 1
+)
+
+func (m M0) hash(data uint64) uint64 {
+ hash := (data << (64 - 8*m0HashLen)) * hashMul64
+ return hash >> (64 - m0TableBits)
+}
+
+// FindMatches looks for matches in src, appends them to dst, and returns dst.
+// src must not be longer than 65536 bytes.
+func (m M0) FindMatches(dst []Match, src []byte) []Match {
+ const inputMargin = 16 - 1
+ const minNonLiteralBlockSize = 1 + 1 + inputMargin
+
+ if len(src) < minNonLiteralBlockSize {
+ dst = append(dst, Match{
+ Unmatched: len(src),
+ })
+ return dst
+ }
+ if len(src) > 65536 {
+ panic("block too long")
+ }
+
+ var table [m0TableSize]uint16
+
+ // 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 := len(src) - inputMargin
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ nextHash := m.hash(binary.LittleEndian.Uint64(src[s:]))
+
+ for {
+ // Copied from the C++ snappy implementation:
+ //
+ // 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 (or skipped), 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.
+ skip := 32
+
+ nextS := s
+ candidate := 0
+ for {
+ s = nextS
+ bytesBetweenHashLookups := skip >> 5
+ nextS = s + bytesBetweenHashLookups
+ skip += bytesBetweenHashLookups
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ candidate = int(table[nextHash&m0TableMask])
+ table[nextHash&m0TableMask] = uint16(s)
+ nextHash = m.hash(binary.LittleEndian.Uint64(src[nextS:]))
+ if m.MaxDistance != 0 && s-candidate > m.MaxDistance {
+ continue
+ }
+ if binary.LittleEndian.Uint32(src[s:]) == binary.LittleEndian.Uint32(src[candidate:]) {
+ break
+ }
+ }
+
+ // Invariant: we have a 4-byte match at s.
+ base := s
+ s = extendMatch(src, candidate+4, s+4)
+
+ origBase := base
+ if m.Lazy && base+1 < sLimit {
+ newBase := base + 1
+ h := m.hash(binary.LittleEndian.Uint64(src[newBase:]))
+ newCandidate := int(table[h&m0TableMask])
+ table[h&m0TableMask] = uint16(newBase)
+ okDistance := true
+ if m.MaxDistance != 0 && newBase-newCandidate > m.MaxDistance {
+ okDistance = false
+ }
+ if okDistance && binary.LittleEndian.Uint32(src[newBase:]) == binary.LittleEndian.Uint32(src[newCandidate:]) {
+ newS := extendMatch(src, newCandidate+4, newBase+4)
+ if newS-newBase > s-base+1 {
+ s = newS
+ base = newBase
+ candidate = newCandidate
+ }
+ }
+ }
+
+ if m.MaxLength != 0 && s-base > m.MaxLength {
+ s = base + m.MaxLength
+ }
+ dst = append(dst, Match{
+ Unmatched: base - nextEmit,
+ Length: s - base,
+ Distance: base - candidate,
+ })
+ nextEmit = s
+ if s >= sLimit {
+ goto emitRemainder
+ }
+
+ if m.Lazy {
+ // If lazy matching is enabled, we update the hash table for
+ // every byte in the match.
+ for i := origBase + 2; i < s-3; i++ {
+ x := binary.LittleEndian.Uint64(src[i:])
+ table[m.hash(x)&m0TableMask] = uint16(i)
+ }
+ } else {
+ // We update the hash table only at base+1
+ x := binary.LittleEndian.Uint64(src[base+1:])
+ table[m.hash(x)&m0TableMask] = uint16(base + 1)
+ }
+
+ // We could immediately start working at s now, but to improve
+ // compression we first update the hash table.
+ x := binary.LittleEndian.Uint64(src[s-3:])
+ table[m.hash(x)&m0TableMask] = uint16(s - 3)
+ table[m.hash(x>>8)&m0TableMask] = uint16(s - 2)
+ prevHash := m.hash(x >> 16)
+ table[prevHash&m0TableMask] = uint16(s - 1)
+ nextHash = m.hash(x >> 24)
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ dst = append(dst, Match{
+ Unmatched: len(src) - nextEmit,
+ })
+ }
+ return dst
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/m4.go b/vendor/github.com/andybalholm/brotli/matchfinder/m4.go
new file mode 100644
index 00000000..a92b92f6
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/m4.go
@@ -0,0 +1,339 @@
+package matchfinder
+
+import (
+ "bytes"
+ "encoding/binary"
+ "math/bits"
+ "runtime"
+)
+
+// M4 is an implementation of the MatchFinder
+// interface that uses a hash table to find matches,
+// optional match chains,
+// and the advanced parsing technique from
+// https://fastcompression.blogspot.com/2011/12/advanced-parsing-strategies.html.
+type M4 struct {
+ // MaxDistance is the maximum distance (in bytes) to look back for
+ // a match. The default is 65535.
+ MaxDistance int
+
+ // MinLength is the length of the shortest match to return.
+ // The default is 4.
+ MinLength int
+
+ // HashLen is the number of bytes to use to calculate the hashes.
+ // The maximum is 8 and the default is 6.
+ HashLen int
+
+ // TableBits is the number of bits in the hash table indexes.
+ // The default is 17 (128K entries).
+ TableBits int
+
+ // ChainLength is how many entries to search on the "match chain" of older
+ // locations with the same hash as the current location.
+ ChainLength int
+
+ // DistanceBitCost is used when comparing two matches to see
+ // which is better. The comparison is primarily based on the length
+ // of the matches, but it can also take the distance into account,
+ // in terms of the number of bits needed to represent the distance.
+ // One byte of length is given a score of 256, so 32 (256/8) would
+ // be a reasonable first guess for the value of one bit.
+ // (The default is 0, which bases the comparison solely on length.)
+ DistanceBitCost int
+
+ table []uint32
+ chain []uint32
+
+ history []byte
+}
+
+func (q *M4) Reset() {
+ for i := range q.table {
+ q.table[i] = 0
+ }
+ q.history = q.history[:0]
+ q.chain = q.chain[:0]
+}
+
+func (q *M4) score(m absoluteMatch) int {
+ return (m.End-m.Start)*256 + (bits.LeadingZeros32(uint32(m.Start-m.Match))-32)*q.DistanceBitCost
+}
+
+func (q *M4) FindMatches(dst []Match, src []byte) []Match {
+ if q.MaxDistance == 0 {
+ q.MaxDistance = 65535
+ }
+ if q.MinLength == 0 {
+ q.MinLength = 4
+ }
+ if q.HashLen == 0 {
+ q.HashLen = 6
+ }
+ if q.TableBits == 0 {
+ q.TableBits = 17
+ }
+ if len(q.table) < 1< q.MaxDistance*2 {
+ // Trim down the history buffer.
+ delta := len(q.history) - q.MaxDistance
+ copy(q.history, q.history[delta:])
+ q.history = q.history[:q.MaxDistance]
+ if q.ChainLength > 0 {
+ copy(q.chain, q.chain[delta:])
+ q.chain = q.chain[:q.MaxDistance]
+ }
+
+ for i, v := range q.table {
+ newV := int(v) - delta
+ if newV < 0 {
+ newV = 0
+ }
+ q.table[i] = uint32(newV)
+ }
+ }
+
+ // Append src to the history buffer.
+ e.NextEmit = len(q.history)
+ q.history = append(q.history, src...)
+ if q.ChainLength > 0 {
+ q.chain = append(q.chain, make([]uint32, len(src))...)
+ }
+ src = q.history
+
+ // matches stores the matches that have been found but not emitted,
+ // in reverse order. (matches[0] is the most recent one.)
+ var matches [3]absoluteMatch
+ for i := e.NextEmit; i < len(src)-7; i++ {
+ if matches[0] != (absoluteMatch{}) && i >= matches[0].End {
+ // We have found some matches, and we're far enough along that we probably
+ // won't find overlapping matches, so we might as well emit them.
+ if matches[1] != (absoluteMatch{}) {
+ if matches[1].End > matches[0].Start {
+ matches[1].End = matches[0].Start
+ }
+ if matches[1].End-matches[1].Start >= q.MinLength && q.score(matches[1]) > 0 {
+ e.emit(matches[1])
+ }
+ }
+ e.emit(matches[0])
+ matches = [3]absoluteMatch{}
+ }
+
+ // Look for a repeat match one byte after the current position.
+ if matches[0] == (absoluteMatch{}) && len(e.Dst) > 0 {
+ prevDistance := e.Dst[len(e.Dst)-1].Distance
+ if binary.LittleEndian.Uint32(src[i+1:]) == binary.LittleEndian.Uint32(src[i+1-prevDistance:]) {
+ // We have a 4-byte match.
+ m := extendMatch2(src, i+1, i+1-prevDistance, e.NextEmit+1)
+ if m.End-m.Start >= q.MinLength {
+ matches[0] = m
+ }
+ }
+ }
+
+ // Calculate and store the hash.
+ h := ((binary.LittleEndian.Uint64(src[i:]) & (1<<(8*q.HashLen) - 1)) * hashMul64) >> (64 - q.TableBits)
+ candidate := int(q.table[h])
+ q.table[h] = uint32(i)
+ if q.ChainLength > 0 && candidate != 0 {
+ delta := i - candidate
+ q.chain[i] = uint32(delta)
+ }
+
+ if i < matches[0].End && i != matches[0].End+2-q.HashLen {
+ continue
+ }
+ if candidate == 0 || i-candidate > q.MaxDistance {
+ continue
+ }
+
+ // Look for a match.
+ var currentMatch absoluteMatch
+
+ if binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {
+ m := extendMatch2(src, i, candidate, e.NextEmit)
+ if m.End-m.Start > q.MinLength && q.score(m) > 0 {
+ currentMatch = m
+ }
+ }
+
+ for j := 0; j < q.ChainLength; j++ {
+ delta := q.chain[candidate]
+ if delta == 0 {
+ break
+ }
+ candidate -= int(delta)
+ if candidate <= 0 || i-candidate > q.MaxDistance {
+ break
+ }
+ if binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {
+ m := extendMatch2(src, i, candidate, e.NextEmit)
+ if m.End-m.Start > q.MinLength && q.score(m) > q.score(currentMatch) {
+ currentMatch = m
+ }
+ }
+ }
+
+ if currentMatch.End-currentMatch.Start < q.MinLength {
+ continue
+ }
+
+ overlapPenalty := 0
+ if matches[0] != (absoluteMatch{}) {
+ overlapPenalty = 275
+ if currentMatch.Start <= matches[1].End {
+ // This match would completely replace the previous match,
+ // so there is no penalty for overlap.
+ overlapPenalty = 0
+ }
+ }
+
+ if q.score(currentMatch) <= q.score(matches[0])+overlapPenalty {
+ continue
+ }
+
+ matches = [3]absoluteMatch{
+ currentMatch,
+ matches[0],
+ matches[1],
+ }
+
+ if matches[2] == (absoluteMatch{}) {
+ continue
+ }
+
+ // We have three matches, so it's time to emit one and/or eliminate one.
+ switch {
+ case matches[0].Start < matches[2].End:
+ // The first and third matches overlap; discard the one in between.
+ matches = [3]absoluteMatch{
+ matches[0],
+ matches[2],
+ absoluteMatch{},
+ }
+
+ case matches[0].Start < matches[2].End+q.MinLength:
+ // The first and third matches don't overlap, but there's no room for
+ // another match between them. Emit the first match and discard the second.
+ e.emit(matches[2])
+ matches = [3]absoluteMatch{
+ matches[0],
+ absoluteMatch{},
+ absoluteMatch{},
+ }
+
+ default:
+ // Emit the first match, shortening it if necessary to avoid overlap with the second.
+ if matches[2].End > matches[1].Start {
+ matches[2].End = matches[1].Start
+ if q.ChainLength > 0 && matches[2].End-matches[2].Start >= q.MinLength {
+ // Since the match length was trimmed, we may be able to find a closer match
+ // to replace it.
+ pos := matches[2].Start
+ for {
+ delta := int(q.chain[pos])
+ if delta == 0 {
+ break
+ }
+ pos -= delta
+ if pos <= matches[2].Match {
+ break
+ }
+ if bytes.Equal(src[matches[2].Start:matches[2].End], src[pos:pos+matches[2].End-matches[2].Start]) {
+ matches[2].Match = pos
+ break
+ }
+ }
+ }
+ }
+ if matches[2].End-matches[2].Start >= q.MinLength && q.score(matches[2]) > 0 {
+ e.emit(matches[2])
+ }
+ matches[2] = absoluteMatch{}
+ }
+ }
+
+ // We've found all the matches now; emit the remaining ones.
+ if matches[1] != (absoluteMatch{}) {
+ if matches[1].End > matches[0].Start {
+ matches[1].End = matches[0].Start
+ }
+ if matches[1].End-matches[1].Start >= q.MinLength && q.score(matches[1]) > 0 {
+ e.emit(matches[1])
+ }
+ }
+ if matches[0] != (absoluteMatch{}) {
+ e.emit(matches[0])
+ }
+
+ dst = e.Dst
+ if e.NextEmit < len(src) {
+ dst = append(dst, Match{
+ Unmatched: len(src) - e.NextEmit,
+ })
+ }
+
+ return dst
+}
+
+const hashMul64 = 0x1E35A7BD1E35A7BD
+
+// extendMatch returns the largest k such that k <= len(src) and that
+// src[i:i+k-j] and src[j:k] have the same contents.
+//
+// It assumes that:
+//
+// 0 <= i && i < j && j <= len(src)
+func extendMatch(src []byte, i, j int) int {
+ switch runtime.GOARCH {
+ case "amd64", "arm64":
+ // As long as we are 8 or more bytes before the end of src, we can load and
+ // compare 8 bytes at a time. If those 8 bytes are equal, repeat.
+ for j+8 < len(src) {
+ iBytes := binary.LittleEndian.Uint64(src[i:])
+ jBytes := binary.LittleEndian.Uint64(src[j:])
+ if iBytes != jBytes {
+ // If those 8 bytes were not equal, XOR the two 8 byte values, and return
+ // the index of the first byte that differs. The BSF instruction finds the
+ // least significant 1 bit, the amd64 architecture is little-endian, and
+ // the shift by 3 converts a bit index to a byte index.
+ return j + bits.TrailingZeros64(iBytes^jBytes)>>3
+ }
+ i, j = i+8, j+8
+ }
+ case "386":
+ // On a 32-bit CPU, we do it 4 bytes at a time.
+ for j+4 < len(src) {
+ iBytes := binary.LittleEndian.Uint32(src[i:])
+ jBytes := binary.LittleEndian.Uint32(src[j:])
+ if iBytes != jBytes {
+ return j + bits.TrailingZeros32(iBytes^jBytes)>>3
+ }
+ i, j = i+4, j+4
+ }
+ }
+ for ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 {
+ }
+ return j
+}
+
+// Given a 4-byte match at src[start] and src[candidate], extendMatch2 extends it
+// upward as far as possible, and downward no farther than to min.
+func extendMatch2(src []byte, start, candidate, min int) absoluteMatch {
+ end := extendMatch(src, candidate+4, start+4)
+ for start > min && candidate > 0 && src[start-1] == src[candidate-1] {
+ start--
+ candidate--
+ }
+ return absoluteMatch{
+ Start: start,
+ End: end,
+ Match: candidate,
+ }
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/matchfinder.go b/vendor/github.com/andybalholm/brotli/matchfinder/matchfinder.go
new file mode 100644
index 00000000..f6bcfdb3
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/matchfinder.go
@@ -0,0 +1,103 @@
+// The matchfinder package defines reusable components for data compression.
+//
+// Many compression libraries have two main parts:
+// - Something that looks for repeated sequences of bytes
+// - An encoder for the compressed data format (often an entropy coder)
+//
+// Although these are logically two separate steps, the implementations are
+// usually closely tied together. You can't use flate's matcher with snappy's
+// encoder, for example. This package defines interfaces and an intermediate
+// representation to allow mixing and matching compression components.
+package matchfinder
+
+import "io"
+
+// A Match is the basic unit of LZ77 compression.
+type Match struct {
+ Unmatched int // the number of unmatched bytes since the previous match
+ Length int // the number of bytes in the matched string; it may be 0 at the end of the input
+ Distance int // how far back in the stream to copy from
+}
+
+// A MatchFinder performs the LZ77 stage of compression, looking for matches.
+type MatchFinder interface {
+ // FindMatches looks for matches in src, appends them to dst, and returns dst.
+ FindMatches(dst []Match, src []byte) []Match
+
+ // Reset clears any internal state, preparing the MatchFinder to be used with
+ // a new stream.
+ Reset()
+}
+
+// An Encoder encodes the data in its final format.
+type Encoder interface {
+ // Encode appends the encoded format of src to dst, using the match
+ // information from matches.
+ Encode(dst []byte, src []byte, matches []Match, lastBlock bool) []byte
+
+ // Reset clears any internal state, preparing the Encoder to be used with
+ // a new stream.
+ Reset()
+}
+
+// A Writer uses MatchFinder and Encoder to write compressed data to Dest.
+type Writer struct {
+ Dest io.Writer
+ MatchFinder MatchFinder
+ Encoder Encoder
+
+ // BlockSize is the number of bytes to compress at a time. If it is zero,
+ // each Write operation will be treated as one block.
+ BlockSize int
+
+ err error
+ inBuf []byte
+ outBuf []byte
+ matches []Match
+}
+
+func (w *Writer) Write(p []byte) (n int, err error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+
+ if w.BlockSize == 0 {
+ return w.writeBlock(p, false)
+ }
+
+ w.inBuf = append(w.inBuf, p...)
+ var pos int
+ for pos = 0; pos+w.BlockSize <= len(w.inBuf) && w.err == nil; pos += w.BlockSize {
+ w.writeBlock(w.inBuf[pos:pos+w.BlockSize], false)
+ }
+ if pos > 0 {
+ n := copy(w.inBuf, w.inBuf[pos:])
+ w.inBuf = w.inBuf[:n]
+ }
+
+ return len(p), w.err
+}
+
+func (w *Writer) writeBlock(p []byte, lastBlock bool) (n int, err error) {
+ w.outBuf = w.outBuf[:0]
+ w.matches = w.MatchFinder.FindMatches(w.matches[:0], p)
+ w.outBuf = w.Encoder.Encode(w.outBuf, p, w.matches, lastBlock)
+ _, w.err = w.Dest.Write(w.outBuf)
+ return len(p), w.err
+}
+
+func (w *Writer) Close() error {
+ w.writeBlock(w.inBuf, true)
+ w.inBuf = w.inBuf[:0]
+ return w.err
+}
+
+func (w *Writer) Reset(newDest io.Writer) {
+ w.MatchFinder.Reset()
+ w.Encoder.Reset()
+ w.err = nil
+ w.inBuf = w.inBuf[:0]
+ w.outBuf = w.outBuf[:0]
+ w.matches = w.matches[:0]
+ w.Dest = newDest
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/pathfinder.go b/vendor/github.com/andybalholm/brotli/matchfinder/pathfinder.go
new file mode 100644
index 00000000..2a12ab9d
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/pathfinder.go
@@ -0,0 +1,328 @@
+package matchfinder
+
+import (
+ "encoding/binary"
+ "math"
+ "math/bits"
+ "slices"
+)
+
+// Pathfinder is a MatchFinder that uses hash chains to find matches, and a
+// shortest-path optimizer to choose which matches to use.
+type Pathfinder struct {
+ // MaxDistance is the maximum distance (in bytes) to look back for
+ // a match. The default is 65535.
+ MaxDistance int
+
+ // MinLength is the length of the shortest match to return.
+ // The default is 4.
+ MinLength int
+
+ // HashLen is the number of bytes to use to calculate the hashes.
+ // The maximum is 8 and the default is 6.
+ HashLen int
+
+ // TableBits is the number of bits in the hash table indexes.
+ // The default is 17 (128K entries).
+ TableBits int
+
+ // ChainLength is how many entries to search on the "match chain" of older
+ // locations with the same hash as the current location.
+ ChainLength int
+
+ table []uint32
+ chain []uint32
+
+ history []byte
+
+ // holding onto buffers to reduce allocations:
+
+ arrivals []arrival
+ foundMatches []absoluteMatch
+ matches []Match
+}
+
+func (q *Pathfinder) Reset() {
+ for i := range q.table {
+ q.table[i] = 0
+ }
+ q.history = q.history[:0]
+ q.chain = q.chain[:0]
+}
+
+// An arrival represents how we got to a certain byte position.
+// The cost is the total cost to get there from the beginning of the block.
+// If distance > 0, the arrival is with a match.
+// If distance == 0, the arrival is with a run of literals.
+type arrival struct {
+ length uint32
+ distance uint32
+ cost float32
+}
+
+const (
+ baseMatchCost float32 = 4
+)
+
+func (q *Pathfinder) FindMatches(dst []Match, src []byte) []Match {
+ if q.MaxDistance == 0 {
+ q.MaxDistance = 65535
+ }
+ if q.MinLength == 0 {
+ q.MinLength = 4
+ }
+ if q.HashLen == 0 {
+ q.HashLen = 6
+ }
+ if q.TableBits == 0 {
+ q.TableBits = 17
+ }
+ if len(q.table) < 1< q.MaxDistance*2 {
+ // Trim down the history buffer.
+ delta := len(q.history) - q.MaxDistance
+ copy(q.history, q.history[delta:])
+ q.history = q.history[:q.MaxDistance]
+ q.chain = q.chain[:q.MaxDistance]
+
+ for i, v := range q.table {
+ newV := max(int(v)-delta, 0)
+ q.table[i] = uint32(newV)
+ }
+ }
+
+ // Append src to the history buffer.
+ historyLen := len(q.history)
+ q.history = append(q.history, src...)
+ q.chain = append(q.chain, make([]uint32, len(src))...)
+ src = q.history
+
+ // Calculate hashes and build the chain.
+ for i := historyLen; i < len(src)-7; i++ {
+ h := ((binary.LittleEndian.Uint64(src[i:]) & (1<<(8*q.HashLen) - 1)) * hashMul64) >> (64 - q.TableBits)
+ candidate := int(q.table[h])
+ q.table[h] = uint32(i)
+ if candidate != 0 {
+ delta := i - candidate
+ q.chain[i] = uint32(delta)
+ }
+ }
+
+ // Look for matches, and collect them in foundMatches. Later we'll figure out
+ // which ones to actually use.
+ foundMatches := q.foundMatches[:0]
+ var prevMatch absoluteMatch
+ i := historyLen
+ for i < len(src)-7 {
+ delta := q.chain[i]
+ if delta == 0 {
+ i++
+ continue
+ }
+ candidate := i - int(delta)
+ if candidate <= 0 || i-candidate > q.MaxDistance {
+ i++
+ continue
+ }
+
+ var currentMatch absoluteMatch
+
+ if i >= prevMatch.End && prevMatch != (absoluteMatch{}) {
+ // Look for a repeat match at i+1.
+ prevDistance := prevMatch.Start - prevMatch.Match
+ if binary.LittleEndian.Uint32(src[i+1:]) == binary.LittleEndian.Uint32(src[i+1-prevDistance:]) {
+ m := extendMatch2(src, i+1, i+1-prevDistance, i+1)
+ if m.End-m.Start > q.MinLength {
+ currentMatch = m
+ foundMatches = append(foundMatches, m)
+ }
+ }
+ }
+
+ if binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {
+ m := extendMatch2(src, i, candidate, max(historyLen, prevMatch.Start))
+ if m.End-m.Start > q.MinLength {
+ currentMatch = m
+ foundMatches = append(foundMatches, m)
+ }
+ }
+
+ for range q.ChainLength {
+ delta := q.chain[candidate]
+ if delta == 0 {
+ break
+ }
+ candidate -= int(delta)
+ if candidate <= 0 || i-candidate > q.MaxDistance {
+ break
+ }
+ if binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {
+ m := extendMatch2(src, i, candidate, max(historyLen, prevMatch.Start))
+ if m.End-m.Start > q.MinLength && m.End-m.Start > currentMatch.End-currentMatch.Start {
+ currentMatch = m
+ foundMatches = append(foundMatches, m)
+ }
+ }
+ }
+
+ if i < prevMatch.End && currentMatch.End-currentMatch.Start <= prevMatch.End-prevMatch.Start {
+ // We were looking for an overlapping match, but we didn't find one longer
+ // than the previous match. So we'll go back to sequential search,
+ // starting right after the previous match.
+ i = prevMatch.End
+ continue
+ }
+
+ if currentMatch == (absoluteMatch{}) {
+ // No match found. Continue with sequential search.
+ i++
+ continue
+ }
+
+ // We've found a match; now look for matches overlapping the end of it.
+ prevMatch = currentMatch
+ i = currentMatch.End + 2 - q.HashLen
+ }
+
+ q.foundMatches = foundMatches
+
+ slices.SortFunc(foundMatches, func(a, b absoluteMatch) int { return a.Start - b.Start })
+ matchIndex := 0
+ var pending absoluteMatch
+
+ for i := historyLen; i < len(src); i++ {
+ var arrivedHere arrival
+ if i > historyLen {
+ arrivedHere = arrivals[i-historyLen-1]
+ }
+
+ unmatched := 0
+ if arrivedHere.distance == 0 {
+ unmatched = int(arrivedHere.length)
+ }
+ prevDistance := 0
+ if i-unmatched > historyLen {
+ prevDistance = int(arrivals[i-historyLen-1-unmatched].distance)
+ }
+
+ literalCost := byteCost[src[i]]
+ nextArrival := &arrivals[i-historyLen]
+ if nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {
+ *nextArrival = arrival{
+ cost: arrivedHere.cost + literalCost,
+ length: uint32(unmatched + 1),
+ }
+ }
+
+ for matchIndex < len(foundMatches) && foundMatches[matchIndex].Start == i {
+ m := foundMatches[matchIndex]
+ matchIndex++
+ if m.End > pending.End {
+ pending = m
+ }
+ matchCost := baseMatchCost + float32(bits.Len(uint(unmatched)))
+ if m.Start-m.Match != prevDistance {
+ matchCost += float32(bits.Len(uint(m.Start - m.Match)))
+ }
+ for j := m.Start + q.MinLength; j <= m.End; j++ {
+ adjustedCost := matchCost
+ if j-m.Start < 6 {
+ // Matches shorter than 6 are comparatively rare, and therefore
+ // have longer codes.
+ adjustedCost += float32(6-(j-m.Start)) * 2
+ }
+ a := &arrivals[j-historyLen-1]
+ if a.cost == 0 || arrivedHere.cost+adjustedCost < a.cost {
+ *a = arrival{
+ length: uint32(j - m.Start),
+ distance: uint32(m.Start - m.Match),
+ cost: arrivedHere.cost + adjustedCost,
+ }
+ }
+ }
+ }
+
+ // If a match from an earlier position extends far enough past the current
+ // position, try using the tail of it, starting from here.
+ if unmatched == 0 && pending.Start != i && pending.End >= i+q.MinLength &&
+ !(arrivedHere.length != 0 && arrivedHere.distance == uint32(pending.Start-pending.Match)) {
+ matchCost := baseMatchCost + float32(bits.Len(uint(pending.Start-pending.Match)))
+ for j := i + q.MinLength; j <= pending.End; j++ {
+ adjustedCost := matchCost
+ if j-i < 6 {
+ // Matches shorter than 6 are comparatively rare, and therefore
+ // have longer codes.
+ adjustedCost += float32(6-(j-i)) * 2
+ }
+ a := &arrivals[j-historyLen-1]
+ if a.cost == 0 || arrivedHere.cost+adjustedCost < a.cost {
+ *a = arrival{
+ length: uint32(j - i),
+ distance: uint32(pending.Start - pending.Match),
+ cost: arrivedHere.cost + adjustedCost,
+ }
+ }
+ }
+ }
+
+ delta := q.chain[i]
+ if delta == 0 {
+ continue
+ }
+ candidate := i - int(delta)
+ if candidate <= 0 || i-candidate > q.MaxDistance {
+ continue
+ }
+ }
+
+ // We've found the shortest path; now walk it backward and store the matches.
+ matches := q.matches[:0]
+ i = len(arrivals) - 1
+ for i >= 0 {
+ a := arrivals[i]
+ if a.distance > 0 {
+ matches = append(matches, Match{
+ Length: int(a.length),
+ Distance: int(a.distance),
+ })
+ i -= int(a.length)
+ } else {
+ if len(matches) == 0 {
+ matches = append(matches, Match{})
+ }
+ matches[len(matches)-1].Unmatched = int(a.length)
+ i -= int(a.length)
+ }
+ }
+ q.matches = matches
+
+ slices.Reverse(matches)
+
+ return append(dst, matches...)
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/textencoder.go b/vendor/github.com/andybalholm/brotli/matchfinder/textencoder.go
new file mode 100644
index 00000000..75ecc590
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/textencoder.go
@@ -0,0 +1,53 @@
+package matchfinder
+
+import "fmt"
+
+// A TextEncoder is an Encoder that produces a human-readable representation of
+// the LZ77 compression. Matches are replaced with symbols.
+type TextEncoder struct{}
+
+func (t TextEncoder) Reset() {}
+
+func (t TextEncoder) Encode(dst []byte, src []byte, matches []Match, lastBlock bool) []byte {
+ pos := 0
+ for _, m := range matches {
+ if m.Unmatched > 0 {
+ dst = append(dst, src[pos:pos+m.Unmatched]...)
+ pos += m.Unmatched
+ }
+ if m.Length > 0 {
+ dst = append(dst, []byte(fmt.Sprintf("<%d,%d>", m.Length, m.Distance))...)
+ pos += m.Length
+ }
+ }
+ if pos < len(src) {
+ dst = append(dst, src[pos:]...)
+ }
+ return dst
+}
+
+// A NoMatchFinder implements MatchFinder, but doesn't find any matches.
+// It can be used to implement the equivalent of the standard library flate package's
+// HuffmanOnly setting.
+type NoMatchFinder struct{}
+
+func (n NoMatchFinder) Reset() {}
+
+func (n NoMatchFinder) FindMatches(dst []Match, src []byte) []Match {
+ return append(dst, Match{
+ Unmatched: len(src),
+ })
+}
+
+// AutoReset wraps a MatchFinder that can return references to data in previous
+// blocks, and calls Reset before each block. It is useful for (e.g.) using a
+// snappy Encoder with a MatchFinder designed for flate. (Snappy doesn't
+// support references between blocks.)
+type AutoReset struct {
+ MatchFinder
+}
+
+func (a AutoReset) FindMatches(dst []Match, src []byte) []Match {
+ a.Reset()
+ return a.MatchFinder.FindMatches(dst, src)
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/trio.go b/vendor/github.com/andybalholm/brotli/matchfinder/trio.go
new file mode 100644
index 00000000..cb33e64a
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/trio.go
@@ -0,0 +1,326 @@
+package matchfinder
+
+import "encoding/binary"
+
+// Trio is a MatchFinder that uses 3 different hash lengths, and
+// overlap parsing.
+type Trio struct {
+ MaxDistance int
+ history []byte
+ table5 [1 << 16]tableEntry
+ table8 [1 << 17]tableEntry
+ table12 [1 << 18]tableEntry
+}
+
+func (z *Trio) Reset() {
+ z.table5 = [len(z.table5)]tableEntry{}
+ z.table8 = [len(z.table8)]tableEntry{}
+ z.table12 = [len(z.table12)]tableEntry{}
+ z.history = z.history[:0]
+}
+
+func (z *Trio) FindMatches(dst []Match, src []byte) []Match {
+ if z.MaxDistance == 0 {
+ z.MaxDistance = 1 << 16
+ }
+
+ if len(z.history) > z.MaxDistance*2 {
+ delta := len(z.history) - z.MaxDistance
+ copy(z.history, z.history[delta:])
+ z.history = z.history[:z.MaxDistance]
+
+ for i := range z.table5 {
+ v := z.table5[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table5[i] = tableEntry{}
+ } else {
+ z.table5[i].offset = v
+ }
+ }
+ for i := range z.table8 {
+ v := z.table8[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table8[i] = tableEntry{}
+ } else {
+ z.table8[i].offset = v
+ }
+ }
+ for i := range z.table12 {
+ v := z.table12[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table12[i] = tableEntry{}
+ } else {
+ z.table12[i].offset = v
+ }
+ }
+ }
+
+ if len(src) < 20 {
+ return append(dst, Match{
+ Unmatched: len(src),
+ })
+ }
+
+ e := matchEmitter{
+ Dst: dst,
+ NextEmit: len(z.history),
+ }
+ z.history = append(z.history, src...)
+ src = z.history
+
+ // matches stores the matches that have been found but not emitted,
+ // in reverse order. (matches[0] is the most recent one.)
+ var matches [3]absoluteMatch
+
+ sLimit := int32(len(src)) - 14
+
+mainLoop:
+ for {
+ // Search for a match, starting after the last match emitted.
+ s := int32(e.NextEmit)
+ if s > sLimit {
+ break mainLoop
+ }
+
+ // t will contain the match offset when we find one.
+ var t int32
+ var hashLengthFound int
+
+ cv := binary.LittleEndian.Uint64(src[s:])
+ extra := binary.LittleEndian.Uint32(src[s+8:])
+
+ for {
+ nextHash12 := z.hash12(cv, extra)
+ nextHash8 := z.hash8(cv)
+ nextHash5 := z.hash5(cv)
+ candidate12 := z.table12[nextHash12]
+ candidate8 := z.table8[nextHash8]
+ candidate5 := z.table5[nextHash5]
+
+ entry := tableEntry{offset: s, val: uint32(cv)}
+ z.table12[nextHash12] = entry
+ z.table8[nextHash8] = entry
+ z.table5[nextHash5] = entry
+
+ // Look for a repeat match one byte after the current position.
+ if len(e.Dst) > 0 {
+ prevDistance := int32(e.Dst[len(e.Dst)-1].Distance)
+ if prevDistance != 0 {
+ repIndex := s - prevDistance + 1
+ if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>8) {
+ // There is a repeated match at s+2.
+ s++
+ t = repIndex
+ break
+ }
+ }
+ }
+
+ if candidate12.offset < s && s-candidate12.offset < int32(z.MaxDistance) && uint32(cv) == candidate12.val &&
+ binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+ // There is a 12-byte match at s.
+ t = candidate12.offset
+ hashLengthFound = 12
+ break
+ }
+ if candidate8.offset < s && s-candidate8.offset < int32(z.MaxDistance) && uint32(cv) == candidate8.val &&
+ binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+ t = candidate8.offset
+ hashLengthFound = 8
+ break
+ }
+ if candidate5.offset < s && s-candidate5.offset < int32(z.MaxDistance) && uint32(cv) == candidate5.val &&
+ binary.LittleEndian.Uint32(src[candidate5.offset:]) == uint32(cv) {
+ t = candidate5.offset
+ hashLengthFound = 5
+ break
+ }
+
+ s += 1 + ((s - int32(e.NextEmit)) >> 7)
+ if s > sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ extra = binary.LittleEndian.Uint32(src[s+8:])
+ }
+
+ if hashLengthFound != 0 && hashLengthFound < 12 {
+ // Look for a "lazy" match with a longer hash at s+1.
+ cv := binary.LittleEndian.Uint64(src[s+1:])
+ extra := binary.LittleEndian.Uint32(src[s+9:])
+ nextHash12 := z.hash12(cv, extra)
+ nextHash8 := z.hash8(cv)
+ candidate12 := z.table12[nextHash12]
+ candidate8 := z.table8[nextHash8]
+ coffset12 := s - candidate12.offset + 1
+ coffset8 := s - candidate8.offset + 1
+ entry := tableEntry{offset: s + 1, val: uint32(cv)}
+ z.table12[nextHash12] = entry
+ z.table8[nextHash8] = entry
+ if candidate12.offset < s+1 && coffset12 < int32(z.MaxDistance) && uint32(cv) == candidate12.val &&
+ binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+ t = candidate12.offset
+ s++
+ } else if hashLengthFound < 8 && candidate8.offset < s+1 && coffset8 < int32(z.MaxDistance) && uint32(cv) == candidate8.val &&
+ binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+ t = candidate8.offset
+ s++
+ }
+ }
+
+ currentMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+ matches[0] = currentMatch
+
+ index0 := s + 1
+
+ // We have a match in matches[0].
+ // Now look for overlapping matches.
+
+ for {
+ if matches[0].End > int(sLimit) {
+ break
+ }
+ s = int32(max(matches[0].Start+2, matches[0].End-10))
+
+ // Store some entries that haven't been indexed yet.
+ for index0 < s-1 {
+ cv0 := binary.LittleEndian.Uint64(src[index0:])
+ extra0 := binary.LittleEndian.Uint32(src[index0+8:])
+ te0 := tableEntry{offset: index0, val: uint32(cv0)}
+ z.table5[z.hash5(cv0)] = te0
+ z.table8[z.hash8(cv0)] = te0
+ z.table12[z.hash12(cv0, extra0)] = te0
+ index0++
+ }
+
+ cv = binary.LittleEndian.Uint64(src[s:])
+ extra = binary.LittleEndian.Uint32(src[s+8:])
+
+ nextHash12 := z.hash12(cv, extra)
+ nextHash8 := z.hash8(cv)
+ nextHash5 := z.hash5(cv)
+ candidate12 := z.table12[nextHash12]
+ candidate8 := z.table8[nextHash8]
+
+ entry := tableEntry{offset: s, val: uint32(cv)}
+ z.table12[nextHash12] = entry
+ z.table8[nextHash8] = entry
+ z.table5[nextHash5] = entry
+
+ t = -1
+ if candidate12.offset < s && s-candidate12.offset < int32(z.MaxDistance) && uint32(cv) == candidate12.val &&
+ binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+ // There is a 12-byte match at s.
+ t = candidate12.offset
+ } else if candidate8.offset < s && s-candidate8.offset < int32(z.MaxDistance) && uint32(cv) == candidate8.val &&
+ binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+ // There is a long match at s.
+ t = candidate8.offset
+ }
+
+ index0 = s + 1
+
+ if t == -1 {
+ // No overlapping match was found.
+ break
+ }
+
+ newMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+
+ if newMatch.End-newMatch.Start <= matches[0].End-matches[0].Start {
+ // The new match isn't longer than the old one, so we break out of the loop
+ // of looking for overlapping matches.
+ break
+ }
+
+ matches = [3]absoluteMatch{
+ newMatch,
+ matches[0],
+ matches[1],
+ }
+
+ if matches[2] == (absoluteMatch{}) {
+ continue
+ }
+
+ // We have three matches, so it's time to emit one and/or eliminate one.
+ switch {
+ case matches[0].Start < matches[2].End:
+ // The first and third matches overlap; discard the one in between.
+ matches = [3]absoluteMatch{
+ matches[0],
+ matches[2],
+ {},
+ }
+
+ case matches[0].Start < matches[2].End+4:
+ // The first and third matches don't overlap, but there's no room for
+ // another match between them. Emit the first match and discard the second.
+ e.emit(matches[2])
+ matches = [3]absoluteMatch{
+ matches[0],
+ {},
+ {},
+ }
+
+ default:
+ // Emit the first match, shortening it if necessary to avoid overlap with the second.
+ if matches[2].End > matches[1].Start {
+ matches[2].End = matches[1].Start
+ }
+ if matches[2].End-matches[2].Start >= 4 {
+ e.emit(matches[2])
+ }
+ matches[2] = absoluteMatch{}
+ }
+ }
+
+ // Store some entries up to the end of the last match.
+ for index0 < int32(matches[0].End) && index0 < sLimit {
+ cv0 := binary.LittleEndian.Uint64(src[index0:])
+ extra0 := binary.LittleEndian.Uint32(src[index0+8:])
+ te0 := tableEntry{offset: index0, val: uint32(cv0)}
+ z.table5[z.hash5(cv0)] = te0
+ z.table8[z.hash8(cv0)] = te0
+ z.table12[z.hash12(cv0, extra0)] = te0
+ index0++
+ }
+
+ // We're done looking for overlapping matches; emit the ones we have.
+
+ if matches[1] != (absoluteMatch{}) {
+ if matches[1].End > matches[0].Start {
+ matches[1].End = matches[0].Start
+ }
+ if matches[1].End-matches[1].Start >= 4 {
+ e.emit(matches[1])
+ }
+ }
+ e.emit(matches[0])
+ matches = [3]absoluteMatch{}
+ }
+
+ dst = e.Dst
+ if e.NextEmit < len(src) {
+ dst = append(dst, Match{
+ Unmatched: len(src) - e.NextEmit,
+ })
+ }
+
+ return dst
+}
+
+func (z *Trio) hash5(u uint64) uint32 {
+ return uint32(((u << 24) * 889523592379) >> (64 - 16))
+}
+
+func (z *Trio) hash8(u uint64) uint32 {
+ return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - 17))
+}
+
+func (z *Trio) hash12(u uint64, e uint32) uint32 {
+ return uint32((u*0xcf1bbcdcb7a56463 + uint64(e)*(2654435761<<32)) >> (64 - 18))
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/zdfast.go b/vendor/github.com/andybalholm/brotli/matchfinder/zdfast.go
new file mode 100644
index 00000000..6890409b
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/zdfast.go
@@ -0,0 +1,258 @@
+package matchfinder
+
+import (
+ "encoding/binary"
+ "math"
+)
+
+const (
+ zdfastLongTableBits = 17
+ zdfastLongTableSize = 1 << zdfastLongTableBits
+)
+
+// ZDFast is a MatchFinder based on the "Default" setting in
+// github.com/klauspost/compress/zstd.
+type ZDFast struct {
+ MaxDistance int
+
+ history []byte
+ // current is the offset at the start of history
+ current int32
+ table [zfastTableSize]tableEntry
+ longTable [zdfastLongTableSize]tableEntry
+}
+
+func (z *ZDFast) Reset() {
+ z.current = 0
+ z.table = [zfastTableSize]tableEntry{}
+ z.longTable = [zdfastLongTableSize]tableEntry{}
+ z.history = z.history[:0]
+}
+
+func (z *ZDFast) FindMatches(dst []Match, src []byte) []Match {
+ if z.MaxDistance == 0 {
+ z.MaxDistance = 1 << 16
+ }
+
+ // Protect against overflow of current.
+ if int(z.current) >= int(math.MaxInt32)-2*z.MaxDistance-len(z.history) {
+ minOffset := z.current + int32(len(z.history)) - int32(z.MaxDistance)
+ for i := range z.table {
+ v := z.table[i].offset
+ if v < minOffset {
+ v = 0
+ } else {
+ v = v - z.current + int32(z.MaxDistance)
+ }
+ z.table[i].offset = v
+ }
+ for i := range z.longTable {
+ v := z.longTable[i].offset
+ if v < minOffset {
+ v = 0
+ } else {
+ v = v - z.current + int32(z.MaxDistance)
+ }
+ z.longTable[i].offset = v
+ }
+ z.current = int32(z.MaxDistance)
+ }
+
+ if len(z.history)+len(src) > cap(z.history) {
+ // history doesn't have enough capacity to hold the new block.
+ if cap(z.history) == 0 {
+ historySize := max(2*z.MaxDistance, 1<<20, len(src))
+ z.history = make([]byte, 0, historySize)
+ } else {
+ // Move down
+ offset := len(z.history) - z.MaxDistance
+ copy(z.history[:z.MaxDistance], z.history[offset:])
+ z.current += int32(offset)
+ z.history = z.history[:z.MaxDistance]
+ }
+ }
+ s := int32(len(z.history))
+ z.history = append(z.history, src...)
+
+ if len(src) < 16 {
+ return append(dst, Match{
+ Unmatched: len(src),
+ })
+ }
+
+ src = z.history
+ sLimit := int32(len(src)) - 10
+
+ const stepSize = 1
+
+ nextEmit := s
+ cv := binary.LittleEndian.Uint64(src[s:])
+ var offset1, offset2 int32
+
+mainLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When exiting the search loop, we have already checked 4 bytes.
+ var t int32
+
+ for {
+ nextHashL := z.hashLong(cv)
+ nextHashS := z.hashShort(cv)
+ candidateL := z.longTable[nextHashL]
+ candidateS := z.table[nextHashS]
+
+ repIndex := s - offset1 + 1
+
+ entry := tableEntry{offset: s + z.current, val: uint32(cv)}
+ z.longTable[nextHashL] = entry
+ z.table[nextHashS] = entry
+
+ if offset1 != 0 && repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>8) {
+ // There is a repeated match at s+1.
+ end := extendMatch(src, int(repIndex+4), int(s+5))
+ start := s + 1
+ for repIndex > 0 && start > nextEmit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ }
+
+ dst = append(dst, Match{
+ Unmatched: int(start - nextEmit),
+ Length: end - int(start),
+ Distance: int(start - repIndex),
+ })
+ s = int32(end)
+ nextEmit = s
+ if s >= sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ continue
+ }
+
+ coffsetL := s - (candidateL.offset - z.current)
+ coffsetS := s - (candidateS.offset - z.current)
+ if coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val {
+ t = candidateL.offset - z.current
+ if binary.LittleEndian.Uint32(src[t:]) == uint32(cv) {
+ // found a long match (likely at least 8 bytes)
+ break
+ }
+ }
+ if coffsetS < int32(z.MaxDistance) && uint32(cv) == candidateS.val {
+ t = candidateS.offset - z.current
+ if binary.LittleEndian.Uint32(src[t:]) != uint32(cv) {
+ goto noMatch
+ }
+ // Found a regular match.
+ // See if we can find a long match at s+1
+ cv := binary.LittleEndian.Uint64(src[s+1:])
+ nextHashL = z.hashLong(cv)
+ candidateL = z.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - z.current) + 1
+ z.longTable[nextHashL] = tableEntry{offset: s + 1 + z.current, val: uint32(cv)}
+ if coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val {
+ t = candidateL.offset - z.current
+ if binary.LittleEndian.Uint32(src[t:]) == uint32(cv) {
+ // We found a long match at s+1, so we'll use that instead
+ // of the regular match at s.
+ s++
+ break
+ }
+ }
+
+ t = candidateS.offset - z.current
+ break
+ }
+ noMatch:
+
+ s += stepSize + ((s - nextEmit) >> 7)
+ if s > sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ }
+
+ // A 4-byte match has been found. We'll later see if more than
+ // 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ end := extendMatch(src, int(t+4), int(s+4))
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ }
+
+ dst = append(dst, Match{
+ Unmatched: int(s - nextEmit),
+ Length: end - int(s),
+ Distance: int(s - t),
+ })
+ prevS := s
+ s = int32(end)
+ nextEmit = s
+ if s >= sLimit {
+ break mainLoop
+ }
+
+ // Store some table entries near the start and end of the match.
+ index0 := prevS + 1
+ index1 := s - 2
+ cv0 := binary.LittleEndian.Uint64(src[index0:])
+ cv1 := binary.LittleEndian.Uint64(src[index1:])
+ te0 := tableEntry{offset: index0 + z.current, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + z.current, val: uint32(cv1)}
+ z.longTable[z.hashLong(cv0)] = te0
+ z.longTable[z.hashLong(cv1)] = te1
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ z.table[z.hashShort(cv0)] = te0
+ z.table[z.hashShort(cv1)] = te1
+
+ cv = binary.LittleEndian.Uint64(src[s:])
+
+ // Check offset 2
+ if o2 := s - offset2; offset2 != 0 && binary.LittleEndian.Uint32(src[o2:]) == uint32(cv) {
+ end := extendMatch(src, int(o2+4), int(s+4))
+
+ // Store the hashes, since we have them.
+ nextHashS := z.hashShort(cv)
+ nextHashL := z.hashLong(cv)
+ entry := tableEntry{offset: s + z.current, val: uint32(cv)}
+ z.table[nextHashS] = entry
+ z.longTable[nextHashL] = entry
+ dst = append(dst, Match{
+ Length: end - int(s),
+ Distance: int(offset2),
+ })
+ s = int32(end)
+ nextEmit = s
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ dst = append(dst, Match{
+ Unmatched: len(src) - int(nextEmit),
+ })
+ }
+
+ return dst
+}
+
+func (z *ZDFast) hashShort(u uint64) uint32 {
+ return uint32(((u << 24) * 889523592379) >> (64 - zfastTableBits))
+}
+
+func (z *ZDFast) hashLong(u uint64) uint32 {
+ return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - zdfastLongTableBits))
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/zfast.go b/vendor/github.com/andybalholm/brotli/matchfinder/zfast.go
new file mode 100644
index 00000000..6f2ad8d0
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/zfast.go
@@ -0,0 +1,206 @@
+package matchfinder
+
+import (
+ "encoding/binary"
+ "math"
+)
+
+type tableEntry struct {
+ val uint32
+ offset int32
+}
+
+const (
+ zfastTableBits = 15
+ zfastTableSize = 1 << zfastTableBits
+ zfastHashLen = 6
+
+ prime6Bytes = 227718039650203
+)
+
+// ZFast is a MatchFinder based on the "Fastest" setting in
+// github.com/klauspost/compress/zstd.
+type ZFast struct {
+ MaxDistance int
+
+ history []byte
+ // current is the offset at the start of history
+ current int32
+ table [zfastTableSize]tableEntry
+}
+
+func (z *ZFast) Reset() {
+ z.current = 0
+ z.table = [zfastTableSize]tableEntry{}
+ z.history = z.history[:0]
+}
+
+func (z *ZFast) FindMatches(dst []Match, src []byte) []Match {
+ if z.MaxDistance == 0 {
+ z.MaxDistance = 1 << 16
+ }
+
+ // Protect against overflow of current.
+ if int(z.current) >= int(math.MaxInt32)-2*z.MaxDistance-len(z.history) {
+ minOffset := z.current + int32(len(z.history)) - int32(z.MaxDistance)
+ for i := range z.table {
+ v := z.table[i].offset
+ if v < minOffset {
+ v = 0
+ } else {
+ v = v - z.current + int32(z.MaxDistance)
+ }
+ z.table[i].offset = v
+ }
+ z.current = int32(z.MaxDistance)
+ }
+
+ if len(z.history)+len(src) > cap(z.history) {
+ // history doesn't have enough capacity to hold the new block.
+ if cap(z.history) == 0 {
+ historySize := max(2*z.MaxDistance, 1<<20, len(src))
+ z.history = make([]byte, 0, historySize)
+ } else {
+ // Move down
+ offset := len(z.history) - z.MaxDistance
+ copy(z.history[:z.MaxDistance], z.history[offset:])
+ z.current += int32(offset)
+ z.history = z.history[:z.MaxDistance]
+ }
+ }
+ s := int32(len(z.history))
+ z.history = append(z.history, src...)
+
+ if len(src) < 10 {
+ return append(dst, Match{
+ Unmatched: len(src),
+ })
+ }
+
+ src = z.history
+ sLimit := int32(len(src)) - 8
+
+ const stepSize = 2
+
+ nextEmit := s
+ cv := binary.LittleEndian.Uint64(src[s:])
+ var offset1, offset2 int32
+
+mainLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When exiting the search loop, we have already checked 4 bytes.
+ var t int32
+
+ for {
+ nextHash := z.hash(cv)
+ nextHash2 := z.hash(cv >> 8)
+ candidate := z.table[nextHash]
+ candidate2 := z.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ z.table[nextHash] = tableEntry{offset: s + z.current, val: uint32(cv)}
+ z.table[nextHash2] = tableEntry{offset: s + z.current + 1, val: uint32(cv >> 8)}
+
+ if offset1 != 0 && repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>16) {
+ // There is a repeated match at s+2.
+ end := extendMatch(src, int(repIndex+4), int(s+6))
+ start := s + 2
+ for repIndex > 0 && start > nextEmit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ }
+ dst = append(dst, Match{
+ Unmatched: int(start - nextEmit),
+ Length: end - int(start),
+ Distance: int(start - repIndex),
+ })
+ s = int32(end)
+ nextEmit = s
+ if s >= sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ continue
+ }
+
+ coffset0 := s - (candidate.offset - z.current)
+ coffset1 := s - (candidate2.offset - z.current) + 1
+ if coffset0 < int32(z.MaxDistance) && uint32(cv) == candidate.val {
+ t = candidate.offset - z.current
+ if binary.LittleEndian.Uint32(src[t:]) == uint32(cv) {
+ // found a regular match
+ break
+ }
+ }
+ if coffset1 < int32(z.MaxDistance) && uint32(cv>>8) == candidate2.val {
+ t = candidate2.offset - z.current
+ if binary.LittleEndian.Uint32(src[t:]) == uint32(cv>>8) {
+ s++
+ break
+ }
+ }
+
+ s += stepSize + ((s - nextEmit) >> 5)
+ if s > sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ }
+
+ // A 4-byte match has been found. We'll later see if more than
+ // 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ end := extendMatch(src, int(t+4), int(s+4))
+ for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ }
+
+ dst = append(dst, Match{
+ Unmatched: int(s - nextEmit),
+ Length: end - int(s),
+ Distance: int(s - t),
+ })
+ s = int32(end)
+ nextEmit = s
+ if s >= sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+
+ // Check offset 2
+ if o2 := s - offset2; offset2 != 0 && binary.LittleEndian.Uint32(src[o2:]) == uint32(cv) {
+ end := extendMatch(src, int(o2+4), int(s+4))
+
+ // Store the hash, since we have it.
+ nextHash := z.hash(cv)
+ z.table[nextHash] = tableEntry{offset: s + z.current, val: uint32(cv)}
+ dst = append(dst, Match{
+ Length: end - int(s),
+ Distance: int(offset2),
+ })
+ s = int32(end)
+ nextEmit = s
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ dst = append(dst, Match{
+ Unmatched: len(src) - int(nextEmit),
+ })
+ }
+
+ return dst
+}
+
+func (z *ZFast) hash(u uint64) uint32 {
+ return uint32(((u << 16) * prime6Bytes) >> (64 - zfastTableBits))
+}
diff --git a/vendor/github.com/andybalholm/brotli/matchfinder/zm.go b/vendor/github.com/andybalholm/brotli/matchfinder/zm.go
new file mode 100644
index 00000000..59a920c3
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/matchfinder/zm.go
@@ -0,0 +1,301 @@
+package matchfinder
+
+import "encoding/binary"
+
+const (
+ zmTableBits = 15
+ zmTableSize = 1 << zmTableBits
+ zmLongTableBits = 17
+ zmLongTableSize = 1 << zmLongTableBits
+)
+
+// ZM is a MatchFinder that combines the cache tables of ZDFast with the
+// overlap-based parsing of M4.
+type ZM struct {
+ MaxDistance int
+ history []byte
+ table [zmTableSize]tableEntry
+ longTable [zmLongTableSize]tableEntry
+}
+
+func (z *ZM) Reset() {
+ z.table = [zmTableSize]tableEntry{}
+ z.longTable = [zmLongTableSize]tableEntry{}
+ z.history = z.history[:0]
+}
+
+func (z *ZM) FindMatches(dst []Match, src []byte) []Match {
+ if z.MaxDistance == 0 {
+ z.MaxDistance = 1 << 16
+ }
+
+ if len(z.history) > z.MaxDistance*2 {
+ delta := len(z.history) - z.MaxDistance
+ copy(z.history, z.history[delta:])
+ z.history = z.history[:z.MaxDistance]
+
+ for i := range z.table {
+ v := z.table[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.table[i] = tableEntry{}
+ } else {
+ z.table[i].offset = v
+ }
+ }
+ for i := range z.longTable {
+ v := z.longTable[i].offset
+ v -= int32(delta)
+ if v < 0 {
+ z.longTable[i] = tableEntry{}
+ } else {
+ z.longTable[i].offset = v
+ }
+ }
+ }
+
+ if len(src) < 16 {
+ return append(dst, Match{
+ Unmatched: len(src),
+ })
+ }
+
+ e := matchEmitter{
+ Dst: dst,
+ NextEmit: len(z.history),
+ }
+ z.history = append(z.history, src...)
+ src = z.history
+
+ // matches stores the matches that have been found but not emitted,
+ // in reverse order. (matches[0] is the most recent one.)
+ var matches [3]absoluteMatch
+
+ sLimit := int32(len(src)) - 10
+
+mainLoop:
+ for {
+ // Search for a match, starting after the last match emitted.
+ s := int32(e.NextEmit)
+ if s > sLimit {
+ break mainLoop
+ }
+
+ // t will contain the match offset when we find one.
+ var t int32
+
+ cv := binary.LittleEndian.Uint64(src[s:])
+
+ for {
+ nextHashL := z.hashLong(cv)
+ nextHashS := z.hashShort(cv)
+ candidateL := z.longTable[nextHashL]
+ candidateS := z.table[nextHashS]
+
+ entry := tableEntry{offset: s, val: uint32(cv)}
+ z.longTable[nextHashL] = entry
+ z.table[nextHashS] = entry
+
+ // Look for a repeat match one byte after the current position.
+ if len(e.Dst) > 0 {
+ prevDistance := int32(e.Dst[len(e.Dst)-1].Distance)
+ if prevDistance != 0 {
+ repIndex := s - prevDistance + 1
+ if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>8) {
+ // There is a repeated match at s+2.
+ s++
+ t = repIndex
+ break
+ }
+ }
+ }
+
+ if candidateL.offset < s && s-candidateL.offset < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+ binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+ // There is a long match at s.
+ t = candidateL.offset
+ break
+ }
+ if candidateS.offset < s && s-candidateS.offset < int32(z.MaxDistance) && uint32(cv) == candidateS.val &&
+ binary.LittleEndian.Uint32(src[candidateS.offset:]) == uint32(cv) {
+ // There is a regular match at s.
+ // See if we can find a long match at s+1.
+ cv := binary.LittleEndian.Uint64(src[s+1:])
+ nextHashL = z.hashLong(cv)
+ candidateL = z.longTable[nextHashL]
+ coffsetL := s - candidateL.offset + 1
+ z.longTable[nextHashL] = tableEntry{offset: s + 1, val: uint32(cv)}
+ if candidateL.offset < s+1 && coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+ binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+ // We found a long match at s+1, so we'll use that instead
+ // of the regular match at s.
+ t = candidateL.offset
+ s++
+ break
+ }
+
+ t = candidateS.offset
+ break
+ }
+
+ s += 1 + ((s - int32(e.NextEmit)) >> 7)
+ if s > sLimit {
+ break mainLoop
+ }
+ cv = binary.LittleEndian.Uint64(src[s:])
+ }
+
+ currentMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+ matches[0] = currentMatch
+
+ // Store some table entries after s.
+ index0 := s + 1
+ cv0 := binary.LittleEndian.Uint64(src[index0:])
+ te0 := tableEntry{offset: index0, val: uint32(cv0)}
+ z.longTable[z.hashLong(cv0)] = te0
+ cv0 >>= 8
+ te0.offset++
+ te0.val = uint32(cv0)
+ z.table[z.hashShort(cv0)] = te0
+
+ // We have a match in matches[0].
+ // Now look for overlapping matches.
+
+ for {
+ if matches[0].End > int(sLimit) {
+ break
+ }
+ s = int32(max(matches[0].Start+2, matches[0].End-6))
+ cv = binary.LittleEndian.Uint64(src[s:])
+
+ nextHashL := z.hashLong(cv)
+ nextHashS := z.hashShort(cv)
+ candidateL := z.longTable[nextHashL]
+ candidateS := z.table[nextHashS]
+
+ entry := tableEntry{offset: s, val: uint32(cv)}
+ z.longTable[nextHashL] = entry
+ z.table[nextHashS] = entry
+
+ t = -1
+ if candidateL.offset < s && s-candidateL.offset < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+ binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+ // There is a long match at s.
+ t = candidateL.offset
+ } else if candidateS.offset < s && s-candidateS.offset < int32(z.MaxDistance) && uint32(cv) == candidateS.val &&
+ binary.LittleEndian.Uint32(src[candidateS.offset:]) == uint32(cv) {
+ // There is a regular match at s.
+ t = candidateS.offset
+ // See if we can find a long match at s+1.
+ cv := binary.LittleEndian.Uint64(src[s+1:])
+ nextHashL = z.hashLong(cv)
+ candidateL = z.longTable[nextHashL]
+ coffsetL := s - candidateL.offset + 1
+ z.longTable[nextHashL] = tableEntry{offset: s + 1, val: uint32(cv)}
+ if candidateL.offset < s+1 && coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+ binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+ // We found a long match at s+1, so we'll use that instead
+ // of the regular match at s.
+ t = candidateL.offset
+ s++
+ }
+ }
+
+ if t == -1 {
+ // No overlapping match was found.
+ break
+ }
+
+ newMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+
+ if newMatch.End-newMatch.Start <= matches[0].End-matches[0].Start {
+ // The new match isn't longer than the old one, so we break out of the loop
+ // of looking for overlapping matches.
+ break
+ }
+
+ matches = [3]absoluteMatch{
+ newMatch,
+ matches[0],
+ matches[1],
+ }
+
+ if matches[2] == (absoluteMatch{}) {
+ continue
+ }
+
+ // We have three matches, so it's time to emit one and/or eliminate one.
+ switch {
+ case matches[0].Start < matches[2].End:
+ // The first and third matches overlap; discard the one in between.
+ matches = [3]absoluteMatch{
+ matches[0],
+ matches[2],
+ {},
+ }
+
+ case matches[0].Start < matches[2].End+4:
+ // The first and third matches don't overlap, but there's no room for
+ // another match between them. Emit the first match and discard the second.
+ e.emit(matches[2])
+ matches = [3]absoluteMatch{
+ matches[0],
+ {},
+ {},
+ }
+
+ default:
+ // Emit the first match, shortening it if necessary to avoid overlap with the second.
+ if matches[2].End > matches[1].Start {
+ matches[2].End = matches[1].Start
+ }
+ if matches[2].End-matches[2].Start >= 4 {
+ e.emit(matches[2])
+ }
+ matches[2] = absoluteMatch{}
+ }
+ }
+
+ // Store some table entries at the end of the last match.
+ index1 := int32(matches[0].End - 2)
+ if index1 < sLimit {
+ cv1 := binary.LittleEndian.Uint64(src[index1:])
+ te1 := tableEntry{offset: index1, val: uint32(cv1)}
+ z.longTable[z.hashLong(cv1)] = te1
+ cv1 >>= 8
+ te1.offset++
+ te1.val = uint32(cv1)
+ z.table[z.hashShort(cv1)] = te1
+ }
+
+ // We're done looking for overlapping matches; emit the ones we have.
+
+ if matches[1] != (absoluteMatch{}) {
+ if matches[1].End > matches[0].Start {
+ matches[1].End = matches[0].Start
+ }
+ if matches[1].End-matches[1].Start >= 4 {
+ e.emit(matches[1])
+ }
+ }
+ e.emit(matches[0])
+ matches = [3]absoluteMatch{}
+ }
+
+ dst = e.Dst
+ if e.NextEmit < len(src) {
+ dst = append(dst, Match{
+ Unmatched: len(src) - e.NextEmit,
+ })
+ }
+
+ return dst
+}
+
+func (z *ZM) hashShort(u uint64) uint32 {
+ return uint32(((u << 24) * 889523592379) >> (64 - zmTableBits))
+}
+
+func (z *ZM) hashLong(u uint64) uint32 {
+ return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - zmLongTableBits))
+}
diff --git a/vendor/github.com/andybalholm/brotli/memory.go b/vendor/github.com/andybalholm/brotli/memory.go
new file mode 100644
index 00000000..a07c7050
--- /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 00000000..3014df8c
--- /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 00000000..46459723
--- /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 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 00000000..90837294
--- /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 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 00000000..1c8b235b
--- /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 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 00000000..0a4c6875
--- /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 00000000..4ebfb152
--- /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 00000000..484df0d6
--- /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 00000000..183f0d53
--- /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 00000000..49709a38
--- /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 00000000..3e227893
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/reader.go
@@ -0,0 +1,111 @@
+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 == io.EOF && r.state != stateDone {
+ readErr = io.ErrUnexpectedEOF
+ }
+ // 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 00000000..1c8f86fe
--- /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 00000000..38d753eb
--- /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 00000000..bc05566d
--- /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 00000000..b33963e9
--- /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 00000000..c5cb49e5
--- /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 00000000..d2c043a6
--- /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 00000000..3244247e
--- /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 00000000..a84553a6
--- /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 00000000..87299011
--- /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 00000000..ce8b80fd
--- /dev/null
+++ b/vendor/github.com/andybalholm/brotli/writer.go
@@ -0,0 +1,162 @@
+package brotli
+
+import (
+ "errors"
+ "io"
+
+ "github.com/andybalholm/brotli/matchfinder"
+)
+
+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 }
+
+// NewWriterV2 is like NewWriterLevel, but it uses the new implementation
+// based on the matchfinder package. It currently supports up to level 9;
+// if a higher level is specified, level 9 will be used.
+func NewWriterV2(dst io.Writer, level int) *matchfinder.Writer {
+ if level < 0 {
+ level = 0
+ } else if level > 9 {
+ level = 9
+ }
+ var mf matchfinder.MatchFinder
+ switch level {
+ case 0, 1:
+ mf = &matchfinder.ZFast{MaxDistance: 1 << 20}
+ case 2:
+ mf = &matchfinder.ZDFast{MaxDistance: 1 << 20}
+ case 3:
+ mf = &matchfinder.ZM{MaxDistance: 1 << 20}
+ case 4:
+ mf = &matchfinder.Trio{MaxDistance: 1 << 20}
+ case 5, 6:
+ mf = &matchfinder.Bargain1{MaxDistance: 1 << 20}
+ case 7:
+ mf = &matchfinder.Bargain2{MaxDistance: 1 << 20, Skip: true}
+ case 8:
+ mf = &matchfinder.Bargain2{MaxDistance: 1 << 20}
+ case 9:
+ mf = &matchfinder.Bargain3{MaxDistance: 1 << 20}
+ }
+
+ w := &matchfinder.Writer{
+ Dest: dst,
+ MatchFinder: mf,
+ Encoder: &Encoder{},
+ BlockSize: 1 << 16,
+ }
+ if level < 1 {
+ w.Encoder = &FastEncoder{}
+ }
+ return w
+}
diff --git a/vendor/github.com/google/go-querystring/LICENSE b/vendor/github.com/google/go-querystring/LICENSE
new file mode 100644
index 00000000..ae121a1e
--- /dev/null
+++ b/vendor/github.com/google/go-querystring/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2013 Google. 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/google/go-querystring/query/encode.go b/vendor/github.com/google/go-querystring/query/encode.go
new file mode 100644
index 00000000..c9369540
--- /dev/null
+++ b/vendor/github.com/google/go-querystring/query/encode.go
@@ -0,0 +1,362 @@
+// Copyright 2013 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 query implements encoding of structs into URL query parameters.
+//
+// As a simple example:
+//
+// type Options struct {
+// Query string `url:"q"`
+// ShowAll bool `url:"all"`
+// Page int `url:"page"`
+// }
+//
+// opt := Options{ "foo", true, 2 }
+// v, _ := query.Values(opt)
+// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"
+//
+// The exact mapping between Go values and url.Values is described in the
+// documentation for the Values() function.
+package query
+
+import (
+ "fmt"
+ "net/url"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var timeType = reflect.TypeOf(time.Time{})
+
+var encoderType = reflect.TypeOf(new(Encoder)).Elem()
+
+// Encoder is an interface implemented by any type that wishes to encode
+// itself into URL values in a non-standard way.
+type Encoder interface {
+ EncodeValues(key string, v *url.Values) error
+}
+
+// Values returns the url.Values encoding of v.
+//
+// Values expects to be passed a struct, and traverses it recursively using the
+// following encoding rules.
+//
+// Each exported struct field is encoded as a URL parameter unless
+//
+// - the field's tag is "-", or
+// - the field is empty and its tag specifies the "omitempty" option
+//
+// The empty values are false, 0, any nil pointer or interface value, any array
+// slice, map, or string of length zero, and any type (such as time.Time) that
+// returns true for IsZero().
+//
+// The URL parameter name defaults to the struct field name but can be
+// specified in the struct field's tag value. The "url" key in the struct
+// field's tag value is the key name, followed by an optional comma and
+// options. For example:
+//
+// // Field is ignored by this package.
+// Field int `url:"-"`
+//
+// // Field appears as URL parameter "myName".
+// Field int `url:"myName"`
+//
+// // Field appears as URL parameter "myName" and the field is omitted if
+// // its value is empty
+// Field int `url:"myName,omitempty"`
+//
+// // Field appears as URL parameter "Field" (the default), but the field
+// // is skipped if empty. Note the leading comma.
+// Field int `url:",omitempty"`
+//
+// For encoding individual field values, the following type-dependent rules
+// apply:
+//
+// Boolean values default to encoding as the strings "true" or "false".
+// Including the "int" option signals that the field should be encoded as the
+// strings "1" or "0".
+//
+// time.Time values default to encoding as RFC3339 timestamps. Including the
+// "unix" option signals that the field should be encoded as a Unix time (see
+// time.Unix()). The "unixmilli" and "unixnano" options will encode the number
+// of milliseconds and nanoseconds, respectively, since January 1, 1970 (see
+// time.UnixNano()). Including the "layout" struct tag (separate from the
+// "url" tag) will use the value of the "layout" tag as a layout passed to
+// time.Format. For example:
+//
+// // Encode a time.Time as YYYY-MM-DD
+// Field time.Time `layout:"2006-01-02"`
+//
+// Slice and Array values default to encoding as multiple URL values of the
+// same name. Including the "comma" option signals that the field should be
+// encoded as a single comma-delimited value. Including the "space" option
+// similarly encodes the value as a single space-delimited string. Including
+// the "semicolon" option will encode the value as a semicolon-delimited string.
+// Including the "brackets" option signals that the multiple URL values should
+// have "[]" appended to the value name. "numbered" will append a number to
+// the end of each incidence of the value name, example:
+// name0=value0&name1=value1, etc. Including the "del" struct tag (separate
+// from the "url" tag) will use the value of the "del" tag as the delimiter.
+// For example:
+//
+// // Encode a slice of bools as ints ("1" for true, "0" for false),
+// // separated by exclamation points "!".
+// Field []bool `url:",int" del:"!"`
+//
+// Anonymous struct fields are usually encoded as if their inner exported
+// fields were fields in the outer struct, subject to the standard Go
+// visibility rules. An anonymous struct field with a name given in its URL
+// tag is treated as having that name, rather than being anonymous.
+//
+// Non-nil pointer values are encoded as the value pointed to.
+//
+// Nested structs have their fields processed recursively and are encoded
+// including parent fields in value names for scoping. For example,
+//
+// "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO"
+//
+// All other values are encoded using their default string representation.
+//
+// Multiple fields that encode to the same URL parameter name will be included
+// as multiple URL values of the same name.
+func Values(v interface{}) (url.Values, error) {
+ values := make(url.Values)
+
+ if v == nil {
+ return values, nil
+ }
+
+ val := reflect.ValueOf(v)
+ for val.Kind() == reflect.Ptr {
+ if val.IsNil() {
+ return values, nil
+ }
+ val = val.Elem()
+ }
+
+ if val.Kind() != reflect.Struct {
+ return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind())
+ }
+
+ err := reflectValue(values, val, "")
+ return values, err
+}
+
+// reflectValue populates the values parameter from the struct fields in val.
+// Embedded structs are followed recursively (using the rules defined in the
+// Values function documentation) breadth-first.
+func reflectValue(values url.Values, val reflect.Value, scope string) error {
+ var embedded []reflect.Value
+
+ typ := val.Type()
+ for i := 0; i < typ.NumField(); i++ {
+ sf := typ.Field(i)
+ if sf.PkgPath != "" && !sf.Anonymous { // unexported
+ continue
+ }
+
+ sv := val.Field(i)
+ tag := sf.Tag.Get("url")
+ if tag == "-" {
+ continue
+ }
+ name, opts := parseTag(tag)
+
+ if name == "" {
+ if sf.Anonymous {
+ v := reflect.Indirect(sv)
+ if v.IsValid() && v.Kind() == reflect.Struct {
+ // save embedded struct for later processing
+ embedded = append(embedded, v)
+ continue
+ }
+ }
+
+ name = sf.Name
+ }
+
+ if scope != "" {
+ name = scope + "[" + name + "]"
+ }
+
+ if opts.Contains("omitempty") && isEmptyValue(sv) {
+ continue
+ }
+
+ if sv.Type().Implements(encoderType) {
+ // if sv is a nil pointer and the custom encoder is defined on a non-pointer
+ // method receiver, set sv to the zero value of the underlying type
+ if !reflect.Indirect(sv).IsValid() && sv.Type().Elem().Implements(encoderType) {
+ sv = reflect.New(sv.Type().Elem())
+ }
+
+ m := sv.Interface().(Encoder)
+ if err := m.EncodeValues(name, &values); err != nil {
+ return err
+ }
+ continue
+ }
+
+ // recursively dereference pointers. break on nil pointers
+ for sv.Kind() == reflect.Ptr {
+ if sv.IsNil() {
+ break
+ }
+ sv = sv.Elem()
+ }
+
+ if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array {
+ if sv.Len() == 0 {
+ // skip if slice or array is empty
+ continue
+ }
+
+ var del string
+ if opts.Contains("comma") {
+ del = ","
+ } else if opts.Contains("space") {
+ del = " "
+ } else if opts.Contains("semicolon") {
+ del = ";"
+ } else if opts.Contains("brackets") {
+ name = name + "[]"
+ } else {
+ del = sf.Tag.Get("del")
+ }
+
+ if del != "" {
+ s := new(strings.Builder)
+ first := true
+ for i := 0; i < sv.Len(); i++ {
+ if first {
+ first = false
+ } else {
+ s.WriteString(del)
+ }
+ s.WriteString(valueString(sv.Index(i), opts, sf))
+ }
+ values.Add(name, s.String())
+ } else {
+ for i := 0; i < sv.Len(); i++ {
+ k := name
+ if opts.Contains("numbered") {
+ k = fmt.Sprintf("%s%d", name, i)
+ }
+ values.Add(k, valueString(sv.Index(i), opts, sf))
+ }
+ }
+ continue
+ }
+
+ if sv.Type() == timeType {
+ values.Add(name, valueString(sv, opts, sf))
+ continue
+ }
+
+ if sv.Kind() == reflect.Struct {
+ if err := reflectValue(values, sv, name); err != nil {
+ return err
+ }
+ continue
+ }
+
+ values.Add(name, valueString(sv, opts, sf))
+ }
+
+ for _, f := range embedded {
+ if err := reflectValue(values, f, scope); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// valueString returns the string representation of a value.
+func valueString(v reflect.Value, opts tagOptions, sf reflect.StructField) string {
+ for v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ return ""
+ }
+ v = v.Elem()
+ }
+
+ if v.Kind() == reflect.Bool && opts.Contains("int") {
+ if v.Bool() {
+ return "1"
+ }
+ return "0"
+ }
+
+ if v.Type() == timeType {
+ t := v.Interface().(time.Time)
+ if opts.Contains("unix") {
+ return strconv.FormatInt(t.Unix(), 10)
+ }
+ if opts.Contains("unixmilli") {
+ return strconv.FormatInt((t.UnixNano() / 1e6), 10)
+ }
+ if opts.Contains("unixnano") {
+ return strconv.FormatInt(t.UnixNano(), 10)
+ }
+ if layout := sf.Tag.Get("layout"); layout != "" {
+ return t.Format(layout)
+ }
+ return t.Format(time.RFC3339)
+ }
+
+ return fmt.Sprint(v.Interface())
+}
+
+// isEmptyValue checks if a value should be considered empty for the purposes
+// of omitting fields with the "omitempty" option.
+func isEmptyValue(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ return v.IsNil()
+ }
+
+ type zeroable interface {
+ IsZero() bool
+ }
+
+ if z, ok := v.Interface().(zeroable); ok {
+ return z.IsZero()
+ }
+
+ return false
+}
+
+// tagOptions is the string following a comma in a struct field's "url" tag, or
+// the empty string. It does not include the leading comma.
+type tagOptions []string
+
+// parseTag splits a struct field's url tag into its name and comma-separated
+// options.
+func parseTag(tag string) (string, tagOptions) {
+ s := strings.Split(tag, ",")
+ return s[0], s[1:]
+}
+
+// Contains checks whether the tagOptions contains the specified option.
+func (o tagOptions) Contains(option string) bool {
+ for _, s := range o {
+ if s == option {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/icholy/digest/.gitignore b/vendor/github.com/icholy/digest/.gitignore
new file mode 100644
index 00000000..a09c56df
--- /dev/null
+++ b/vendor/github.com/icholy/digest/.gitignore
@@ -0,0 +1 @@
+/.idea
diff --git a/vendor/github.com/icholy/digest/LICENSE b/vendor/github.com/icholy/digest/LICENSE
new file mode 100644
index 00000000..f77edc26
--- /dev/null
+++ b/vendor/github.com/icholy/digest/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Ilia Choly
+
+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/icholy/digest/README.md b/vendor/github.com/icholy/digest/README.md
new file mode 100644
index 00000000..e7a18918
--- /dev/null
+++ b/vendor/github.com/icholy/digest/README.md
@@ -0,0 +1,164 @@
+# HTTP Digest Access Authentication
+
+[](https://pkg.go.dev/github.com/icholy/digest)
+
+> This package provides a http.RoundTripper implementation which re-uses digest challenges
+
+``` go
+package main
+
+import (
+ "net/http"
+
+ "github.com/icholy/digest"
+)
+
+func main() {
+ client := &http.Client{
+ Transport: &digest.Transport{
+ Username: "foo",
+ Password: "bar",
+ },
+ }
+ res, err := client.Get("http://localhost:8080/some_outdated_service")
+ if err != nil {
+ panic(err)
+ }
+ defer res.Body.Close()
+}
+```
+
+## Using Cookies
+
+If you're using an `http.CookieJar` the `digest.Transport` needs a reference to it.
+
+``` go
+package main
+
+import (
+ "net/http"
+ "net/http/cookiejar"
+
+ "github.com/icholy/digest"
+)
+
+func main() {
+ jar, _ := cookiejar.New(nil)
+ client := &http.Client{
+ Transport: &digest.Transport{
+ Jar: jar,
+ Username: "foo",
+ Password: "bar",
+ },
+ }
+ res, err := client.Get("http://localhost:8080/digest_with_cookies")
+ if err != nil {
+ panic(err)
+ }
+ defer res.Body.Close()
+}
+```
+
+## Custom Authenticate Header
+
+``` go
+package main
+
+import (
+ "net/http"
+
+ "github.com/icholy/digest"
+)
+
+func main() {
+ client := &http.Client{
+ Transport: &digest.Transport{
+ Username: "foo",
+ Password: "bar",
+ FindChallenge: func(h http.Header) (*digest.Challenge, error) {
+ value := h.Get("Custom-Authenticate-Header")
+ if value == "" {
+ return nil, digest.ErrNoChallenge
+ }
+ return digest.ParseChallenge(value)
+ },
+ },
+ }
+ res, err := client.Get("http://localhost:8080/non_compliant")
+ if err != nil {
+ panic(err)
+ }
+ defer res.Body.Close()
+}
+```
+
+## Override Digest Options
+
+``` go
+package main
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/icholy/digest"
+)
+
+func main() {
+ client := &http.Client{
+ Transport: &digest.Transport{
+ Digest: func(req *http.Request, chal *digest.Challenge, opt digest.Options) (*digest.Credentials, error) {
+ switch req.URL.Hostname() {
+ case "badauth.org":
+ opt.Username = "foo"
+ opt.Password = "bar"
+ case "poorsecurity.com":
+ opt.Username = "zoo"
+ opt.Password = "boo"
+ default:
+ return nil, fmt.Errorf("unsuported host: %q", req.URL)
+ }
+ return digest.Digest(chal, opt)
+ },
+ },
+ }
+ res, err := client.Get("http://poorsecurity.com/legacy.php")
+ if err != nil {
+ panic(err)
+ }
+ defer res.Body.Close()
+}
+```
+
+
+## Low Level API
+
+``` go
+func main() {
+ // get the challenge from a 401 response
+ header := res.Header.Get("WWW-Authenticate")
+ chal, _ := digest.ParseChallenge(header)
+
+ // use it to create credentials for the next request
+ cred, _ := digest.Digest(chal, digest.Options{
+ Username: "foo",
+ Password: "bar",
+ Method: req.Method,
+ URI: req.URL.RequestURI(),
+ GetBody: req.GetBody,
+ Count: 1,
+ })
+ req.Header.Set("Authorization", cred.String())
+
+ // if you use the same challenge again, you must increment the Count
+ cred2, _ := digest.Digest(chal, digest.Options{
+ Username: "foo",
+ Password: "bar",
+ Method: req2.Method,
+ URI: req2.URL.RequestURI(),
+ GetBody: req2.GetBody,
+ Count: 2,
+ })
+ req2.Header.Set("Authorization", cred.String())
+}
+```
diff --git a/vendor/github.com/icholy/digest/challenge.go b/vendor/github.com/icholy/digest/challenge.go
new file mode 100644
index 00000000..e8b98fbf
--- /dev/null
+++ b/vendor/github.com/icholy/digest/challenge.go
@@ -0,0 +1,155 @@
+package digest
+
+import (
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/icholy/digest/internal/param"
+)
+
+// Challenge is a challenge sent in the WWW-Authenticate header
+type Challenge struct {
+ Realm string
+ Domain []string
+ Nonce string
+ Opaque string
+ Stale bool
+ Algorithm string
+ QOP []string
+ Charset string
+ Userhash bool
+}
+
+// SupportsQOP returns true if the challenge advertises support
+// for the provided qop value
+func (c *Challenge) SupportsQOP(qop string) bool {
+ for _, v := range c.QOP {
+ if v == qop {
+ return true
+ }
+ }
+ return false
+}
+
+// ParseChallenge parses the WWW-Authenticate header challenge
+func ParseChallenge(s string) (*Challenge, error) {
+ s, ok := strings.CutPrefix(s, Prefix)
+ if !ok {
+ return nil, errors.New("digest: invalid challenge prefix")
+ }
+ pp, err := param.Parse(s)
+ if err != nil {
+ return nil, fmt.Errorf("digest: invalid challenge: %w", err)
+ }
+ var c Challenge
+ for _, p := range pp {
+ switch p.Key {
+ case "realm":
+ c.Realm = p.Value
+ case "domain":
+ c.Domain = strings.Fields(p.Value)
+ case "nonce":
+ c.Nonce = p.Value
+ case "algorithm":
+ c.Algorithm = p.Value
+ case "stale":
+ c.Stale = strings.ToLower(p.Value) == "true"
+ case "opaque":
+ c.Opaque = p.Value
+ case "qop":
+ c.QOP = strings.Split(p.Value, ",")
+ case "charset":
+ c.Charset = p.Value
+ case "userhash":
+ c.Userhash = strings.ToLower(p.Value) == "true"
+ }
+ }
+ return &c, nil
+}
+
+// String returns the foramtted header value
+func (c *Challenge) String() string {
+ var pp []param.Param
+ pp = append(pp, param.Param{
+ Key: "realm",
+ Value: c.Realm,
+ Quote: true,
+ })
+ if len(c.Domain) != 0 {
+ pp = append(pp, param.Param{
+ Key: "domain",
+ Value: strings.Join(c.Domain, " "),
+ Quote: true,
+ })
+ }
+ pp = append(pp, param.Param{
+ Key: "nonce",
+ Value: c.Nonce,
+ Quote: true,
+ })
+ if c.Opaque != "" {
+ pp = append(pp, param.Param{
+ Key: "opaque",
+ Value: c.Opaque,
+ Quote: true,
+ })
+ }
+ if c.Stale {
+ pp = append(pp, param.Param{
+ Key: "stale",
+ Value: "true",
+ })
+ }
+ if c.Algorithm != "" {
+ pp = append(pp, param.Param{
+ Key: "algorithm",
+ Value: c.Algorithm,
+ })
+ }
+ if len(c.QOP) != 0 {
+ pp = append(pp, param.Param{
+ Key: "qop",
+ Value: strings.Join(c.QOP, ","),
+ Quote: true,
+ })
+ }
+ if c.Charset != "" {
+ pp = append(pp, param.Param{
+ Key: "charset",
+ Value: c.Charset,
+ })
+ }
+ if c.Userhash {
+ pp = append(pp, param.Param{
+ Key: "userhash",
+ Value: "true",
+ })
+ }
+ return Prefix + param.Format(pp...)
+}
+
+// ErrNoChallenge indicates that no WWW-Authenticate headers were found.
+var ErrNoChallenge = errors.New("digest: no challenge found")
+
+// FindChallenge returns the first supported challenge in the headers
+func FindChallenge(h http.Header) (*Challenge, error) {
+ var last error
+ for _, header := range h.Values("WWW-Authenticate") {
+ if !IsDigest(header) {
+ continue
+ }
+ chal, err := ParseChallenge(header)
+ if err == nil && CanDigest(chal) {
+ return chal, nil
+ }
+ if err != nil {
+ last = err
+ }
+ }
+ if last != nil {
+ return nil, last
+ }
+ return nil, ErrNoChallenge
+}
diff --git a/vendor/github.com/icholy/digest/credentials.go b/vendor/github.com/icholy/digest/credentials.go
new file mode 100644
index 00000000..56ff1df1
--- /dev/null
+++ b/vendor/github.com/icholy/digest/credentials.go
@@ -0,0 +1,142 @@
+package digest
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/icholy/digest/internal/param"
+)
+
+// Credentials is a parsed version of the Authorization header
+type Credentials struct {
+ Username string
+ Realm string
+ Nonce string
+ URI string
+ Response string
+ Algorithm string
+ Cnonce string
+ Opaque string
+ QOP string
+ Nc int
+ Userhash bool
+}
+
+// ParseCredentials parses the Authorization header value into credentials
+func ParseCredentials(s string) (*Credentials, error) {
+ s, ok := strings.CutPrefix(s, Prefix)
+ if !ok {
+ return nil, errors.New("digest: invalid credentials prefix")
+ }
+ pp, err := param.Parse(s)
+ if err != nil {
+ return nil, fmt.Errorf("digest: invalid credentials: %w", err)
+ }
+ var c Credentials
+ for _, p := range pp {
+ switch p.Key {
+ case "username":
+ c.Username = p.Value
+ case "realm":
+ c.Realm = p.Value
+ case "nonce":
+ c.Nonce = p.Value
+ case "uri":
+ c.URI = p.Value
+ case "response":
+ c.Response = p.Value
+ case "algorithm":
+ c.Algorithm = p.Value
+ case "cnonce":
+ c.Cnonce = p.Value
+ case "opaque":
+ c.Opaque = p.Value
+ case "qop":
+ c.QOP = p.Value
+ case "nc":
+ nc, err := strconv.ParseInt(p.Value, 16, 32)
+ if err != nil {
+ return nil, fmt.Errorf("digest: invalid nc: %w", err)
+ }
+ c.Nc = int(nc)
+ case "userhash":
+ c.Userhash = strings.ToLower(p.Value) == "true"
+ }
+ }
+ return &c, nil
+}
+
+// String formats the credentials into the header format
+func (c *Credentials) String() string {
+ var pp []param.Param
+ pp = append(pp,
+ param.Param{
+ Key: "username",
+ Value: c.Username,
+ Quote: true,
+ },
+ param.Param{
+ Key: "realm",
+ Value: c.Realm,
+ Quote: true,
+ },
+ param.Param{
+ Key: "nonce",
+ Value: c.Nonce,
+ Quote: true,
+ },
+ param.Param{
+ Key: "uri",
+ Value: c.URI,
+ Quote: true,
+ },
+ )
+ if c.Algorithm != "" {
+ pp = append(pp, param.Param{
+ Key: "algorithm",
+ Value: c.Algorithm,
+ })
+ }
+ if c.QOP != "" {
+ pp = append(pp, param.Param{
+ Key: "cnonce",
+ Value: c.Cnonce,
+ Quote: true,
+ })
+ }
+ if c.Opaque != "" {
+ pp = append(pp, param.Param{
+ Key: "opaque",
+ Value: c.Opaque,
+ Quote: true,
+ })
+ }
+ if c.QOP != "" {
+ pp = append(pp,
+ param.Param{
+ Key: "qop",
+ Value: c.QOP,
+ },
+ param.Param{
+ Key: "nc",
+ Value: fmt.Sprintf("%08x", c.Nc),
+ },
+ )
+ }
+ if c.Userhash {
+ pp = append(pp, param.Param{
+ Key: "userhash",
+ Value: "true",
+ })
+ }
+ // The RFC does not specify an order, but some implementations expect the response to be at the end.
+ // See: https://github.com/icholy/digest/issues/8
+ pp = append(pp, param.Param{
+ Key: "response",
+ Value: c.Response,
+ Quote: true,
+ })
+ return Prefix + param.Format(pp...)
+}
diff --git a/vendor/github.com/icholy/digest/digest.go b/vendor/github.com/icholy/digest/digest.go
new file mode 100644
index 00000000..4bbea7f7
--- /dev/null
+++ b/vendor/github.com/icholy/digest/digest.go
@@ -0,0 +1,164 @@
+package digest
+
+import (
+ "crypto/md5"
+ "crypto/rand"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/hex"
+ "fmt"
+ "hash"
+ "io"
+ "net/http"
+ "strings"
+)
+
+// Prefix for digest authentication headers
+const Prefix = "Digest "
+
+// IsDigest returns true if the header value is a digest auth header
+func IsDigest(header string) bool {
+ return strings.HasPrefix(header, Prefix)
+}
+
+// Options for creating a credentials
+type Options struct {
+ Method string
+ URI string
+ GetBody func() (io.ReadCloser, error)
+ Count int
+ Username string
+ Password string
+
+ // The following are provided for advanced use cases where the client needs
+ // to override the default digest calculation behavior. Most users should
+ // leave these fields unset.
+ A1 string
+ Cnonce string
+}
+
+// CanDigest checks if the algorithm and qop are supported
+func CanDigest(c *Challenge) bool {
+ switch strings.ToUpper(c.Algorithm) {
+ case "", "MD5", "SHA-256", "SHA-512", "SHA-512-256":
+ default:
+ return false
+ }
+ return len(c.QOP) == 0 || c.SupportsQOP("auth") || c.SupportsQOP("auth-int")
+}
+
+// Digest creates credentials from a challenge and request options.
+// Note: if you want to re-use a challenge, you must increment the Count.
+func Digest(chal *Challenge, o Options) (*Credentials, error) {
+ cred := &Credentials{
+ Username: o.Username,
+ URI: o.URI,
+ Cnonce: o.Cnonce,
+ Nc: o.Count,
+ Realm: chal.Realm,
+ Nonce: chal.Nonce,
+ Algorithm: chal.Algorithm,
+ Opaque: chal.Opaque,
+ Userhash: chal.Userhash,
+ }
+ // we re-use the same hash.Hash
+ var h hash.Hash
+ switch strings.ToUpper(cred.Algorithm) {
+ case "", "MD5":
+ h = md5.New()
+ case "SHA-256":
+ h = sha256.New()
+ case "SHA-512":
+ h = sha512.New()
+ case "SHA-512-256":
+ h = sha512.New512_256()
+ default:
+ return nil, fmt.Errorf("digest: unsupported algorithm: %q", cred.Algorithm)
+ }
+ // hash the username if requested
+ if cred.Userhash {
+ cred.Username = hashf(h, "%s:%s", o.Username, cred.Realm)
+ }
+ // generate the a1 hash if one was not provided
+ a1 := o.A1
+ if a1 == "" {
+ a1 = hashf(h, "%s:%s:%s", o.Username, cred.Realm, o.Password)
+ }
+ // generate the response
+ switch {
+ case len(chal.QOP) == 0:
+ cred.Response = hashf(h, "%s:%s:%s",
+ a1,
+ cred.Nonce,
+ hashf(h, "%s:%s", o.Method, o.URI), // A2
+ )
+ case chal.SupportsQOP("auth"):
+ cred.QOP = "auth"
+ if cred.Cnonce == "" {
+ cred.Cnonce = cnonce()
+ }
+ if cred.Nc == 0 {
+ cred.Nc = 1
+ }
+ cred.Response = hashf(h, "%s:%s:%08x:%s:%s:%s",
+ a1,
+ cred.Nonce,
+ cred.Nc,
+ cred.Cnonce,
+ cred.QOP,
+ hashf(h, "%s:%s", o.Method, o.URI), // A2
+ )
+ case chal.SupportsQOP("auth-int"):
+ cred.QOP = "auth-int"
+ if cred.Cnonce == "" {
+ cred.Cnonce = cnonce()
+ }
+ if cred.Nc == 0 {
+ cred.Nc = 1
+ }
+ hbody, err := hashbody(h, o.GetBody)
+ if err != nil {
+ return nil, fmt.Errorf("digest: failed to read body for auth-int: %w", err)
+ }
+ cred.Response = hashf(h, "%s:%s:%08x:%s:%s:%s",
+ a1,
+ cred.Nonce,
+ cred.Nc,
+ cred.Cnonce,
+ cred.QOP,
+ hashf(h, "%s:%s:%s", o.Method, o.URI, hbody), // A2
+ )
+ default:
+ return nil, fmt.Errorf("digest: unsupported qop: %q", strings.Join(chal.QOP, ","))
+ }
+ return cred, nil
+}
+
+func hashf(h hash.Hash, format string, args ...interface{}) string {
+ h.Reset()
+ fmt.Fprintf(h, format, args...)
+ return hex.EncodeToString(h.Sum(nil))
+}
+
+func hashbody(h hash.Hash, getbody func() (io.ReadCloser, error)) (string, error) {
+ h.Reset()
+ if getbody != nil {
+ r, err := getbody()
+ if err != nil {
+ return "", err
+ }
+ defer r.Close()
+ if r != http.NoBody {
+ if _, err := io.Copy(h, r); err != nil {
+ return "", err
+ }
+ }
+ }
+ return hex.EncodeToString(h.Sum(nil)), nil
+}
+
+func cnonce() string {
+ b := make([]byte, 8)
+ io.ReadFull(rand.Reader, b)
+ return hex.EncodeToString(b)
+}
diff --git a/vendor/github.com/icholy/digest/internal/param/param.go b/vendor/github.com/icholy/digest/internal/param/param.go
new file mode 100644
index 00000000..e2a6aecb
--- /dev/null
+++ b/vendor/github.com/icholy/digest/internal/param/param.go
@@ -0,0 +1,186 @@
+package param
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "strings"
+)
+
+// Param is a key/value header parameter
+type Param struct {
+ Key string
+ Value string
+ Quote bool
+}
+
+// String returns the formatted parameter
+func (p Param) String() string {
+ if p.Quote {
+ return fmt.Sprintf("%s=%q", p.Key, p.Value)
+ }
+ return fmt.Sprintf("%s=%s", p.Key, p.Value)
+}
+
+// Format formats the parameters to be included in the header
+func Format(pp ...Param) string {
+ var b strings.Builder
+ for i, p := range pp {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(p.String())
+ }
+ return b.String()
+}
+
+// Parse parses the header parameters
+func Parse(s string) ([]Param, error) {
+ var pp []Param
+ br := bufio.NewReader(strings.NewReader(s))
+ for i := 0; true; i++ {
+ // skip whitespace
+ if err := skipWhite(br); err != nil {
+ return nil, err
+ }
+ // see if there's more to read
+ if _, err := br.Peek(1); err == io.EOF {
+ break
+ }
+ // read key/value pair
+ p, err := parseParam(br, i == 0)
+ if err != nil {
+ return nil, fmt.Errorf("param: %w", err)
+ }
+ pp = append(pp, p)
+ }
+ return pp, nil
+}
+
+func parseIdent(br *bufio.Reader) (string, error) {
+ var ident []byte
+ for {
+ b, err := br.ReadByte()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return "", err
+ }
+ if !(('a' <= b && b <= 'z') || ('A' <= b && b <= 'Z') || '0' <= b && b <= '9' || b == '-') {
+ if err := br.UnreadByte(); err != nil {
+ return "", err
+ }
+ break
+ }
+ ident = append(ident, b)
+ }
+ return string(ident), nil
+}
+
+func parseByte(br *bufio.Reader, expect byte) error {
+ b, err := br.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ return fmt.Errorf("expected '%c', got EOF", expect)
+ }
+ return err
+ }
+ if b != expect {
+ return fmt.Errorf("expected '%c', got '%c'", expect, b)
+ }
+ return nil
+}
+
+func parseString(br *bufio.Reader) (string, error) {
+ var s []rune
+ // read the open quote
+ if err := parseByte(br, '"'); err != nil {
+ return "", err
+ }
+ // read the string
+ var escaped bool
+ for {
+ r, _, err := br.ReadRune()
+ if err != nil {
+ return "", err
+ }
+ if escaped {
+ s = append(s, r)
+ escaped = false
+ continue
+ }
+ if r == '\\' {
+ escaped = true
+ continue
+ }
+ // closing quote
+ if r == '"' {
+ break
+ }
+ s = append(s, r)
+ }
+ return string(s), nil
+}
+
+func skipWhite(br *bufio.Reader) error {
+ for {
+ b, err := br.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+ if b != ' ' {
+ return br.UnreadByte()
+ }
+ }
+}
+
+func parseParam(br *bufio.Reader, first bool) (Param, error) {
+ // skip whitespace
+ if err := skipWhite(br); err != nil {
+ return Param{}, err
+ }
+ if !first {
+ // read the comma separator
+ if err := parseByte(br, ','); err != nil {
+ return Param{}, err
+ }
+ // skip whitespace
+ if err := skipWhite(br); err != nil {
+ return Param{}, err
+ }
+ }
+ // read the key
+ key, err := parseIdent(br)
+ if err != nil {
+ return Param{}, err
+ }
+ // skip whitespace
+ if err := skipWhite(br); err != nil {
+ return Param{}, err
+ }
+ // read the equals sign
+ if err := parseByte(br, '='); err != nil {
+ return Param{}, err
+ }
+ // skip whitespace
+ if err := skipWhite(br); err != nil {
+ return Param{}, err
+ }
+ // read the value
+ var value string
+ var quote bool
+ if b, _ := br.Peek(1); len(b) == 1 && b[0] == '"' {
+ quote = true
+ value, err = parseString(br)
+ } else {
+ value, err = parseIdent(br)
+ }
+ if err != nil {
+ return Param{}, err
+ }
+ return Param{Key: key, Value: value, Quote: quote}, nil
+}
diff --git a/vendor/github.com/icholy/digest/transport.go b/vendor/github.com/icholy/digest/transport.go
new file mode 100644
index 00000000..6dfc4a24
--- /dev/null
+++ b/vendor/github.com/icholy/digest/transport.go
@@ -0,0 +1,237 @@
+package digest
+
+import (
+ "bytes"
+ "io"
+ "net/http"
+ "sync"
+)
+
+// cchal is a cached challenge and the number of times it's been used.
+type cchal struct {
+ c *Challenge
+ n int
+}
+
+// Transport implements http.RoundTripper
+type Transport struct {
+ Username string
+ Password string
+
+ // Digest computes the digest credentials.
+ // If nil, the Digest function is used.
+ Digest func(*http.Request, *Challenge, Options) (*Credentials, error)
+
+ // FindChallenge extracts the challenge from the request headers.
+ // If nil, the FindChallenge function is used.
+ FindChallenge func(http.Header) (*Challenge, error)
+
+ // Transport specifies the mechanism by which individual
+ // HTTP requests are made.
+ // If nil, DefaultTransport is used.
+ Transport http.RoundTripper
+
+ // Jar specifies the cookie jar.
+ //
+ // The Jar is used to insert relevant cookies into every
+ // outbound Request and is updated with the cookie values
+ // of every inbound Response. The Jar is consulted for every
+ // redirect that the Client follows.
+ //
+ // If Jar is nil, cookies are only sent if they are explicitly
+ // set on the Request.
+ Jar http.CookieJar
+
+ // NoReuse prevents the transport from reusing challenges.
+ NoReuse bool
+
+ // cache of challenges indexed by host
+ cache map[string]*cchal
+ cacheMu sync.Mutex
+}
+
+// save parses the digest challenge from the response
+// and adds it to the cache
+func (t *Transport) save(res *http.Response) error {
+ // save cookies
+ if t.Jar != nil {
+ t.Jar.SetCookies(res.Request.URL, res.Cookies())
+ }
+ // find and save digest challenge
+ find := t.FindChallenge
+ if find == nil {
+ find = FindChallenge
+ }
+ chal, err := find(res.Header)
+ t.cacheMu.Lock()
+ defer t.cacheMu.Unlock()
+ if t.cache == nil {
+ t.cache = map[string]*cchal{}
+ }
+ // TODO: if the challenge contains a domain, we should be using that
+ // to match against outgoing requests. We're currently ignoring
+ // it and just matching the hostname. That being said, none of
+ // the major browsers respect the domain either.
+ host := res.Request.URL.Hostname()
+ if err != nil {
+ // if save is being invoked, the existing cached challenge didn't work
+ delete(t.cache, host)
+ return err
+ }
+ t.cache[host] = &cchal{c: chal}
+ return nil
+}
+
+// digest creates credentials from the cached challenge
+func (t *Transport) digest(req *http.Request, chal *Challenge, count int) (*Credentials, error) {
+ opt := Options{
+ Method: req.Method,
+ URI: req.URL.RequestURI(),
+ GetBody: req.GetBody,
+ Count: count,
+ Username: t.Username,
+ Password: t.Password,
+ }
+ if t.Digest != nil {
+ return t.Digest(req, chal, opt)
+ }
+ return Digest(chal, opt)
+}
+
+// challenge returns a cached challenge and count for the provided request
+func (t *Transport) challenge(req *http.Request) (*Challenge, int, bool) {
+ t.cacheMu.Lock()
+ defer t.cacheMu.Unlock()
+ host := req.URL.Hostname()
+ cc, ok := t.cache[host]
+ if !ok {
+ return nil, 0, false
+ }
+ if t.NoReuse {
+ delete(t.cache, host)
+ }
+ cc.n++
+ return cc.c, cc.n, true
+}
+
+// prepare attempts to find a cached challenge that matches the
+// requested domain, and use it to set the Authorization header
+func (t *Transport) prepare(req *http.Request) error {
+ // add cookies
+ if t.Jar != nil {
+ for _, cookie := range t.Jar.Cookies(req.URL) {
+ req.AddCookie(cookie)
+ }
+ }
+ // add auth
+ chal, count, ok := t.challenge(req)
+ if !ok {
+ return nil
+ }
+ cred, err := t.digest(req, chal, count)
+ if err != nil {
+ return err
+ }
+ if cred != nil {
+ req.Header.Set("Authorization", cred.String())
+ }
+ return nil
+}
+
+// RoundTrip will try to authorize the request using a cached challenge.
+// If that doesn't work and we receive a 401, we'll try again using that challenge.
+func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
+ // use the configured transport if there is one
+ tr := t.Transport
+ if tr == nil {
+ tr = http.DefaultTransport
+ }
+ // don't modify the original request
+ clone, err := cloner(req)
+ if err != nil {
+ return nil, err
+ }
+ // make a copy of the request
+ first, err := clone()
+ if err != nil {
+ return nil, err
+ }
+ // prepare the first request using a cached challenge
+ if err := t.prepare(first); err != nil {
+ return nil, err
+ }
+ // the first request will either succeed or return a 401
+ res, err := tr.RoundTrip(first)
+ if err != nil || res.StatusCode != http.StatusUnauthorized {
+ return res, err
+ }
+ // drain and close the first message body
+ _, _ = io.Copy(io.Discard, res.Body)
+ _ = res.Body.Close()
+ // save the challenge for future use
+ if err := t.save(res); err != nil {
+ if err == ErrNoChallenge {
+ return res, nil
+ }
+ return nil, err
+ }
+ // make a second copy of the request
+ second, err := clone()
+ if err != nil {
+ return nil, err
+ }
+ // prepare the second request based on the new challenge
+ if err := t.prepare(second); err != nil {
+ return nil, err
+ }
+ return tr.RoundTrip(second)
+}
+
+// CloseIdleConnections delegates the call to the underlying transport.
+func (t *Transport) CloseIdleConnections() {
+ tr := t.Transport
+ if tr == nil {
+ tr = http.DefaultTransport
+ }
+ type closeIdler interface {
+ CloseIdleConnections()
+ }
+ if tr, ok := tr.(closeIdler); ok {
+ tr.CloseIdleConnections()
+ }
+}
+
+// cloner returns a function which makes clones of the provided request
+func cloner(req *http.Request) (func() (*http.Request, error), error) {
+ getbody := req.GetBody
+ // if there's no GetBody function set we have to copy the body
+ // into memory to use for future clones
+ if getbody == nil {
+ if req.Body == nil || req.Body == http.NoBody {
+ getbody = func() (io.ReadCloser, error) {
+ return http.NoBody, nil
+ }
+ } else {
+ body, err := io.ReadAll(req.Body)
+ if err != nil {
+ return nil, err
+ }
+ if err := req.Body.Close(); err != nil {
+ return nil, err
+ }
+ getbody = func() (io.ReadCloser, error) {
+ return io.NopCloser(bytes.NewReader(body)), nil
+ }
+ }
+ }
+ return func() (*http.Request, error) {
+ clone := req.Clone(req.Context())
+ body, err := getbody()
+ if err != nil {
+ return nil, err
+ }
+ clone.Body = body
+ clone.GetBody = getbody
+ return clone, nil
+ }, nil
+}
diff --git a/vendor/github.com/klauspost/compress/.gitattributes b/vendor/github.com/klauspost/compress/.gitattributes
new file mode 100644
index 00000000..57aa6487
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/.gitattributes
@@ -0,0 +1,3 @@
+* -text
+*.bin -text -diff
+*.md text eol=lf
diff --git a/vendor/github.com/klauspost/compress/.gitignore b/vendor/github.com/klauspost/compress/.gitignore
new file mode 100644
index 00000000..d31b3781
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/.gitignore
@@ -0,0 +1,32 @@
+# 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
+*.test
+*.prof
+/s2/cmd/_s2sx/sfx-exe
+
+# Linux perf files
+perf.data
+perf.data.old
+
+# gdb history
+.gdb_history
diff --git a/vendor/github.com/klauspost/compress/.goreleaser.yml b/vendor/github.com/klauspost/compress/.goreleaser.yml
new file mode 100644
index 00000000..804a2018
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/.goreleaser.yml
@@ -0,0 +1,132 @@
+version: 2
+
+before:
+ hooks:
+ - ./gen.sh
+
+builds:
+ -
+ id: "s2c"
+ binary: s2c
+ main: ./s2/cmd/s2c/main.go
+ flags:
+ - -trimpath
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - aix
+ - linux
+ - freebsd
+ - netbsd
+ - windows
+ - darwin
+ goarch:
+ - 386
+ - amd64
+ - arm
+ - arm64
+ - ppc64
+ - ppc64le
+ - mips64
+ - mips64le
+ goarm:
+ - 7
+ ignore:
+ - goos: windows
+ goarch: arm
+ -
+ id: "s2d"
+ binary: s2d
+ main: ./s2/cmd/s2d/main.go
+ flags:
+ - -trimpath
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - aix
+ - linux
+ - freebsd
+ - netbsd
+ - windows
+ - darwin
+ goarch:
+ - 386
+ - amd64
+ - arm
+ - arm64
+ - ppc64
+ - ppc64le
+ - mips64
+ - mips64le
+ goarm:
+ - 7
+ ignore:
+ - goos: windows
+ goarch: arm
+ -
+ id: "s2sx"
+ binary: s2sx
+ main: ./s2/cmd/_s2sx/main.go
+ flags:
+ - -modfile=s2sx.mod
+ - -trimpath
+ env:
+ - CGO_ENABLED=0
+ goos:
+ - aix
+ - linux
+ - freebsd
+ - netbsd
+ - windows
+ - darwin
+ goarch:
+ - 386
+ - amd64
+ - arm
+ - arm64
+ - ppc64
+ - ppc64le
+ - mips64
+ - mips64le
+ goarm:
+ - 7
+ ignore:
+ - goos: windows
+ goarch: arm
+
+archives:
+ -
+ id: s2-binaries
+ name_template: "s2-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
+ format_overrides:
+ - goos: windows
+ formats: ['zip']
+ files:
+ - unpack/*
+ - s2/LICENSE
+ - s2/README.md
+checksum:
+ name_template: 'checksums.txt'
+snapshot:
+ version_template: "{{ .Tag }}-next"
+changelog:
+ sort: asc
+ filters:
+ exclude:
+ - '^doc:'
+ - '^docs:'
+ - '^test:'
+ - '^tests:'
+ - '^Update\sREADME.md'
+
+nfpms:
+ -
+ file_name_template: "s2_package__{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
+ vendor: Klaus Post
+ homepage: https://github.com/klauspost/compress
+ maintainer: Klaus Post
+ description: S2 Compression Tool
+ license: BSD 3-Clause
+ formats:
+ - deb
+ - rpm
diff --git a/vendor/github.com/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE
new file mode 100644
index 00000000..87d55747
--- /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/README.md b/vendor/github.com/klauspost/compress/README.md
new file mode 100644
index 00000000..fb023f2c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/README.md
@@ -0,0 +1,700 @@
+# compress
+
+This package provides various compression algorithms.
+
+* [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression in pure Go.
+* [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy.
+* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib).
+* [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams.
+* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding.
+* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently.
+* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation.
+
+[](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories)
+[](https://github.com/klauspost/compress/actions/workflows/go.yml)
+[](https://sourcegraph.com/github.com/klauspost/compress?badge)
+
+# package usage
+
+Use `go get github.com/klauspost/compress@latest` to add it to your project.
+
+This package will support the current Go version and 2 versions back.
+
+* Use the `nounsafe` tag to disable all use of the "unsafe" package.
+* Use the `noasm` tag to disable all assembly across packages.
+
+Use the links above for more information on each.
+
+# changelog
+
+* Feb 9th, 2026 [1.18.4](https://github.com/klauspost/compress/releases/tag/v1.18.4)
+ * gzhttp: Add zstandard to server handler wrapper https://github.com/klauspost/compress/pull/1121
+ * zstd: Add ResetWithOptions to encoder/decoder https://github.com/klauspost/compress/pull/1122
+ * gzhttp: preserve qvalue when extra parameters follow in Accept-Encoding by @analytically in https://github.com/klauspost/compress/pull/1116
+
+* Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3)
+ * Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102).
+
+* Dec 1st, 2025 - [1.18.2](https://github.com/klauspost/compress/releases/tag/v1.18.2)
+ * flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115
+ * flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106
+
+* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) - RETRACTED
+ * zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079
+ * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059
+ * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080
+ * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086
+ * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090
+ * flate: Faster load+store https://github.com/klauspost/compress/pull/1104
+ * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101
+ * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103
+
+* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0)
+ * Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036
+ * fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028
+ * flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043
+ * flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045
+ * s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048
+ * flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049
+ * flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050
+
+
+ See changes to v1.17.x
+
+* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11)
+ * zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017
+ * s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014
+ * gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011
+ * gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013
+
+* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10)
+ * gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978
+ * gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002
+ * s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982
+ * zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007
+ * flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996
+
+* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9)
+ * s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949
+ * flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963
+ * Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971
+ * zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951
+
+* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8)
+ * zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885
+ * zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938
+
+* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7)
+ * s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927
+ * s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930
+
+* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6)
+ * zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923
+ * s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925
+
+* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5)
+ * flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912
+ * zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908
+ * zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913
+ * zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910
+ * s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917
+https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918
+
+* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4)
+ * huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887
+ * huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886
+ * gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892
+ * gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890
+ * gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891
+
+* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3)
+ * fse: Fix max header size https://github.com/klauspost/compress/pull/881
+ * zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877
+ * gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883
+
+* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2)
+ * zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876
+
+* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1)
+ * s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871
+ * flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869
+ * s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867
+
+* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0)
+ * Add experimental dictionary builder https://github.com/klauspost/compress/pull/853
+ * Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838
+ * flate: Add limited window compression https://github.com/klauspost/compress/pull/843
+ * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
+ * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
+ * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
+
+
+
+ See changes to v1.16.x
+
+
+* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7)
+ * zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
+ * s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832
+
+* June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6)
+ * zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806
+ * zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824
+ * gzhttp: Handle informational headers by @rtribotte in https://github.com/klauspost/compress/pull/815
+ * s2: Improve Better compression slightly https://github.com/klauspost/compress/pull/663
+
+* Apr 16, 2023 - [v1.16.5](https://github.com/klauspost/compress/releases/tag/v1.16.5)
+ * zstd: readByte needs to use io.ReadFull by @jnoxon in https://github.com/klauspost/compress/pull/802
+ * gzip: Fix WriterTo after initial read https://github.com/klauspost/compress/pull/804
+
+* Apr 5, 2023 - [v1.16.4](https://github.com/klauspost/compress/releases/tag/v1.16.4)
+ * zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784
+ * zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792
+ * zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785
+ * zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795
+ * s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779
+ * s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780
+ * gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799
+
+* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1)
+ * zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776
+ * gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767
+ * s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766
+ * zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773
+ * huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774
+
+* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0)
+ * s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685
+ * s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752
+ * s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755
+ * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
+ * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
+ * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
+
+
+
+ See changes to v1.15.x
+
+* Jan 21st, 2023 (v1.15.15)
+ * deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739
+ * zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728
+ * zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745
+ * gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740
+
+* Jan 3rd, 2023 (v1.15.14)
+
+ * flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
+ * zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720
+ * export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722
+ * s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723
+
+* Dec 11, 2022 (v1.15.13)
+ * zstd: Add [MaxEncodedSize](https://pkg.go.dev/github.com/klauspost/compress@v1.15.13/zstd#Encoder.MaxEncodedSize) to encoder https://github.com/klauspost/compress/pull/691
+ * zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708
+
+* Oct 26, 2022 (v1.15.12)
+
+ * zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680
+ * gzhttp: Always delete `HeaderNoCompression` https://github.com/klauspost/compress/pull/683
+
+* Sept 26, 2022 (v1.15.11)
+
+ * flate: Improve level 1-3 compression https://github.com/klauspost/compress/pull/678
+ * zstd: Improve "best" compression by @nightwolfz in https://github.com/klauspost/compress/pull/677
+ * zstd: Fix+reduce decompression allocations https://github.com/klauspost/compress/pull/668
+ * zstd: Fix non-effective noescape tag https://github.com/klauspost/compress/pull/667
+
+* Sept 16, 2022 (v1.15.10)
+
+ * zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649
+ * Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651
+ * flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656
+ * zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657
+ * s2: Improve "best" compression https://github.com/klauspost/compress/pull/658
+ * s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635
+ * s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646
+ * Use arrays for constant size copies https://github.com/klauspost/compress/pull/659
+
+* July 21, 2022 (v1.15.9)
+
+ * zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645
+ * zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644
+ * zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643
+
+* July 13, 2022 (v1.15.8)
+
+ * gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641
+ * s2: Add Index header trim/restore https://github.com/klauspost/compress/pull/638
+ * zstd: Optimize seqdeq amd64 asm by @greatroar in https://github.com/klauspost/compress/pull/636
+ * zstd: Improve decoder memcopy https://github.com/klauspost/compress/pull/637
+ * huff0: Pass a single bitReader pointer to asm by @greatroar in https://github.com/klauspost/compress/pull/634
+ * zstd: Branchless getBits for amd64 w/o BMI2 by @greatroar in https://github.com/klauspost/compress/pull/640
+ * gzhttp: Remove header before writing https://github.com/klauspost/compress/pull/639
+
+* June 29, 2022 (v1.15.7)
+
+ * s2: Fix absolute forward seeks https://github.com/klauspost/compress/pull/633
+ * zip: Merge upstream https://github.com/klauspost/compress/pull/631
+ * zip: Re-add zip64 fix https://github.com/klauspost/compress/pull/624
+ * zstd: translate fseDecoder.buildDtable into asm by @WojciechMula in https://github.com/klauspost/compress/pull/598
+ * flate: Faster histograms https://github.com/klauspost/compress/pull/620
+ * deflate: Use compound hcode https://github.com/klauspost/compress/pull/622
+
+* June 3, 2022 (v1.15.6)
+ * s2: Improve coding for long, close matches https://github.com/klauspost/compress/pull/613
+ * s2c: Add Snappy/S2 stream recompression https://github.com/klauspost/compress/pull/611
+ * zstd: Always use configured block size https://github.com/klauspost/compress/pull/605
+ * zstd: Fix incorrect hash table placement for dict encoding in default https://github.com/klauspost/compress/pull/606
+ * zstd: Apply default config to ZipDecompressor without options https://github.com/klauspost/compress/pull/608
+ * gzhttp: Exclude more common archive formats https://github.com/klauspost/compress/pull/612
+ * s2: Add ReaderIgnoreCRC https://github.com/klauspost/compress/pull/609
+ * s2: Remove sanity load on index creation https://github.com/klauspost/compress/pull/607
+ * snappy: Use dedicated function for scoring https://github.com/klauspost/compress/pull/614
+ * s2c+s2d: Use official snappy framed extension https://github.com/klauspost/compress/pull/610
+
+* May 25, 2022 (v1.15.5)
+ * s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602
+ * s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601
+ * huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596
+ * zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588
+ * zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592
+ * zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599
+ * zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593
+ * huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586
+ * flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590
+
+
+* May 11, 2022 (v1.15.4)
+ * huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577)
+ * inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581)
+ * zstd: Faster decoding memcopy in asm [#583](https://github.com/klauspost/compress/pull/583)
+ * zstd: Fix ignored crc [#580](https://github.com/klauspost/compress/pull/580)
+
+* May 5, 2022 (v1.15.3)
+ * zstd: Allow to ignore checksum checking by @WojciechMula [#572](https://github.com/klauspost/compress/pull/572)
+ * s2: Fix incorrect seek for io.SeekEnd in [#575](https://github.com/klauspost/compress/pull/575)
+
+* Apr 26, 2022 (v1.15.2)
+ * zstd: Add x86-64 assembly for decompression on streams and blocks. Contributed by [@WojciechMula](https://github.com/WojciechMula). Typically 2x faster. [#528](https://github.com/klauspost/compress/pull/528) [#531](https://github.com/klauspost/compress/pull/531) [#545](https://github.com/klauspost/compress/pull/545) [#537](https://github.com/klauspost/compress/pull/537)
+ * zstd: Add options to ZipDecompressor and fixes [#539](https://github.com/klauspost/compress/pull/539)
+ * s2: Use sorted search for index [#555](https://github.com/klauspost/compress/pull/555)
+ * Minimum version is Go 1.16, added CI test on 1.18.
+
+* Mar 11, 2022 (v1.15.1)
+ * huff0: Add x86 assembly of Decode4X by @WojciechMula in [#512](https://github.com/klauspost/compress/pull/512)
+ * zstd: Reuse zip decoders in [#514](https://github.com/klauspost/compress/pull/514)
+ * zstd: Detect extra block data and report as corrupted in [#520](https://github.com/klauspost/compress/pull/520)
+ * zstd: Handle zero sized frame content size stricter in [#521](https://github.com/klauspost/compress/pull/521)
+ * zstd: Add stricter block size checks in [#523](https://github.com/klauspost/compress/pull/523)
+
+* Mar 3, 2022 (v1.15.0)
+ * zstd: Refactor decoder [#498](https://github.com/klauspost/compress/pull/498)
+ * zstd: Add stream encoding without goroutines [#505](https://github.com/klauspost/compress/pull/505)
+ * huff0: Prevent single blocks exceeding 16 bits by @klauspost in[#507](https://github.com/klauspost/compress/pull/507)
+ * flate: Inline literal emission [#509](https://github.com/klauspost/compress/pull/509)
+ * gzhttp: Add zstd to transport [#400](https://github.com/klauspost/compress/pull/400)
+ * gzhttp: Make content-type optional [#510](https://github.com/klauspost/compress/pull/510)
+
+Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines.
+
+Stream decompression is now faster on asynchronous, since the goroutine allocation much more effectively splits the workload. On typical streams this will typically use 2 cores fully for decompression. When a stream has finished decoding no goroutines will be left over, so decoders can now safely be pooled and still be garbage collected.
+
+While the release has been extensively tested, it is recommended to testing when upgrading.
+
+
+
+
+ See changes to v1.14.x
+
+* Feb 22, 2022 (v1.14.4)
+ * flate: Fix rare huffman only (-2) corruption. [#503](https://github.com/klauspost/compress/pull/503)
+ * zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in [#502](https://github.com/klauspost/compress/pull/502)
+ * zip: don't read data descriptor early by @saracen in [#501](https://github.com/klauspost/compress/pull/501) #501
+ * huff0: Use static decompression buffer up to 30% faster [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500)
+
+* Feb 17, 2022 (v1.14.3)
+ * flate: Improve fastest levels compression speed ~10% more throughput. [#482](https://github.com/klauspost/compress/pull/482) [#489](https://github.com/klauspost/compress/pull/489) [#490](https://github.com/klauspost/compress/pull/490) [#491](https://github.com/klauspost/compress/pull/491) [#494](https://github.com/klauspost/compress/pull/494) [#478](https://github.com/klauspost/compress/pull/478)
+ * flate: Faster decompression speed, ~5-10%. [#483](https://github.com/klauspost/compress/pull/483)
+ * s2: Faster compression with Go v1.18 and amd64 microarch level 3+. [#484](https://github.com/klauspost/compress/pull/484) [#486](https://github.com/klauspost/compress/pull/486)
+
+* Jan 25, 2022 (v1.14.2)
+ * zstd: improve header decoder by @dsnet [#476](https://github.com/klauspost/compress/pull/476)
+ * zstd: Add bigger default blocks [#469](https://github.com/klauspost/compress/pull/469)
+ * zstd: Remove unused decompression buffer [#470](https://github.com/klauspost/compress/pull/470)
+ * zstd: Fix logically dead code by @ningmingxiao [#472](https://github.com/klauspost/compress/pull/472)
+ * flate: Improve level 7-9 [#471](https://github.com/klauspost/compress/pull/471) [#473](https://github.com/klauspost/compress/pull/473)
+ * zstd: Add noasm tag for xxhash [#475](https://github.com/klauspost/compress/pull/475)
+
+* Jan 11, 2022 (v1.14.1)
+ * s2: Add stream index in [#462](https://github.com/klauspost/compress/pull/462)
+ * flate: Speed and efficiency improvements in [#439](https://github.com/klauspost/compress/pull/439) [#461](https://github.com/klauspost/compress/pull/461) [#455](https://github.com/klauspost/compress/pull/455) [#452](https://github.com/klauspost/compress/pull/452) [#458](https://github.com/klauspost/compress/pull/458)
+ * zstd: Performance improvement in [#420]( https://github.com/klauspost/compress/pull/420) [#456](https://github.com/klauspost/compress/pull/456) [#437](https://github.com/klauspost/compress/pull/437) [#467](https://github.com/klauspost/compress/pull/467) [#468](https://github.com/klauspost/compress/pull/468)
+ * zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464)
+ * Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445)
+
+
+
+ See changes to v1.13.x
+
+* Aug 30, 2021 (v1.13.5)
+ * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
+ * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
+ * zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426)
+ * Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421)
+
+* Aug 12, 2021 (v1.13.4)
+ * Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy).
+ * zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415)
+
+* Aug 3, 2021 (v1.13.3)
+ * zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404)
+ * zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411)
+ * gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406)
+ * s2sx: Fix max size error [#399](https://github.com/klauspost/compress/pull/399)
+ * zstd: Add optional stream content size on reset [#401](https://github.com/klauspost/compress/pull/401)
+ * zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410)
+
+* Jun 14, 2021 (v1.13.1)
+ * s2: Add full Snappy output support [#396](https://github.com/klauspost/compress/pull/396)
+ * zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394)
+ * gzhttp: Add header to skip compression [#389](https://github.com/klauspost/compress/pull/389)
+ * s2: Improve speed with bigger output margin [#395](https://github.com/klauspost/compress/pull/395)
+
+* Jun 3, 2021 (v1.13.0)
+ * Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors.
+ * zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382)
+ * zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380)
+
+
+
+
+ See changes to v1.12.x
+
+* May 25, 2021 (v1.12.3)
+ * deflate: Better/faster Huffman encoding [#374](https://github.com/klauspost/compress/pull/374)
+ * deflate: Allocate less for history. [#375](https://github.com/klauspost/compress/pull/375)
+ * zstd: Forward read errors [#373](https://github.com/klauspost/compress/pull/373)
+
+* Apr 27, 2021 (v1.12.2)
+ * zstd: Improve better/best compression [#360](https://github.com/klauspost/compress/pull/360) [#364](https://github.com/klauspost/compress/pull/364) [#365](https://github.com/klauspost/compress/pull/365)
+ * zstd: Add helpers to compress/decompress zstd inside zip files [#363](https://github.com/klauspost/compress/pull/363)
+ * deflate: Improve level 5+6 compression [#367](https://github.com/klauspost/compress/pull/367)
+ * s2: Improve better/best compression [#358](https://github.com/klauspost/compress/pull/358) [#359](https://github.com/klauspost/compress/pull/358)
+ * s2: Load after checking src limit on amd64. [#362](https://github.com/klauspost/compress/pull/362)
+ * s2sx: Limit max executable size [#368](https://github.com/klauspost/compress/pull/368)
+
+* Apr 14, 2021 (v1.12.1)
+ * snappy package removed. Upstream added as dependency.
+ * s2: Better compression in "best" mode [#353](https://github.com/klauspost/compress/pull/353)
+ * s2sx: Add stdin input and detect pre-compressed from signature [#352](https://github.com/klauspost/compress/pull/352)
+ * s2c/s2d: Add http as possible input [#348](https://github.com/klauspost/compress/pull/348)
+ * s2c/s2d/s2sx: Always truncate when writing files [#352](https://github.com/klauspost/compress/pull/352)
+ * zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346)
+ * s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349)
+
+
+
+ See changes to v1.11.x
+
+* Mar 26, 2021 (v1.11.13)
+ * zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345)
+ * zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336)
+ * deflate: Improve entropy compression [#338](https://github.com/klauspost/compress/pull/338)
+ * s2: Clean up and minor performance improvement in best [#341](https://github.com/klauspost/compress/pull/341)
+
+* Mar 5, 2021 (v1.11.12)
+ * s2: Add `s2sx` binary that creates [self extracting archives](https://github.com/klauspost/compress/tree/master/s2#s2sx-self-extracting-archives).
+ * s2: Speed up decompression on non-assembly platforms [#328](https://github.com/klauspost/compress/pull/328)
+
+* Mar 1, 2021 (v1.11.9)
+ * s2: Add ARM64 decompression assembly. Around 2x output speed. [#324](https://github.com/klauspost/compress/pull/324)
+ * s2: Improve "better" speed and efficiency. [#325](https://github.com/klauspost/compress/pull/325)
+ * s2: Fix binaries.
+
+* Feb 25, 2021 (v1.11.8)
+ * s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended.
+ * s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315)
+ * s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322)
+ * zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314)
+ * zip: Fix zip64 headers. [#313](https://github.com/klauspost/compress/pull/313)
+
+* Jan 14, 2021 (v1.11.7)
+ * Use Bytes() interface to get bytes across packages. [#309](https://github.com/klauspost/compress/pull/309)
+ * s2: Add 'best' compression option. [#310](https://github.com/klauspost/compress/pull/310)
+ * s2: Add ReaderMaxBlockSize, changes `s2.NewReader` signature to include varargs. [#311](https://github.com/klauspost/compress/pull/311)
+ * s2: Fix crash on small better buffers. [#308](https://github.com/klauspost/compress/pull/308)
+ * s2: Clean up decoder. [#312](https://github.com/klauspost/compress/pull/312)
+
+* Jan 7, 2021 (v1.11.6)
+ * zstd: Make decoder allocations smaller [#306](https://github.com/klauspost/compress/pull/306)
+ * zstd: Free Decoder resources when Reset is called with a nil io.Reader [#305](https://github.com/klauspost/compress/pull/305)
+
+* Dec 20, 2020 (v1.11.4)
+ * zstd: Add Best compression mode [#304](https://github.com/klauspost/compress/pull/304)
+ * Add header decoder [#299](https://github.com/klauspost/compress/pull/299)
+ * s2: Add uncompressed stream option [#297](https://github.com/klauspost/compress/pull/297)
+ * Simplify/speed up small blocks with known max size. [#300](https://github.com/klauspost/compress/pull/300)
+ * zstd: Always reset literal dict encoder [#303](https://github.com/klauspost/compress/pull/303)
+
+* Nov 15, 2020 (v1.11.3)
+ * inflate: 10-15% faster decompression [#293](https://github.com/klauspost/compress/pull/293)
+ * zstd: Tweak DecodeAll default allocation [#295](https://github.com/klauspost/compress/pull/295)
+
+* Oct 11, 2020 (v1.11.2)
+ * s2: Fix out of bounds read in "better" block compression [#291](https://github.com/klauspost/compress/pull/291)
+
+* Oct 1, 2020 (v1.11.1)
+ * zstd: Set allLitEntropy true in default configuration [#286](https://github.com/klauspost/compress/pull/286)
+
+* Sept 8, 2020 (v1.11.0)
+ * zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281)
+ * zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282)
+ * inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274)
+
+
+
+ See changes to v1.10.x
+
+* July 8, 2020 (v1.10.11)
+ * zstd: Fix extra block when compressing with ReadFrom. [#278](https://github.com/klauspost/compress/pull/278)
+ * huff0: Also populate compression table when reading decoding table. [#275](https://github.com/klauspost/compress/pull/275)
+
+* June 23, 2020 (v1.10.10)
+ * zstd: Skip entropy compression in fastest mode when no matches. [#270](https://github.com/klauspost/compress/pull/270)
+
+* June 16, 2020 (v1.10.9):
+ * zstd: API change for specifying dictionaries. See [#268](https://github.com/klauspost/compress/pull/268)
+ * zip: update CreateHeaderRaw to handle zip64 fields. [#266](https://github.com/klauspost/compress/pull/266)
+ * Fuzzit tests removed. The service has been purchased and is no longer available.
+
+* June 5, 2020 (v1.10.8):
+ * 1.15x faster zstd block decompression. [#265](https://github.com/klauspost/compress/pull/265)
+
+* June 1, 2020 (v1.10.7):
+ * Added zstd decompression [dictionary support](https://github.com/klauspost/compress/tree/master/zstd#dictionaries)
+ * Increase zstd decompression speed up to 1.19x. [#259](https://github.com/klauspost/compress/pull/259)
+ * Remove internal reset call in zstd compression and reduce allocations. [#263](https://github.com/klauspost/compress/pull/263)
+
+* May 21, 2020: (v1.10.6)
+ * zstd: Reduce allocations while decoding. [#258](https://github.com/klauspost/compress/pull/258), [#252](https://github.com/klauspost/compress/pull/252)
+ * zstd: Stricter decompression checks.
+
+* April 12, 2020: (v1.10.5)
+ * s2-commands: Flush output when receiving SIGINT. [#239](https://github.com/klauspost/compress/pull/239)
+
+* Apr 8, 2020: (v1.10.4)
+ * zstd: Minor/special case optimizations. [#251](https://github.com/klauspost/compress/pull/251), [#250](https://github.com/klauspost/compress/pull/250), [#249](https://github.com/klauspost/compress/pull/249), [#247](https://github.com/klauspost/compress/pull/247)
+* Mar 11, 2020: (v1.10.3)
+ * s2: Use S2 encoder in pure Go mode for Snappy output as well. [#245](https://github.com/klauspost/compress/pull/245)
+ * s2: Fix pure Go block encoder. [#244](https://github.com/klauspost/compress/pull/244)
+ * zstd: Added "better compression" mode. [#240](https://github.com/klauspost/compress/pull/240)
+ * zstd: Improve speed of fastest compression mode by 5-10% [#241](https://github.com/klauspost/compress/pull/241)
+ * zstd: Skip creating encoders when not needed. [#238](https://github.com/klauspost/compress/pull/238)
+
+* Feb 27, 2020: (v1.10.2)
+ * Close to 50% speedup in inflate (gzip/zip decompression). [#236](https://github.com/klauspost/compress/pull/236) [#234](https://github.com/klauspost/compress/pull/234) [#232](https://github.com/klauspost/compress/pull/232)
+ * Reduce deflate level 1-6 memory usage up to 59%. [#227](https://github.com/klauspost/compress/pull/227)
+
+* Feb 18, 2020: (v1.10.1)
+ * Fix zstd crash when resetting multiple times without sending data. [#226](https://github.com/klauspost/compress/pull/226)
+ * deflate: Fix dictionary use on level 1-6. [#224](https://github.com/klauspost/compress/pull/224)
+ * Remove deflate writer reference when closing. [#224](https://github.com/klauspost/compress/pull/224)
+
+* Feb 4, 2020: (v1.10.0)
+ * Add optional dictionary to [stateless deflate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc#StatelessDeflate). Breaking change, send `nil` for previous behaviour. [#216](https://github.com/klauspost/compress/pull/216)
+ * Fix buffer overflow on repeated small block deflate. [#218](https://github.com/klauspost/compress/pull/218)
+ * Allow copying content from an existing ZIP file without decompressing+compressing. [#214](https://github.com/klauspost/compress/pull/214)
+ * Added [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) AMD64 assembler and various optimizations. Stream speed >10GB/s. [#186](https://github.com/klauspost/compress/pull/186)
+
+
+
+
+ See changes prior to v1.10.0
+
+* Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. [#207](https://github.com/klauspost/compress/pull/207) by [luyu6056](https://github.com/luyu6056), [#206](https://github.com/klauspost/compress/pull/206).
+* Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. [#204](https://github.com/klauspost/compress/pull/204)
+* Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed.
+* Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases.
+* Jan 4, 2020: Faster IO in [s2c + s2d commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) compression/decompression. [#192](https://github.com/klauspost/compress/pull/192)
+* Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder.
+* Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. [#199](https://github.com/klauspost/compress/pull/199)
+* Dec 29, 2019: [zip](https://godoc.org/github.com/klauspost/compress/zip) package updated with latest Go features
+* Dec 29, 2019: zstd: Single segment flag condintions tweaked. [#197](https://github.com/klauspost/compress/pull/197)
+* Dec 18, 2019: s2: Faster compression when ReadFrom is used. [#198](https://github.com/klauspost/compress/pull/198)
+* Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit.
+* Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. [#191](https://github.com/klauspost/compress/pull/191)
+* Dec 3, 2019: (v1.9.4) S2: limit max repeat length. [#188](https://github.com/klauspost/compress/pull/188)
+* Dec 3, 2019: Add [WithNoEntropyCompression](https://godoc.org/github.com/klauspost/compress/zstd#WithNoEntropyCompression) to zstd [#187](https://github.com/klauspost/compress/pull/187)
+* Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines.
+* Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate.
+* Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. [#184](https://github.com/klauspost/compress/pull/184)
+* Nov 12, 2019 (v1.9.2) Added [Stateless Compression](#stateless-compression) for gzip/deflate.
+* Nov 12, 2019: Fixed zstd decompression of large single blocks. [#180](https://github.com/klauspost/compress/pull/180)
+* Nov 11, 2019: Set default [s2c](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) block size to 4MB.
+* Nov 11, 2019: Reduce inflate memory use by 1KB.
+* Nov 10, 2019: Less allocations in deflate bit writer.
+* Nov 10, 2019: Fix inconsistent error returned by zstd decoder.
+* Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. [#174](https://github.com/klauspost/compress/pull/174)
+* Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption [#173](https://github.com/klauspost/compress/pull/173)
+* Oct 24, 2019 zstd: Fix huff0 out of buffer write [#171](https://github.com/klauspost/compress/pull/171) and always return errors [#172](https://github.com/klauspost/compress/pull/172)
+* Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression [#105](https://github.com/klauspost/compress/pull/105)
+
+
+
+
+ See changes prior to v1.9.0
+
+* Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. [#169](https://github.com/klauspost/compress/pull/169)
+* Oct 3, 2019: Fix inconsistent results on broken zstd streams.
+* Sep 25, 2019: Added `-rm` (remove source files) and `-q` (no output except errors) to `s2c` and `s2d` [commands](https://github.com/klauspost/compress/tree/master/s2#commandline-tools)
+* Sep 16, 2019: (v1.8.4) Add `s2c` and `s2d` [commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools).
+* Sep 10, 2019: (v1.8.3) Fix s2 decoder [Skip](https://godoc.org/github.com/klauspost/compress/s2#Reader.Skip).
+* Sep 7, 2019: zstd: Added [WithWindowSize](https://godoc.org/github.com/klauspost/compress/zstd#WithWindowSize), contributed by [ianwilkes](https://github.com/ianwilkes).
+* Sep 5, 2019: (v1.8.2) Add [WithZeroFrames](https://godoc.org/github.com/klauspost/compress/zstd#WithZeroFrames) which adds full zero payload block encoding option.
+* Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables.
+* Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode.
+* Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding.
+* Aug 24, 2019: (v1.8.0) Added [S2 compression](https://github.com/klauspost/compress/tree/master/s2#s2-compression), a high performance replacement for Snappy.
+* Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing.
+* Aug 18, 2019: Add [fuzzit](https://fuzzit.dev/) continuous fuzzing.
+* Aug 14, 2019: zstd: Skip incompressible data 2x faster. [#147](https://github.com/klauspost/compress/pull/147)
+* Aug 4, 2019 (v1.7.5): Better literal compression. [#146](https://github.com/klauspost/compress/pull/146)
+* Aug 4, 2019: Faster zstd compression. [#143](https://github.com/klauspost/compress/pull/143) [#144](https://github.com/klauspost/compress/pull/144)
+* Aug 4, 2019: Faster zstd decompression. [#145](https://github.com/klauspost/compress/pull/145) [#143](https://github.com/klauspost/compress/pull/143) [#142](https://github.com/klauspost/compress/pull/142)
+* July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder.
+* July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder.
+* July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content.
+* July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix.
+* June 17, 2019: zstd decompression bugfix.
+* June 17, 2019: fix 32 bit builds.
+* June 17, 2019: Easier use in modules (less dependencies).
+* June 9, 2019: New stronger "default" [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression mode. Matches zstd default compression ratio.
+* June 5, 2019: 20-40% throughput in [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and better compression.
+* June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels.
+* June 2, 2019: Added [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression!
+* May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels.
+* Apr 22, 2019: [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) decompression added.
+* Aug 1, 2018: Added [huff0 README](https://github.com/klauspost/compress/tree/master/huff0#huff0-entropy-compression).
+* Jul 8, 2018: Added [Performance Update 2018](#performance-update-2018) below.
+* Jun 23, 2018: Merged [Go 1.11 inflate optimizations](https://go-review.googlesource.com/c/go/+/102235). Go 1.9 is now required. Backwards compatible version tagged with [v1.3.0](https://github.com/klauspost/compress/releases/tag/v1.3.0).
+* Apr 2, 2018: Added [huff0](https://godoc.org/github.com/klauspost/compress/huff0) en/decoder. Experimental for now, API may change.
+* Mar 4, 2018: Added [FSE Entropy](https://godoc.org/github.com/klauspost/compress/fse) en/decoder. Experimental for now, API may change.
+* Nov 3, 2017: Add compression [Estimate](https://godoc.org/github.com/klauspost/compress#Estimate) function.
+* May 28, 2017: Reduce allocations when resetting decoder.
+* Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7.
+* Jan 14, 2017: Reduce stack pressure due to array copies. See [Issue #18625](https://github.com/golang/go/issues/18625).
+* Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before.
+* Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update.
+* Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level.
+* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression.
+* Mar 24, 2016: Small speedup for level 1-3.
+* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster.
+* Feb 19, 2016: Handle small payloads faster in level 1-3.
+* Feb 19, 2016: Added faster level 2 + 3 compression modes.
+* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5.
+* Feb 14, 2016: Snappy: Merge upstream changes.
+* Feb 14, 2016: Snappy: Fix aggressive skipping.
+* Feb 14, 2016: Snappy: Update benchmark.
+* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression.
+* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%.
+* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content.
+* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup.
+* Jan 16, 2016: Optimization on deflate level 1,2,3 compression.
+* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives.
+* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs.
+* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms.
+* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update!
+* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet).
+* Nov 20 2015: Small optimization to bit writer on 64 bit systems.
+* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15).
+* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate.
+* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file
+* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x.
+
+
+
+# deflate usage
+
+The packages are drop-in replacements for standard library [deflate](https://godoc.org/github.com/klauspost/compress/flate), [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip), and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). Simply replace the import path to use them:
+
+Typical speed is about 2x of the standard library packages.
+
+| old import | new import | Documentation |
+|------------------|---------------------------------------|-------------------------------------------------------------------------|
+| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc) |
+| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc) |
+| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) |
+| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) |
+
+You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages.
+
+The packages implement the same API as the standard library, so you can use the original godoc documentation: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/).
+
+Currently there is only minor speedup on decompression (mostly CRC32 calculation).
+
+Memory usage is typically 1MB for a Writer. stdlib is in the same range.
+If you expect to have a lot of concurrently allocated Writers consider using
+the stateless compression described below.
+
+For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing).
+
+To disable all assembly add `-tags=noasm`. This works across all packages.
+
+# Stateless compression
+
+This package offers stateless compression as a special option for gzip/deflate.
+It will do compression but without maintaining any state between Write calls.
+
+This means there will be no memory kept between Write calls, but compression and speed will be suboptimal.
+
+This is only relevant in cases where you expect to run many thousands of compressors concurrently,
+but with very little activity. This is *not* intended for regular web servers serving individual requests.
+
+Because of this, the size of actual Write calls will affect output size.
+
+In gzip, specify level `-3` / `gzip.StatelessCompression` to enable.
+
+For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See [documentation](https://godoc.org/github.com/klauspost/compress/flate#NewStatelessWriter)
+
+A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer:
+
+```go
+ // replace 'ioutil.Discard' with your output.
+ gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression)
+ if err != nil {
+ return err
+ }
+ defer gzw.Close()
+
+ w := bufio.NewWriterSize(gzw, 4096)
+ defer w.Flush()
+
+ // Write to 'w'
+```
+
+This will only use up to 4KB in memory when the writer is idle.
+
+Compression is almost always worse than the fastest compression level
+and each write will allocate (a little) memory.
+
+
+# Other packages
+
+Here are other packages of good quality and pure Go (no cgo wrappers or autoconverted code):
+
+* [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression.
+* [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression.
+* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer.
+* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression.
+* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression.
+* [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index.
+* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor.
+
+# license
+
+This code is licensed under the same conditions as the original Go code. See LICENSE file.
+
+
+
+
+
diff --git a/vendor/github.com/klauspost/compress/SECURITY.md b/vendor/github.com/klauspost/compress/SECURITY.md
new file mode 100644
index 00000000..ca6685e2
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/SECURITY.md
@@ -0,0 +1,25 @@
+# Security Policy
+
+## Supported Versions
+
+Security updates are applied only to the latest release.
+
+## Vulnerability Definition
+
+A security vulnerability is a bug that with certain input triggers a crash or an infinite loop. Most calls will have varying execution time and only in rare cases will slow operation be considered a security vulnerability.
+
+Corrupted output generally is not considered a security vulnerability, unless independent operations are able to affect each other. Note that not all functionality is re-entrant and safe to use concurrently.
+
+Out-of-memory crashes only applies if the en/decoder uses an abnormal amount of memory, with appropriate options applied, to limit maximum window size, concurrency, etc. However, if you are in doubt you are welcome to file a security issue.
+
+It is assumed that all callers are trusted, meaning internal data exposed through reflection or inspection of returned data structures is not considered a vulnerability.
+
+Vulnerabilities resulting from compiler/assembler errors should be reported upstream. Depending on the severity this package may or may not implement a workaround.
+
+## Reporting a Vulnerability
+
+If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
+
+Please disclose it at [security advisory](https://github.com/klauspost/compress/security/advisories/new). If possible please provide a minimal reproducer. If the issue only applies to a single platform, it would be helpful to provide access to that.
+
+This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base.
diff --git a/vendor/github.com/klauspost/compress/compressible.go b/vendor/github.com/klauspost/compress/compressible.go
new file mode 100644
index 00000000..ea5a692d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/compressible.go
@@ -0,0 +1,85 @@
+package compress
+
+import "math"
+
+// Estimate returns a normalized compressibility estimate of block b.
+// Values close to zero are likely uncompressible.
+// Values above 0.1 are likely to be compressible.
+// Values above 0.5 are very compressible.
+// Very small lengths will return 0.
+func Estimate(b []byte) float64 {
+ if len(b) < 16 {
+ return 0
+ }
+
+ // Correctly predicted order 1
+ hits := 0
+ lastMatch := false
+ var o1 [256]byte
+ var hist [256]int
+ c1 := byte(0)
+ for _, c := range b {
+ if c == o1[c1] {
+ // We only count a hit if there was two correct predictions in a row.
+ if lastMatch {
+ hits++
+ }
+ lastMatch = true
+ } else {
+ lastMatch = false
+ }
+ o1[c1] = c
+ c1 = c
+ hist[c]++
+ }
+
+ // Use x^0.6 to give better spread
+ prediction := math.Pow(float64(hits)/float64(len(b)), 0.6)
+
+ // Calculate histogram distribution
+ variance := float64(0)
+ avg := float64(len(b)) / 256
+
+ for _, v := range hist {
+ Δ := float64(v) - avg
+ variance += Δ * Δ
+ }
+
+ stddev := math.Sqrt(float64(variance)) / float64(len(b))
+ exp := math.Sqrt(1 / float64(len(b)))
+
+ // Subtract expected stddev
+ stddev -= exp
+ if stddev < 0 {
+ stddev = 0
+ }
+ stddev *= 1 + exp
+
+ // Use x^0.4 to give better spread
+ entropy := math.Pow(stddev, 0.4)
+
+ // 50/50 weight between prediction and histogram distribution
+ return math.Pow((prediction+entropy)/2, 0.9)
+}
+
+// ShannonEntropyBits returns the number of bits minimum required to represent
+// an entropy encoding of the input bytes.
+// https://en.wiktionary.org/wiki/Shannon_entropy
+func ShannonEntropyBits(b []byte) int {
+ if len(b) == 0 {
+ return 0
+ }
+ var hist [256]int
+ for _, c := range b {
+ hist[c]++
+ }
+ shannon := float64(0)
+ invTotal := 1.0 / float64(len(b))
+ for _, v := range hist[:] {
+ if v > 0 {
+ n := float64(v)
+ shannon += math.Ceil(-math.Log2(n*invTotal) * n)
+ }
+ }
+ return int(math.Ceil(shannon))
+}
diff --git a/vendor/github.com/klauspost/compress/fse/README.md b/vendor/github.com/klauspost/compress/fse/README.md
new file mode 100644
index 00000000..27d8ed56
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/README.md
@@ -0,0 +1,79 @@
+# Finite State Entropy
+
+This package provides Finite State Entropy encoding and decoding.
+
+Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS))
+encoding provides a fast near-optimal symbol encoding/decoding
+for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd).
+
+This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
+This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
+but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
+
+* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse)
+
+## News
+
+ * Feb 2018: First implementation released. Consider this beta software for now.
+
+# Usage
+
+This package provides a low level interface that allows to compress single independent blocks.
+
+Each block is separate, and there is no built in integrity checks.
+This means that the caller should keep track of block sizes and also do checksums if needed.
+
+Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function.
+You must provide input and will receive the output and maybe an error.
+
+These error values can be returned:
+
+| Error | Description |
+|---------------------|-----------------------------------------------------------------------------|
+| `` | Everything ok, output is returned |
+| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
+| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
+| `(error)` | An internal error occurred. |
+
+As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.
+
+To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object
+that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
+object can be used for both.
+
+Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
+you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
+
+Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function.
+You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
+your input was likely corrupted.
+
+It is important to note that a successful decoding does *not* mean your output matches your original input.
+There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
+
+For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples).
+
+# Performance
+
+A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
+All compression functions are currently only running on the calling goroutine so only one core will be used per block.
+
+The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
+is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be
+beneficial to transpose all your input values down by 64.
+
+With moderate block sizes around 64k speed are typically 200MB/s per core for compression and
+around 300MB/s decompression speed.
+
+The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.
+
+# Plans
+
+At one point, more internals will be exposed to facilitate more "expert" usage of the components.
+
+A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261).
+
+# Contributing
+
+Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
+changes will likely not be accepted. If in doubt open an issue before writing the PR.
\ No newline at end of file
diff --git a/vendor/github.com/klauspost/compress/fse/bitreader.go b/vendor/github.com/klauspost/compress/fse/bitreader.go
new file mode 100644
index 00000000..f65eb390
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/bitreader.go
@@ -0,0 +1,122 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+// bitReader reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReader struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReader) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.bitsRead += 8 - uint8(highBits(uint32(v)))
+ return nil
+}
+
+// getBits will return n bits. n can be 0.
+func (b *bitReader) getBits(n uint8) uint16 {
+ if n == 0 || b.bitsRead >= 64 {
+ return 0
+ }
+ return b.getBitsFast(n)
+}
+
+// getBitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReader) getBitsFast(n uint8) uint16 {
+ const regMask = 64 - 1
+ v := uint16((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
+ b.bitsRead += n
+ return v
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReader) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+ // 2 bounds checks.
+ v := b.in[b.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value = (b.value << 32) | uint64(low)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReader) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off > 4 {
+ v := b.in[b.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ b.value = (b.value << 32) | uint64(low)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value = (b.value << 8) | uint64(b.in[b.off-1])
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
+func (b *bitReader) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = binary.LittleEndian.Uint64(b.in[b.off-8:])
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReader) finished() bool {
+ return b.bitsRead >= 64 && b.off == 0
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReader) close() error {
+ // Release reference.
+ b.in = nil
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/fse/bitwriter.go b/vendor/github.com/klauspost/compress/fse/bitwriter.go
new file mode 100644
index 00000000..d58b3fe4
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/bitwriter.go
@@ -0,0 +1,167 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+import "fmt"
+
+// bitWriter will write bits.
+// First bit will be LSB of the first byte of output.
+type bitWriter struct {
+ bitContainer uint64
+ nBits uint8
+ out []byte
+}
+
+// bitMask16 is bitmasks. Has extra to avoid bounds check.
+var bitMask16 = [32]uint16{
+ 0, 1, 3, 7, 0xF, 0x1F,
+ 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF} /* up to 16 bits */
+
+// addBits16NC will add up to 16 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16NC(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits16ZeroNC will add up to 16 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+// This is fastest if bits can be zero.
+func (b *bitWriter) addBits16ZeroNC(value uint16, bits uint8) {
+ if bits == 0 {
+ return
+ }
+ value <<= (16 - bits) & 15
+ value >>= (16 - bits) & 15
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// flush will flush all pending full bytes.
+// There will be at least 56 bits available for writing when this has been called.
+// Using flush32 is faster, but leaves less space for writing.
+func (b *bitWriter) flush() {
+ v := b.nBits >> 3
+ switch v {
+ case 0:
+ case 1:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ )
+ case 2:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ )
+ case 3:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ )
+ case 4:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ )
+ case 5:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ )
+ case 6:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ byte(b.bitContainer>>40),
+ )
+ case 7:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ byte(b.bitContainer>>40),
+ byte(b.bitContainer>>48),
+ )
+ case 8:
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24),
+ byte(b.bitContainer>>32),
+ byte(b.bitContainer>>40),
+ byte(b.bitContainer>>48),
+ byte(b.bitContainer>>56),
+ )
+ default:
+ panic(fmt.Errorf("bits (%d) > 64", b.nBits))
+ }
+ b.bitContainer >>= v << 3
+ b.nBits &= 7
+}
+
+// flush32 will flush out, so there are at least 32 bits available for writing.
+func (b *bitWriter) flush32() {
+ if b.nBits < 32 {
+ return
+ }
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24))
+ b.nBits -= 32
+ b.bitContainer >>= 32
+}
+
+// flushAlign will flush remaining full bytes and align to next byte boundary.
+func (b *bitWriter) flushAlign() {
+ nbBytes := (b.nBits + 7) >> 3
+ for i := range nbBytes {
+ b.out = append(b.out, byte(b.bitContainer>>(i*8)))
+ }
+ b.nBits = 0
+ b.bitContainer = 0
+}
+
+// close will write the alignment bit and write the final byte(s)
+// to the output.
+func (b *bitWriter) close() {
+ // End mark
+ b.addBits16Clean(1, 1)
+ // flush until next byte.
+ b.flushAlign()
+}
+
+// reset and continue writing by appending to out.
+func (b *bitWriter) reset(out []byte) {
+ b.bitContainer = 0
+ b.nBits = 0
+ b.out = out
+}
diff --git a/vendor/github.com/klauspost/compress/fse/bytereader.go b/vendor/github.com/klauspost/compress/fse/bytereader.go
new file mode 100644
index 00000000..abade2d6
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/bytereader.go
@@ -0,0 +1,47 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+// byteReader provides a byte reader that reads
+// little endian values from a byte stream.
+// The input stream is manually advanced.
+// The reader performs no bounds checks.
+type byteReader struct {
+ b []byte
+ off int
+}
+
+// init will initialize the reader and set the input.
+func (b *byteReader) init(in []byte) {
+ b.b = in
+ b.off = 0
+}
+
+// advance the stream b n bytes.
+func (b *byteReader) advance(n uint) {
+ b.off += int(n)
+}
+
+// Uint32 returns a little endian uint32 starting at current offset.
+func (b byteReader) Uint32() uint32 {
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// unread returns the unread portion of the input.
+func (b byteReader) unread() []byte {
+ return b.b[b.off:]
+}
+
+// remain will return the number of bytes remaining.
+func (b byteReader) remain() int {
+ return len(b.b) - b.off
+}
diff --git a/vendor/github.com/klauspost/compress/fse/compress.go b/vendor/github.com/klauspost/compress/fse/compress.go
new file mode 100644
index 00000000..8c8baa4f
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/compress.go
@@ -0,0 +1,683 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package fse
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Compress the input bytes. Input must be < 2GB.
+// Provide a Scratch buffer to avoid memory allocations.
+// Note that the output is also kept in the scratch buffer.
+// If input is too hard to compress, ErrIncompressible is returned.
+// If input is a single byte value repeated ErrUseRLE is returned.
+func Compress(in []byte, s *Scratch) ([]byte, error) {
+ if len(in) <= 1 {
+ return nil, ErrIncompressible
+ }
+ if len(in) > (2<<30)-1 {
+ return nil, errors.New("input too big, must be < 2GB")
+ }
+ s, err := s.prepare(in)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create histogram, if none was provided.
+ maxCount := s.maxCount
+ if maxCount == 0 {
+ maxCount = s.countSimple(in)
+ }
+ // Reset for next run.
+ s.clearCount = true
+ s.maxCount = 0
+ if maxCount == len(in) {
+ // One symbol, use RLE
+ return nil, ErrUseRLE
+ }
+ if maxCount == 1 || maxCount < (len(in)>>7) {
+ // Each symbol present maximum once or too well distributed.
+ return nil, ErrIncompressible
+ }
+ s.optimalTableLog()
+ err = s.normalizeCount()
+ if err != nil {
+ return nil, err
+ }
+ err = s.writeCount()
+ if err != nil {
+ return nil, err
+ }
+
+ if false {
+ err = s.validateNorm()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ err = s.buildCTable()
+ if err != nil {
+ return nil, err
+ }
+ err = s.compress(in)
+ if err != nil {
+ return nil, err
+ }
+ s.Out = s.bw.out
+ // Check if we compressed.
+ if len(s.Out) >= len(in) {
+ return nil, ErrIncompressible
+ }
+ return s.Out, nil
+}
+
+// cState contains the compression state of a stream.
+type cState struct {
+ bw *bitWriter
+ stateTable []uint16
+ state uint16
+}
+
+// init will initialize the compression state to the first symbol of the stream.
+func (c *cState) init(bw *bitWriter, ct *cTable, tableLog uint8, first symbolTransform) {
+ c.bw = bw
+ c.stateTable = ct.stateTable
+
+ nbBitsOut := (first.deltaNbBits + (1 << 15)) >> 16
+ im := int32((nbBitsOut << 16) - first.deltaNbBits)
+ lu := (im >> nbBitsOut) + first.deltaFindState
+ c.state = c.stateTable[lu]
+}
+
+// encode the output symbol provided and write it to the bitstream.
+func (c *cState) encode(symbolTT symbolTransform) {
+ nbBitsOut := (uint32(c.state) + symbolTT.deltaNbBits) >> 16
+ dstState := int32(c.state>>(nbBitsOut&15)) + symbolTT.deltaFindState
+ c.bw.addBits16NC(c.state, uint8(nbBitsOut))
+ c.state = c.stateTable[dstState]
+}
+
+// encode the output symbol provided and write it to the bitstream.
+func (c *cState) encodeZero(symbolTT symbolTransform) {
+ nbBitsOut := (uint32(c.state) + symbolTT.deltaNbBits) >> 16
+ dstState := int32(c.state>>(nbBitsOut&15)) + symbolTT.deltaFindState
+ c.bw.addBits16ZeroNC(c.state, uint8(nbBitsOut))
+ c.state = c.stateTable[dstState]
+}
+
+// flush will write the tablelog to the output and flush the remaining full bytes.
+func (c *cState) flush(tableLog uint8) {
+ c.bw.flush32()
+ c.bw.addBits16NC(c.state, tableLog)
+ c.bw.flush()
+}
+
+// compress is the main compression loop that will encode the input from the last byte to the first.
+func (s *Scratch) compress(src []byte) error {
+ if len(src) <= 2 {
+ return errors.New("compress: src too small")
+ }
+ tt := s.ct.symbolTT[:256]
+ s.bw.reset(s.Out)
+
+ // Our two states each encodes every second byte.
+ // Last byte encoded (first byte decoded) will always be encoded by c1.
+ var c1, c2 cState
+
+ // Encode so remaining size is divisible by 4.
+ ip := len(src)
+ if ip&1 == 1 {
+ c1.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-1]])
+ c2.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-2]])
+ c1.encodeZero(tt[src[ip-3]])
+ ip -= 3
+ } else {
+ c2.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-1]])
+ c1.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-2]])
+ ip -= 2
+ }
+ if ip&2 != 0 {
+ c2.encodeZero(tt[src[ip-1]])
+ c1.encodeZero(tt[src[ip-2]])
+ ip -= 2
+ }
+ src = src[:ip]
+
+ // Main compression loop.
+ switch {
+ case !s.zeroBits && s.actualTableLog <= 8:
+ // We can encode 4 symbols without requiring a flush.
+ // We do not need to check if any output is 0 bits.
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encode(tt[v0])
+ c1.encode(tt[v1])
+ c2.encode(tt[v2])
+ c1.encode(tt[v3])
+ }
+ case !s.zeroBits:
+ // We do not need to check if any output is 0 bits.
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encode(tt[v0])
+ c1.encode(tt[v1])
+ s.bw.flush32()
+ c2.encode(tt[v2])
+ c1.encode(tt[v3])
+ }
+ case s.actualTableLog <= 8:
+ // We can encode 4 symbols without requiring a flush
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encodeZero(tt[v0])
+ c1.encodeZero(tt[v1])
+ c2.encodeZero(tt[v2])
+ c1.encodeZero(tt[v3])
+ }
+ default:
+ for ; len(src) >= 4; src = src[:len(src)-4] {
+ s.bw.flush32()
+ v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
+ c2.encodeZero(tt[v0])
+ c1.encodeZero(tt[v1])
+ s.bw.flush32()
+ c2.encodeZero(tt[v2])
+ c1.encodeZero(tt[v3])
+ }
+ }
+
+ // Flush final state.
+ // Used to initialize state when decoding.
+ c2.flush(s.actualTableLog)
+ c1.flush(s.actualTableLog)
+
+ s.bw.close()
+ return nil
+}
+
+// writeCount will write the normalized histogram count to header.
+// This is read back by readNCount.
+func (s *Scratch) writeCount() error {
+ var (
+ tableLog = s.actualTableLog
+ tableSize = 1 << tableLog
+ previous0 bool
+ charnum uint16
+
+ maxHeaderSize = ((int(s.symbolLen)*int(tableLog) + 4 + 2) >> 3) + 3
+
+ // Write Table Size
+ bitStream = uint32(tableLog - minTablelog)
+ bitCount = uint(4)
+ remaining = int16(tableSize + 1) /* +1 for extra accuracy */
+ threshold = int16(tableSize)
+ nbBits = uint(tableLog + 1)
+ )
+ if cap(s.Out) < maxHeaderSize {
+ s.Out = make([]byte, 0, s.br.remain()+maxHeaderSize)
+ }
+ outP := uint(0)
+ out := s.Out[:maxHeaderSize]
+
+ // stops at 1
+ for remaining > 1 {
+ if previous0 {
+ start := charnum
+ for s.norm[charnum] == 0 {
+ charnum++
+ }
+ for charnum >= start+24 {
+ start += 24
+ bitStream += uint32(0xFFFF) << bitCount
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ }
+ for charnum >= start+3 {
+ start += 3
+ bitStream += 3 << bitCount
+ bitCount += 2
+ }
+ bitStream += uint32(charnum-start) << bitCount
+ bitCount += 2
+ if bitCount > 16 {
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ bitCount -= 16
+ }
+ }
+
+ count := s.norm[charnum]
+ charnum++
+ max := (2*threshold - 1) - remaining
+ if count < 0 {
+ remaining += count
+ } else {
+ remaining -= count
+ }
+ count++ // +1 for extra accuracy
+ if count >= threshold {
+ count += max // [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[
+ }
+ bitStream += uint32(count) << bitCount
+ bitCount += nbBits
+ if count < max {
+ bitCount--
+ }
+
+ previous0 = count == 1
+ if remaining < 1 {
+ return errors.New("internal error: remaining<1")
+ }
+ for remaining < threshold {
+ nbBits--
+ threshold >>= 1
+ }
+
+ if bitCount > 16 {
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ bitCount -= 16
+ }
+ }
+
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += (bitCount + 7) / 8
+
+ if charnum > s.symbolLen {
+ return errors.New("internal error: charnum > s.symbolLen")
+ }
+ s.Out = out[:outP]
+ return nil
+}
+
+// symbolTransform contains the state transform for a symbol.
+type symbolTransform struct {
+ deltaFindState int32
+ deltaNbBits uint32
+}
+
+// String prints values as a human readable string.
+func (s symbolTransform) String() string {
+ return fmt.Sprintf("dnbits: %08x, fs:%d", s.deltaNbBits, s.deltaFindState)
+}
+
+// cTable contains tables used for compression.
+type cTable struct {
+ tableSymbol []byte
+ stateTable []uint16
+ symbolTT []symbolTransform
+}
+
+// allocCtable will allocate tables needed for compression.
+// If existing tables a re big enough, they are simply re-used.
+func (s *Scratch) allocCtable() {
+ tableSize := 1 << s.actualTableLog
+ // get tableSymbol that is big enough.
+ if cap(s.ct.tableSymbol) < tableSize {
+ s.ct.tableSymbol = make([]byte, tableSize)
+ }
+ s.ct.tableSymbol = s.ct.tableSymbol[:tableSize]
+
+ ctSize := tableSize
+ if cap(s.ct.stateTable) < ctSize {
+ s.ct.stateTable = make([]uint16, ctSize)
+ }
+ s.ct.stateTable = s.ct.stateTable[:ctSize]
+
+ if cap(s.ct.symbolTT) < 256 {
+ s.ct.symbolTT = make([]symbolTransform, 256)
+ }
+ s.ct.symbolTT = s.ct.symbolTT[:256]
+}
+
+// buildCTable will populate the compression table so it is ready to be used.
+func (s *Scratch) buildCTable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ var cumul [maxSymbolValue + 2]int16
+
+ s.allocCtable()
+ tableSymbol := s.ct.tableSymbol[:tableSize]
+ // symbol start positions
+ {
+ cumul[0] = 0
+ for ui, v := range s.norm[:s.symbolLen-1] {
+ u := byte(ui) // one less than reference
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = u
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ }
+ // Encode last symbol separately to avoid overflowing u
+ u := int(s.symbolLen - 1)
+ v := s.norm[s.symbolLen-1]
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = byte(u)
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ if uint32(cumul[s.symbolLen]) != tableSize {
+ return fmt.Errorf("internal error: expected cumul[s.symbolLen] (%d) == tableSize (%d)", cumul[s.symbolLen], tableSize)
+ }
+ cumul[s.symbolLen] = int16(tableSize) + 1
+ }
+ // Spread symbols
+ s.zeroBits = false
+ {
+ step := tableStep(tableSize)
+ tableMask := tableSize - 1
+ var position uint32
+ // if any symbol > largeLimit, we may have 0 bits output.
+ largeLimit := int16(1 << (s.actualTableLog - 1))
+ for ui, v := range s.norm[:s.symbolLen] {
+ symbol := byte(ui)
+ if v > largeLimit {
+ s.zeroBits = true
+ }
+ for range v {
+ tableSymbol[position] = symbol
+ position = (position + step) & tableMask
+ for position > highThreshold {
+ position = (position + step) & tableMask
+ } /* Low proba area */
+ }
+ }
+
+ // Check if we have gone through all positions
+ if position != 0 {
+ return errors.New("position!=0")
+ }
+ }
+
+ // Build table
+ table := s.ct.stateTable
+ {
+ tsi := int(tableSize)
+ for u, v := range tableSymbol {
+ // TableU16 : sorted by symbol order; gives next state value
+ table[cumul[v]] = uint16(tsi + u)
+ cumul[v]++
+ }
+ }
+
+ // Build Symbol Transformation Table
+ {
+ total := int16(0)
+ symbolTT := s.ct.symbolTT[:s.symbolLen]
+ tableLog := s.actualTableLog
+ tl := (uint32(tableLog) << 16) - (1 << tableLog)
+ for i, v := range s.norm[:s.symbolLen] {
+ switch v {
+ case 0:
+ case -1, 1:
+ symbolTT[i].deltaNbBits = tl
+ symbolTT[i].deltaFindState = int32(total - 1)
+ total++
+ default:
+ maxBitsOut := uint32(tableLog) - highBits(uint32(v-1))
+ minStatePlus := uint32(v) << maxBitsOut
+ symbolTT[i].deltaNbBits = (maxBitsOut << 16) - minStatePlus
+ symbolTT[i].deltaFindState = int32(total - v)
+ total += v
+ }
+ }
+ if total != int16(tableSize) {
+ return fmt.Errorf("total mismatch %d (got) != %d (want)", total, tableSize)
+ }
+ }
+ return nil
+}
+
+// countSimple will create a simple histogram in s.count.
+// Returns the biggest count.
+// Does not update s.clearCount.
+func (s *Scratch) countSimple(in []byte) (max int) {
+ for _, v := range in {
+ s.count[v]++
+ }
+ m, symlen := uint32(0), s.symbolLen
+ for i, v := range s.count[:] {
+ if v == 0 {
+ continue
+ }
+ if v > m {
+ m = v
+ }
+ symlen = uint16(i) + 1
+ }
+ s.symbolLen = symlen
+ return int(m)
+}
+
+// minTableLog provides the minimum logSize to safely represent a distribution.
+func (s *Scratch) minTableLog() uint8 {
+ minBitsSrc := highBits(uint32(s.br.remain()-1)) + 1
+ minBitsSymbols := highBits(uint32(s.symbolLen-1)) + 2
+ if minBitsSrc < minBitsSymbols {
+ return uint8(minBitsSrc)
+ }
+ return uint8(minBitsSymbols)
+}
+
+// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
+func (s *Scratch) optimalTableLog() {
+ tableLog := s.TableLog
+ minBits := s.minTableLog()
+ maxBitsSrc := uint8(highBits(uint32(s.br.remain()-1))) - 2
+ if maxBitsSrc < tableLog {
+ // Accuracy can be reduced
+ tableLog = maxBitsSrc
+ }
+ if minBits > tableLog {
+ tableLog = minBits
+ }
+ // Need a minimum to safely represent all symbol values
+ if tableLog < minTablelog {
+ tableLog = minTablelog
+ }
+ if tableLog > maxTableLog {
+ tableLog = maxTableLog
+ }
+ s.actualTableLog = tableLog
+}
+
+var rtbTable = [...]uint32{0, 473195, 504333, 520860, 550000, 700000, 750000, 830000}
+
+// normalizeCount will normalize the count of the symbols so
+// the total is equal to the table size.
+func (s *Scratch) normalizeCount() error {
+ var (
+ tableLog = s.actualTableLog
+ scale = 62 - uint64(tableLog)
+ step = (1 << 62) / uint64(s.br.remain())
+ vStep = uint64(1) << (scale - 20)
+ stillToDistribute = int16(1 << tableLog)
+ largest int
+ largestP int16
+ lowThreshold = (uint32)(s.br.remain() >> tableLog)
+ )
+
+ for i, cnt := range s.count[:s.symbolLen] {
+ // already handled
+ // if (count[s] == s.length) return 0; /* rle special case */
+
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ stillToDistribute--
+ } else {
+ proba := (int16)((uint64(cnt) * step) >> scale)
+ if proba < 8 {
+ restToBeat := vStep * uint64(rtbTable[proba])
+ v := uint64(cnt)*step - (uint64(proba) << scale)
+ if v > restToBeat {
+ proba++
+ }
+ }
+ if proba > largestP {
+ largestP = proba
+ largest = i
+ }
+ s.norm[i] = proba
+ stillToDistribute -= proba
+ }
+ }
+
+ if -stillToDistribute >= (s.norm[largest] >> 1) {
+ // corner case, need another normalization method
+ return s.normalizeCount2()
+ }
+ s.norm[largest] += stillToDistribute
+ return nil
+}
+
+// Secondary normalization method.
+// To be used when primary method fails.
+func (s *Scratch) normalizeCount2() error {
+ const notYetAssigned = -2
+ var (
+ distributed uint32
+ total = uint32(s.br.remain())
+ tableLog = s.actualTableLog
+ lowThreshold = total >> tableLog
+ lowOne = (total * 3) >> (tableLog + 1)
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ distributed++
+ total -= cnt
+ continue
+ }
+ if cnt <= lowOne {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ s.norm[i] = notYetAssigned
+ }
+ toDistribute := (1 << tableLog) - distributed
+
+ if (total / toDistribute) > lowOne {
+ // risk of rounding to zero
+ lowOne = (total * 3) / (toDistribute * 2)
+ for i, cnt := range s.count[:s.symbolLen] {
+ if (s.norm[i] == notYetAssigned) && (cnt <= lowOne) {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ }
+ toDistribute = (1 << tableLog) - distributed
+ }
+ if distributed == uint32(s.symbolLen)+1 {
+ // all values are pretty poor;
+ // probably incompressible data (should have already been detected);
+ // find max, then give all remaining points to max
+ var maxV int
+ var maxC uint32
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt > maxC {
+ maxV = i
+ maxC = cnt
+ }
+ }
+ s.norm[maxV] += int16(toDistribute)
+ return nil
+ }
+
+ if total == 0 {
+ // all of the symbols were low enough for the lowOne or lowThreshold
+ for i := uint32(0); toDistribute > 0; i = (i + 1) % (uint32(s.symbolLen)) {
+ if s.norm[i] > 0 {
+ toDistribute--
+ s.norm[i]++
+ }
+ }
+ return nil
+ }
+
+ var (
+ vStepLog = 62 - uint64(tableLog)
+ mid = uint64((1 << (vStepLog - 1)) - 1)
+ rStep = (((1 << vStepLog) * uint64(toDistribute)) + mid) / uint64(total) // scale on remaining
+ tmpTotal = mid
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if s.norm[i] == notYetAssigned {
+ var (
+ end = tmpTotal + uint64(cnt)*rStep
+ sStart = uint32(tmpTotal >> vStepLog)
+ sEnd = uint32(end >> vStepLog)
+ weight = sEnd - sStart
+ )
+ if weight < 1 {
+ return errors.New("weight < 1")
+ }
+ s.norm[i] = int16(weight)
+ tmpTotal = end
+ }
+ }
+ return nil
+}
+
+// validateNorm validates the normalized histogram table.
+func (s *Scratch) validateNorm() (err error) {
+ var total int
+ for _, v := range s.norm[:s.symbolLen] {
+ if v >= 0 {
+ total += int(v)
+ } else {
+ total -= int(v)
+ }
+ }
+ defer func() {
+ if err == nil {
+ return
+ }
+ fmt.Printf("selected TableLog: %d, Symbol length: %d\n", s.actualTableLog, s.symbolLen)
+ for i, v := range s.norm[:s.symbolLen] {
+ fmt.Printf("%3d: %5d -> %4d \n", i, s.count[i], v)
+ }
+ }()
+ if total != (1 << s.actualTableLog) {
+ return fmt.Errorf("warning: Total == %d != %d", total, 1< tablelogAbsoluteMax {
+ return errors.New("tableLog too large")
+ }
+ bitStream >>= 4
+ bitCount := uint(4)
+
+ s.actualTableLog = uint8(nbBits)
+ remaining := int32((1 << nbBits) + 1)
+ threshold := int32(1 << nbBits)
+ gotTotal := int32(0)
+ nbBits++
+
+ for remaining > 1 {
+ if previous0 {
+ n0 := charnum
+ for (bitStream & 0xFFFF) == 0xFFFF {
+ n0 += 24
+ if b.off < iend-5 {
+ b.advance(2)
+ bitStream = b.Uint32() >> bitCount
+ } else {
+ bitStream >>= 16
+ bitCount += 16
+ }
+ }
+ for (bitStream & 3) == 3 {
+ n0 += 3
+ bitStream >>= 2
+ bitCount += 2
+ }
+ n0 += uint16(bitStream & 3)
+ bitCount += 2
+ if n0 > maxSymbolValue {
+ return errors.New("maxSymbolValue too small")
+ }
+ for charnum < n0 {
+ s.norm[charnum&0xff] = 0
+ charnum++
+ }
+
+ if b.off <= iend-7 || b.off+int(bitCount>>3) <= iend-4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ bitStream = b.Uint32() >> bitCount
+ } else {
+ bitStream >>= 2
+ }
+ }
+
+ max := (2*(threshold) - 1) - (remaining)
+ var count int32
+
+ if (int32(bitStream) & (threshold - 1)) < max {
+ count = int32(bitStream) & (threshold - 1)
+ bitCount += nbBits - 1
+ } else {
+ count = int32(bitStream) & (2*threshold - 1)
+ if count >= threshold {
+ count -= max
+ }
+ bitCount += nbBits
+ }
+
+ count-- // extra accuracy
+ if count < 0 {
+ // -1 means +1
+ remaining += count
+ gotTotal -= count
+ } else {
+ remaining -= count
+ gotTotal += count
+ }
+ s.norm[charnum&0xff] = int16(count)
+ charnum++
+ previous0 = count == 0
+ for remaining < threshold {
+ nbBits--
+ threshold >>= 1
+ }
+ if b.off <= iend-7 || b.off+int(bitCount>>3) <= iend-4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ } else {
+ bitCount -= (uint)(8 * (len(b.b) - 4 - b.off))
+ b.off = len(b.b) - 4
+ }
+ bitStream = b.Uint32() >> (bitCount & 31)
+ }
+ s.symbolLen = charnum
+
+ if s.symbolLen <= 1 {
+ return fmt.Errorf("symbolLen (%d) too small", s.symbolLen)
+ }
+ if s.symbolLen > maxSymbolValue+1 {
+ return fmt.Errorf("symbolLen (%d) too big", s.symbolLen)
+ }
+ if remaining != 1 {
+ return fmt.Errorf("corruption detected (remaining %d != 1)", remaining)
+ }
+ if bitCount > 32 {
+ return fmt.Errorf("corruption detected (bitCount %d > 32)", bitCount)
+ }
+ if gotTotal != 1<> 3)
+ return nil
+}
+
+// decSymbol contains information about a state entry,
+// Including the state offset base, the output symbol and
+// the number of bits to read for the low part of the destination state.
+type decSymbol struct {
+ newState uint16
+ symbol uint8
+ nbBits uint8
+}
+
+// allocDtable will allocate decoding tables if they are not big enough.
+func (s *Scratch) allocDtable() {
+ tableSize := 1 << s.actualTableLog
+ if cap(s.decTable) < tableSize {
+ s.decTable = make([]decSymbol, tableSize)
+ }
+ s.decTable = s.decTable[:tableSize]
+
+ if cap(s.ct.tableSymbol) < 256 {
+ s.ct.tableSymbol = make([]byte, 256)
+ }
+ s.ct.tableSymbol = s.ct.tableSymbol[:256]
+
+ if cap(s.ct.stateTable) < 256 {
+ s.ct.stateTable = make([]uint16, 256)
+ }
+ s.ct.stateTable = s.ct.stateTable[:256]
+}
+
+// buildDtable will build the decoding table.
+func (s *Scratch) buildDtable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ s.allocDtable()
+ symbolNext := s.ct.stateTable[:256]
+
+ // Init, lay down lowprob symbols
+ s.zeroBits = false
+ {
+ largeLimit := int16(1 << (s.actualTableLog - 1))
+ for i, v := range s.norm[:s.symbolLen] {
+ if v == -1 {
+ s.decTable[highThreshold].symbol = uint8(i)
+ highThreshold--
+ symbolNext[i] = 1
+ } else {
+ if v >= largeLimit {
+ s.zeroBits = true
+ }
+ symbolNext[i] = uint16(v)
+ }
+ }
+ }
+ // Spread symbols
+ {
+ tableMask := tableSize - 1
+ step := tableStep(tableSize)
+ position := uint32(0)
+ for ss, v := range s.norm[:s.symbolLen] {
+ for i := 0; i < int(v); i++ {
+ s.decTable[position].symbol = uint8(ss)
+ position = (position + step) & tableMask
+ for position > highThreshold {
+ // lowprob area
+ position = (position + step) & tableMask
+ }
+ }
+ }
+ if position != 0 {
+ // position must reach all cells once, otherwise normalizedCounter is incorrect
+ return errors.New("corrupted input (position != 0)")
+ }
+ }
+
+ // Build Decoding table
+ {
+ tableSize := uint16(1 << s.actualTableLog)
+ for u, v := range s.decTable {
+ symbol := v.symbol
+ nextState := symbolNext[symbol]
+ symbolNext[symbol] = nextState + 1
+ nBits := s.actualTableLog - byte(highBits(uint32(nextState)))
+ s.decTable[u].nbBits = nBits
+ newState := (nextState << nBits) - tableSize
+ if newState >= tableSize {
+ return fmt.Errorf("newState (%d) outside table size (%d)", newState, tableSize)
+ }
+ if newState == uint16(u) && nBits == 0 {
+ // Seems weird that this is possible with nbits > 0.
+ return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, u)
+ }
+ s.decTable[u].newState = newState
+ }
+ }
+ return nil
+}
+
+// decompress will decompress the bitstream.
+// If the buffer is over-read an error is returned.
+func (s *Scratch) decompress() error {
+ br := &s.bits
+ if err := br.init(s.br.unread()); err != nil {
+ return err
+ }
+
+ var s1, s2 decoder
+ // Initialize and decode first state and symbol.
+ s1.init(br, s.decTable, s.actualTableLog)
+ s2.init(br, s.decTable, s.actualTableLog)
+
+ // Use temp table to avoid bound checks/append penalty.
+ var tmp = s.ct.tableSymbol[:256]
+ var off uint8
+
+ // Main part
+ if !s.zeroBits {
+ for br.off >= 8 {
+ br.fillFast()
+ tmp[off+0] = s1.nextFast()
+ tmp[off+1] = s2.nextFast()
+ br.fillFast()
+ tmp[off+2] = s1.nextFast()
+ tmp[off+3] = s2.nextFast()
+ off += 4
+ // When off is 0, we have overflowed and should write.
+ if off == 0 {
+ s.Out = append(s.Out, tmp...)
+ if len(s.Out) >= s.DecompressLimit {
+ return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit)
+ }
+ }
+ }
+ } else {
+ for br.off >= 8 {
+ br.fillFast()
+ tmp[off+0] = s1.next()
+ tmp[off+1] = s2.next()
+ br.fillFast()
+ tmp[off+2] = s1.next()
+ tmp[off+3] = s2.next()
+ off += 4
+ if off == 0 {
+ s.Out = append(s.Out, tmp...)
+ // When off is 0, we have overflowed and should write.
+ if len(s.Out) >= s.DecompressLimit {
+ return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit)
+ }
+ }
+ }
+ }
+ s.Out = append(s.Out, tmp[:off]...)
+
+ // Final bits, a bit more expensive check
+ for {
+ if s1.finished() {
+ s.Out = append(s.Out, s1.final(), s2.final())
+ break
+ }
+ br.fill()
+ s.Out = append(s.Out, s1.next())
+ if s2.finished() {
+ s.Out = append(s.Out, s2.final(), s1.final())
+ break
+ }
+ s.Out = append(s.Out, s2.next())
+ if len(s.Out) >= s.DecompressLimit {
+ return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit)
+ }
+ }
+ return br.close()
+}
+
+// decoder keeps track of the current state and updates it from the bitstream.
+type decoder struct {
+ state uint16
+ br *bitReader
+ dt []decSymbol
+}
+
+// init will initialize the decoder and read the first state from the stream.
+func (d *decoder) init(in *bitReader, dt []decSymbol, tableLog uint8) {
+ d.dt = dt
+ d.br = in
+ d.state = in.getBits(tableLog)
+}
+
+// next returns the next symbol and sets the next state.
+// At least tablelog bits must be available in the bit reader.
+func (d *decoder) next() uint8 {
+ n := &d.dt[d.state]
+ lowBits := d.br.getBits(n.nbBits)
+ d.state = n.newState + lowBits
+ return n.symbol
+}
+
+// finished returns true if all bits have been read from the bitstream
+// and the next state would require reading bits from the input.
+func (d *decoder) finished() bool {
+ return d.br.finished() && d.dt[d.state].nbBits > 0
+}
+
+// final returns the current state symbol without decoding the next.
+func (d *decoder) final() uint8 {
+ return d.dt[d.state].symbol
+}
+
+// nextFast returns the next symbol and sets the next state.
+// This can only be used if no symbols are 0 bits.
+// At least tablelog bits must be available in the bit reader.
+func (d *decoder) nextFast() uint8 {
+ n := d.dt[d.state]
+ lowBits := d.br.getBitsFast(n.nbBits)
+ d.state = n.newState + lowBits
+ return n.symbol
+}
diff --git a/vendor/github.com/klauspost/compress/fse/fse.go b/vendor/github.com/klauspost/compress/fse/fse.go
new file mode 100644
index 00000000..535cbadf
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/fse/fse.go
@@ -0,0 +1,144 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+// Package fse provides Finite State Entropy encoding and decoding.
+//
+// Finite State Entropy encoding provides a fast near-optimal symbol encoding/decoding
+// for byte blocks as implemented in zstd.
+//
+// See https://github.com/klauspost/compress/tree/master/fse for more information.
+package fse
+
+import (
+ "errors"
+ "fmt"
+ "math/bits"
+)
+
+const (
+ /*!MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
+ maxMemoryUsage = 14
+ defaultMemoryUsage = 13
+
+ maxTableLog = maxMemoryUsage - 2
+ maxTablesize = 1 << maxTableLog
+ defaultTablelog = defaultMemoryUsage - 2
+ minTablelog = 5
+ maxSymbolValue = 255
+)
+
+var (
+ // ErrIncompressible is returned when input is judged to be too hard to compress.
+ ErrIncompressible = errors.New("input is not compressible")
+
+ // ErrUseRLE is returned from the compressor when the input is a single byte value repeated.
+ ErrUseRLE = errors.New("input is single value repeated")
+)
+
+// Scratch provides temporary storage for compression and decompression.
+type Scratch struct {
+ // Private
+ count [maxSymbolValue + 1]uint32
+ norm [maxSymbolValue + 1]int16
+ br byteReader
+ bits bitReader
+ bw bitWriter
+ ct cTable // Compression tables.
+ decTable []decSymbol // Decompression table.
+ maxCount int // count of the most probable symbol
+
+ // Per block parameters.
+ // These can be used to override compression parameters of the block.
+ // Do not touch, unless you know what you are doing.
+
+ // Out is output buffer.
+ // If the scratch is re-used before the caller is done processing the output,
+ // set this field to nil.
+ // Otherwise the output buffer will be re-used for next Compression/Decompression step
+ // and allocation will be avoided.
+ Out []byte
+
+ // DecompressLimit limits the maximum decoded size acceptable.
+ // If > 0 decompression will stop when approximately this many bytes
+ // has been decoded.
+ // If 0, maximum size will be 2GB.
+ DecompressLimit int
+
+ symbolLen uint16 // Length of active part of the symbol table.
+ actualTableLog uint8 // Selected tablelog.
+ zeroBits bool // no bits has prob > 50%.
+ clearCount bool // clear count
+
+ // MaxSymbolValue will override the maximum symbol value of the next block.
+ MaxSymbolValue uint8
+
+ // TableLog will attempt to override the tablelog for the next block.
+ TableLog uint8
+}
+
+// Histogram allows to populate the histogram and skip that step in the compression,
+// It otherwise allows to inspect the histogram when compression is done.
+// To indicate that you have populated the histogram call HistogramFinished
+// with the value of the highest populated symbol, as well as the number of entries
+// in the most populated entry. These are accepted at face value.
+// The returned slice will always be length 256.
+func (s *Scratch) Histogram() []uint32 {
+ return s.count[:]
+}
+
+// HistogramFinished can be called to indicate that the histogram has been populated.
+// maxSymbol is the index of the highest set symbol of the next data segment.
+// maxCount is the number of entries in the most populated entry.
+// These are accepted at face value.
+func (s *Scratch) HistogramFinished(maxSymbol uint8, maxCount int) {
+ s.maxCount = maxCount
+ s.symbolLen = uint16(maxSymbol) + 1
+ s.clearCount = maxCount != 0
+}
+
+// prepare will prepare and allocate scratch tables used for both compression and decompression.
+func (s *Scratch) prepare(in []byte) (*Scratch, error) {
+ if s == nil {
+ s = &Scratch{}
+ }
+ if s.MaxSymbolValue == 0 {
+ s.MaxSymbolValue = 255
+ }
+ if s.TableLog == 0 {
+ s.TableLog = defaultTablelog
+ }
+ if s.TableLog > maxTableLog {
+ return nil, fmt.Errorf("tableLog (%d) > maxTableLog (%d)", s.TableLog, maxTableLog)
+ }
+ if cap(s.Out) == 0 {
+ s.Out = make([]byte, 0, len(in))
+ }
+ if s.clearCount && s.maxCount == 0 {
+ for i := range s.count {
+ s.count[i] = 0
+ }
+ s.clearCount = false
+ }
+ s.br.init(in)
+ if s.DecompressLimit == 0 {
+ // Max size 2GB.
+ s.DecompressLimit = (2 << 30) - 1
+ }
+
+ return s, nil
+}
+
+// tableStep returns the next table index.
+func tableStep(tableSize uint32) uint32 {
+ return (tableSize >> 1) + (tableSize >> 3) + 3
+}
+
+func highBits(val uint32) (n uint32) {
+ return uint32(bits.Len32(val) - 1)
+}
diff --git a/vendor/github.com/klauspost/compress/gen.sh b/vendor/github.com/klauspost/compress/gen.sh
new file mode 100644
index 00000000..aff94220
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/gen.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cd s2/cmd/_s2sx/ || exit 1
+go generate .
diff --git a/vendor/github.com/klauspost/compress/huff0/.gitignore b/vendor/github.com/klauspost/compress/huff0/.gitignore
new file mode 100644
index 00000000..b3d26295
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/.gitignore
@@ -0,0 +1 @@
+/huff0-fuzz.zip
diff --git a/vendor/github.com/klauspost/compress/huff0/README.md b/vendor/github.com/klauspost/compress/huff0/README.md
new file mode 100644
index 00000000..26d5101b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/README.md
@@ -0,0 +1,89 @@
+# Huff0 entropy compression
+
+This package provides Huff0 encoding and decoding as used in zstd.
+
+[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders),
+a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU
+(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.
+
+This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
+This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
+but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
+
+* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)
+
+## News
+
+This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package.
+
+This ensures that most functionality is well tested.
+
+# Usage
+
+This package provides a low level interface that allows to compress single independent blocks.
+
+Each block is separate, and there is no built in integrity checks.
+This means that the caller should keep track of block sizes and also do checksums if needed.
+
+Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and
+[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions.
+You must provide input and will receive the output and maybe an error.
+
+These error values can be returned:
+
+| Error | Description |
+|---------------------|-----------------------------------------------------------------------------|
+| `` | Everything ok, output is returned |
+| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
+| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
+| `ErrTooBig` | Returned if the input block exceeds the maximum allowed size (128 Kib) |
+| `(error)` | An internal error occurred. |
+
+
+As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.
+
+To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object
+that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
+object can be used for both.
+
+Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
+you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
+
+The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding.
+
+## Tables and re-use
+
+Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results.
+
+The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy)
+that controls this behaviour. See the documentation for details. This can be altered between each block.
+
+Do however note that this information is *not* stored in the output block and it is up to the users of the package to
+record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called,
+based on the boolean reported back from the CompressXX call.
+
+If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the
+[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object.
+
+## Decompressing
+
+The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable).
+This will initialize the decoding tables.
+You can supply the complete block to `ReadTable` and it will return the data part of the block
+which can be given to the decompressor.
+
+Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X)
+or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.
+
+For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
+
+You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
+your input was likely corrupted.
+
+It is important to note that a successful decoding does *not* mean your output matches your original input.
+There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
+
+# Contributing
+
+Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
+changes will likely not be accepted. If in doubt open an issue before writing the PR.
diff --git a/vendor/github.com/klauspost/compress/huff0/bitreader.go b/vendor/github.com/klauspost/compress/huff0/bitreader.go
new file mode 100644
index 00000000..bfc7a523
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/bitreader.go
@@ -0,0 +1,224 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package huff0
+
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+// bitReader reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReaderBytes struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReaderBytes) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.advance(8 - uint8(highBit32(uint32(v))))
+ return nil
+}
+
+// peekByteFast requires that at least one byte is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReaderBytes) peekByteFast() uint8 {
+ got := uint8(b.value >> 56)
+ return got
+}
+
+func (b *bitReaderBytes) advance(n uint8) {
+ b.bitsRead += n
+ b.value <<= n & 63
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReaderBytes) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+
+ // 2 bounds checks.
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << (b.bitsRead - 32)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fillFastStart() assumes the bitReaderBytes is empty and there is at least 8 bytes to read.
+func (b *bitReaderBytes) fillFastStart() {
+ // Do single re-slice to avoid bounds checks.
+ b.value = le.Load64(b.in, b.off-8)
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReaderBytes) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off >= 4 {
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << (b.bitsRead - 32)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value |= uint64(b.in[b.off-1]) << (b.bitsRead - 8)
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReaderBytes) finished() bool {
+ return b.off == 0 && b.bitsRead >= 64
+}
+
+func (b *bitReaderBytes) remaining() uint {
+ return b.off*8 + uint(64-b.bitsRead)
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReaderBytes) close() error {
+ // Release reference.
+ b.in = nil
+ if b.remaining() > 0 {
+ return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining())
+ }
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
+// bitReaderShifted reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReaderShifted struct {
+ in []byte
+ off uint // next byte to read is at in[off - 1]
+ value uint64
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReaderShifted) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ b.off = uint(len(in))
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.advance(8 - uint8(highBit32(uint32(v))))
+ return nil
+}
+
+// peekBitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReaderShifted) peekBitsFast(n uint8) uint16 {
+ return uint16(b.value >> ((64 - n) & 63))
+}
+
+func (b *bitReaderShifted) advance(n uint8) {
+ b.bitsRead += n
+ b.value <<= n & 63
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReaderShifted) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
+ b.bitsRead -= 32
+ b.off -= 4
+}
+
+// fillFastStart() assumes the bitReaderShifted is empty and there is at least 8 bytes to read.
+func (b *bitReaderShifted) fillFastStart() {
+ b.value = le.Load64(b.in, b.off-8)
+ b.bitsRead = 0
+ b.off -= 8
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReaderShifted) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.off > 4 {
+ low := le.Load32(b.in, b.off-4)
+ b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
+ b.bitsRead -= 32
+ b.off -= 4
+ return
+ }
+ for b.off > 0 {
+ b.value |= uint64(b.in[b.off-1]) << ((b.bitsRead - 8) & 63)
+ b.bitsRead -= 8
+ b.off--
+ }
+}
+
+func (b *bitReaderShifted) remaining() uint {
+ return b.off*8 + uint(64-b.bitsRead)
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReaderShifted) close() error {
+ // Release reference.
+ b.in = nil
+ if b.remaining() > 0 {
+ return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining())
+ }
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/bitwriter.go b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
new file mode 100644
index 00000000..41db94cd
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
@@ -0,0 +1,102 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package huff0
+
+// bitWriter will write bits.
+// First bit will be LSB of the first byte of output.
+type bitWriter struct {
+ bitContainer uint64
+ nBits uint8
+ out []byte
+}
+
+// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// encSymbol will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
+ enc := ct[symbol]
+ b.bitContainer |= uint64(enc.val) << (b.nBits & 63)
+ if false {
+ if enc.nBits == 0 {
+ panic("nbits 0")
+ }
+ }
+ b.nBits += enc.nBits
+}
+
+// encTwoSymbols will add up to 32 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
+ encA := ct[av]
+ encB := ct[bv]
+ sh := b.nBits & 63
+ combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63))
+ b.bitContainer |= combined << sh
+ if false {
+ if encA.nBits == 0 {
+ panic("nbitsA 0")
+ }
+ if encB.nBits == 0 {
+ panic("nbitsB 0")
+ }
+ }
+ b.nBits += encA.nBits + encB.nBits
+}
+
+// encFourSymbols adds up to 32 bits from four symbols.
+// It will not check if there is space for them,
+// so the caller must ensure that b has been flushed recently.
+func (b *bitWriter) encFourSymbols(encA, encB, encC, encD cTableEntry) {
+ bitsA := encA.nBits
+ bitsB := bitsA + encB.nBits
+ bitsC := bitsB + encC.nBits
+ bitsD := bitsC + encD.nBits
+ combined := uint64(encA.val) |
+ (uint64(encB.val) << (bitsA & 63)) |
+ (uint64(encC.val) << (bitsB & 63)) |
+ (uint64(encD.val) << (bitsC & 63))
+ b.bitContainer |= combined << (b.nBits & 63)
+ b.nBits += bitsD
+}
+
+// flush32 will flush out, so there are at least 32 bits available for writing.
+func (b *bitWriter) flush32() {
+ if b.nBits < 32 {
+ return
+ }
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24))
+ b.nBits -= 32
+ b.bitContainer >>= 32
+}
+
+// flushAlign will flush remaining full bytes and align to next byte boundary.
+func (b *bitWriter) flushAlign() {
+ nbBytes := (b.nBits + 7) >> 3
+ for i := range nbBytes {
+ b.out = append(b.out, byte(b.bitContainer>>(i*8)))
+ }
+ b.nBits = 0
+ b.bitContainer = 0
+}
+
+// close will write the alignment bit and write the final byte(s)
+// to the output.
+func (b *bitWriter) close() {
+ // End mark
+ b.addBits16Clean(1, 1)
+ // flush until next byte.
+ b.flushAlign()
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/compress.go b/vendor/github.com/klauspost/compress/huff0/compress.go
new file mode 100644
index 00000000..a97cf1b5
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/compress.go
@@ -0,0 +1,742 @@
+package huff0
+
+import (
+ "fmt"
+ "math"
+ "runtime"
+ "sync"
+)
+
+// Compress1X will compress the input.
+// The output can be decoded using Decompress1X.
+// Supply a Scratch object. The scratch object contains state about re-use,
+// So when sharing across independent encodes, be sure to set the re-use policy.
+func Compress1X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
+ s, err = s.prepare(in)
+ if err != nil {
+ return nil, false, err
+ }
+ return compress(in, s, s.compress1X)
+}
+
+// Compress4X will compress the input. The input is split into 4 independent blocks
+// and compressed similar to Compress1X.
+// The output can be decoded using Decompress4X.
+// Supply a Scratch object. The scratch object contains state about re-use,
+// So when sharing across independent encodes, be sure to set the re-use policy.
+func Compress4X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) {
+ s, err = s.prepare(in)
+ if err != nil {
+ return nil, false, err
+ }
+ if false {
+ // TODO: compress4Xp only slightly faster.
+ const parallelThreshold = 8 << 10
+ if len(in) < parallelThreshold || runtime.GOMAXPROCS(0) == 1 {
+ return compress(in, s, s.compress4X)
+ }
+ return compress(in, s, s.compress4Xp)
+ }
+ return compress(in, s, s.compress4X)
+}
+
+func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)) (out []byte, reUsed bool, err error) {
+ // Nuke previous table if we cannot reuse anyway.
+ if s.Reuse == ReusePolicyNone {
+ s.prevTable = s.prevTable[:0]
+ }
+
+ // Create histogram, if none was provided.
+ maxCount := s.maxCount
+ var canReuse = false
+ if maxCount == 0 {
+ maxCount, canReuse = s.countSimple(in)
+ } else {
+ canReuse = s.canUseTable(s.prevTable)
+ }
+
+ // We want the output size to be less than this:
+ wantSize := len(in)
+ if s.WantLogLess > 0 {
+ wantSize -= wantSize >> s.WantLogLess
+ }
+
+ // Reset for next run.
+ s.clearCount = true
+ s.maxCount = 0
+ if maxCount >= len(in) {
+ if maxCount > len(in) {
+ return nil, false, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in))
+ }
+ if len(in) == 1 {
+ return nil, false, ErrIncompressible
+ }
+ // One symbol, use RLE
+ return nil, false, ErrUseRLE
+ }
+ if maxCount == 1 || maxCount < (len(in)>>7) {
+ // Each symbol present maximum once or too well distributed.
+ return nil, false, ErrIncompressible
+ }
+ if s.Reuse == ReusePolicyMust && !canReuse {
+ // We must reuse, but we can't.
+ return nil, false, ErrIncompressible
+ }
+ if (s.Reuse == ReusePolicyPrefer || s.Reuse == ReusePolicyMust) && canReuse {
+ keepTable := s.cTable
+ keepTL := s.actualTableLog
+ s.cTable = s.prevTable
+ s.actualTableLog = s.prevTableLog
+ s.Out, err = compressor(in)
+ s.cTable = keepTable
+ s.actualTableLog = keepTL
+ if err == nil && len(s.Out) < wantSize {
+ s.OutData = s.Out
+ return s.Out, true, nil
+ }
+ if s.Reuse == ReusePolicyMust {
+ return nil, false, ErrIncompressible
+ }
+ // Do not attempt to re-use later.
+ s.prevTable = s.prevTable[:0]
+ }
+
+ // Calculate new table.
+ err = s.buildCTable()
+ if err != nil {
+ return nil, false, err
+ }
+
+ if false && !s.canUseTable(s.cTable) {
+ panic("invalid table generated")
+ }
+
+ if s.Reuse == ReusePolicyAllow && canReuse {
+ hSize := len(s.Out)
+ oldSize := s.prevTable.estimateSize(s.count[:s.symbolLen])
+ newSize := s.cTable.estimateSize(s.count[:s.symbolLen])
+ if oldSize <= hSize+newSize || hSize+12 >= wantSize {
+ // Retain cTable even if we re-use.
+ keepTable := s.cTable
+ keepTL := s.actualTableLog
+
+ s.cTable = s.prevTable
+ s.actualTableLog = s.prevTableLog
+ s.Out, err = compressor(in)
+
+ // Restore ctable.
+ s.cTable = keepTable
+ s.actualTableLog = keepTL
+ if err != nil {
+ return nil, false, err
+ }
+ if len(s.Out) >= wantSize {
+ return nil, false, ErrIncompressible
+ }
+ s.OutData = s.Out
+ return s.Out, true, nil
+ }
+ }
+
+ // Use new table
+ err = s.cTable.write(s)
+ if err != nil {
+ s.OutTable = nil
+ return nil, false, err
+ }
+ s.OutTable = s.Out
+
+ // Compress using new table
+ s.Out, err = compressor(in)
+ if err != nil {
+ s.OutTable = nil
+ return nil, false, err
+ }
+ if len(s.Out) >= wantSize {
+ s.OutTable = nil
+ return nil, false, ErrIncompressible
+ }
+ // Move current table into previous.
+ s.prevTable, s.prevTableLog, s.cTable = s.cTable, s.actualTableLog, s.prevTable[:0]
+ s.OutData = s.Out[len(s.OutTable):]
+ return s.Out, false, nil
+}
+
+// EstimateSizes will estimate the data sizes
+func EstimateSizes(in []byte, s *Scratch) (tableSz, dataSz, reuseSz int, err error) {
+ s, err = s.prepare(in)
+ if err != nil {
+ return 0, 0, 0, err
+ }
+
+ // Create histogram, if none was provided.
+ tableSz, dataSz, reuseSz = -1, -1, -1
+ maxCount := s.maxCount
+ var canReuse = false
+ if maxCount == 0 {
+ maxCount, canReuse = s.countSimple(in)
+ } else {
+ canReuse = s.canUseTable(s.prevTable)
+ }
+
+ // We want the output size to be less than this:
+ wantSize := len(in)
+ if s.WantLogLess > 0 {
+ wantSize -= wantSize >> s.WantLogLess
+ }
+
+ // Reset for next run.
+ s.clearCount = true
+ s.maxCount = 0
+ if maxCount >= len(in) {
+ if maxCount > len(in) {
+ return 0, 0, 0, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in))
+ }
+ if len(in) == 1 {
+ return 0, 0, 0, ErrIncompressible
+ }
+ // One symbol, use RLE
+ return 0, 0, 0, ErrUseRLE
+ }
+ if maxCount == 1 || maxCount < (len(in)>>7) {
+ // Each symbol present maximum once or too well distributed.
+ return 0, 0, 0, ErrIncompressible
+ }
+
+ // Calculate new table.
+ err = s.buildCTable()
+ if err != nil {
+ return 0, 0, 0, err
+ }
+
+ if false && !s.canUseTable(s.cTable) {
+ panic("invalid table generated")
+ }
+
+ tableSz, err = s.cTable.estTableSize(s)
+ if err != nil {
+ return 0, 0, 0, err
+ }
+ if canReuse {
+ reuseSz = s.prevTable.estimateSize(s.count[:s.symbolLen])
+ }
+ dataSz = s.cTable.estimateSize(s.count[:s.symbolLen])
+
+ // Restore
+ return tableSz, dataSz, reuseSz, nil
+}
+
+func (s *Scratch) compress1X(src []byte) ([]byte, error) {
+ return s.compress1xDo(s.Out, src), nil
+}
+
+func (s *Scratch) compress1xDo(dst, src []byte) []byte {
+ var bw = bitWriter{out: dst}
+
+ // N is length divisible by 4.
+ n := len(src)
+ n -= n & 3
+ cTable := s.cTable[:256]
+
+ // Encode last bytes.
+ for i := len(src) & 3; i > 0; i-- {
+ bw.encSymbol(cTable, src[n+i-1])
+ }
+ n -= 4
+ if s.actualTableLog <= 8 {
+ for ; n >= 0; n -= 4 {
+ tmp := src[n : n+4]
+ // tmp should be len 4
+ bw.flush32()
+ bw.encFourSymbols(cTable[tmp[3]], cTable[tmp[2]], cTable[tmp[1]], cTable[tmp[0]])
+ }
+ } else {
+ for ; n >= 0; n -= 4 {
+ tmp := src[n : n+4]
+ // tmp should be len 4
+ bw.flush32()
+ bw.encTwoSymbols(cTable, tmp[3], tmp[2])
+ bw.flush32()
+ bw.encTwoSymbols(cTable, tmp[1], tmp[0])
+ }
+ }
+ bw.close()
+ return bw.out
+}
+
+var sixZeros [6]byte
+
+func (s *Scratch) compress4X(src []byte) ([]byte, error) {
+ if len(src) < 12 {
+ return nil, ErrIncompressible
+ }
+ segmentSize := (len(src) + 3) / 4
+
+ // Add placeholder for output length
+ offsetIdx := len(s.Out)
+ s.Out = append(s.Out, sixZeros[:]...)
+
+ for i := range 4 {
+ toDo := src
+ if len(toDo) > segmentSize {
+ toDo = toDo[:segmentSize]
+ }
+ src = src[len(toDo):]
+
+ idx := len(s.Out)
+ s.Out = s.compress1xDo(s.Out, toDo)
+ if len(s.Out)-idx > math.MaxUint16 {
+ // We cannot store the size in the jump table
+ return nil, ErrIncompressible
+ }
+ // Write compressed length as little endian before block.
+ if i < 3 {
+ // Last length is not written.
+ length := len(s.Out) - idx
+ s.Out[i*2+offsetIdx] = byte(length)
+ s.Out[i*2+offsetIdx+1] = byte(length >> 8)
+ }
+ }
+
+ return s.Out, nil
+}
+
+// compress4Xp will compress 4 streams using separate goroutines.
+func (s *Scratch) compress4Xp(src []byte) ([]byte, error) {
+ if len(src) < 12 {
+ return nil, ErrIncompressible
+ }
+ // Add placeholder for output length
+ s.Out = s.Out[:6]
+
+ segmentSize := (len(src) + 3) / 4
+ var wg sync.WaitGroup
+ wg.Add(4)
+ for i := range 4 {
+ toDo := src
+ if len(toDo) > segmentSize {
+ toDo = toDo[:segmentSize]
+ }
+ src = src[len(toDo):]
+
+ // Separate goroutine for each block.
+ go func(i int) {
+ s.tmpOut[i] = s.compress1xDo(s.tmpOut[i][:0], toDo)
+ wg.Done()
+ }(i)
+ }
+ wg.Wait()
+ for i := range 4 {
+ o := s.tmpOut[i]
+ if len(o) > math.MaxUint16 {
+ // We cannot store the size in the jump table
+ return nil, ErrIncompressible
+ }
+ // Write compressed length as little endian before block.
+ if i < 3 {
+ // Last length is not written.
+ s.Out[i*2] = byte(len(o))
+ s.Out[i*2+1] = byte(len(o) >> 8)
+ }
+
+ // Write output.
+ s.Out = append(s.Out, o...)
+ }
+ return s.Out, nil
+}
+
+// countSimple will create a simple histogram in s.count.
+// Returns the biggest count.
+// Does not update s.clearCount.
+func (s *Scratch) countSimple(in []byte) (max int, reuse bool) {
+ reuse = true
+ _ = s.count // Assert that s != nil to speed up the following loop.
+ for _, v := range in {
+ s.count[v]++
+ }
+ m := uint32(0)
+ if len(s.prevTable) > 0 {
+ for i, v := range s.count[:] {
+ if v == 0 {
+ continue
+ }
+ if v > m {
+ m = v
+ }
+ s.symbolLen = uint16(i) + 1
+ if i >= len(s.prevTable) {
+ reuse = false
+ } else if s.prevTable[i].nBits == 0 {
+ reuse = false
+ }
+ }
+ return int(m), reuse
+ }
+ for i, v := range s.count[:] {
+ if v == 0 {
+ continue
+ }
+ if v > m {
+ m = v
+ }
+ s.symbolLen = uint16(i) + 1
+ }
+ return int(m), false
+}
+
+func (s *Scratch) canUseTable(c cTable) bool {
+ if len(c) < int(s.symbolLen) {
+ return false
+ }
+ for i, v := range s.count[:s.symbolLen] {
+ if v != 0 && c[i].nBits == 0 {
+ return false
+ }
+ }
+ return true
+}
+
+//lint:ignore U1000 used for debugging
+func (s *Scratch) validateTable(c cTable) bool {
+ if len(c) < int(s.symbolLen) {
+ return false
+ }
+ for i, v := range s.count[:s.symbolLen] {
+ if v != 0 {
+ if c[i].nBits == 0 {
+ return false
+ }
+ if c[i].nBits > s.actualTableLog {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// minTableLog provides the minimum logSize to safely represent a distribution.
+func (s *Scratch) minTableLog() uint8 {
+ minBitsSrc := highBit32(uint32(s.srcLen)) + 1
+ minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2
+ if minBitsSrc < minBitsSymbols {
+ return uint8(minBitsSrc)
+ }
+ return uint8(minBitsSymbols)
+}
+
+// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
+func (s *Scratch) optimalTableLog() {
+ tableLog := s.TableLog
+ minBits := s.minTableLog()
+ maxBitsSrc := uint8(highBit32(uint32(s.srcLen-1))) - 1
+ if maxBitsSrc < tableLog {
+ // Accuracy can be reduced
+ tableLog = maxBitsSrc
+ }
+ if minBits > tableLog {
+ tableLog = minBits
+ }
+ // Need a minimum to safely represent all symbol values
+ if tableLog < minTablelog {
+ tableLog = minTablelog
+ }
+ if tableLog > tableLogMax {
+ tableLog = tableLogMax
+ }
+ s.actualTableLog = tableLog
+}
+
+type cTableEntry struct {
+ val uint16
+ nBits uint8
+ // We have 8 bits extra
+}
+
+const huffNodesMask = huffNodesLen - 1
+
+func (s *Scratch) buildCTable() error {
+ s.optimalTableLog()
+ s.huffSort()
+ if cap(s.cTable) < maxSymbolValue+1 {
+ s.cTable = make([]cTableEntry, s.symbolLen, maxSymbolValue+1)
+ } else {
+ s.cTable = s.cTable[:s.symbolLen]
+ for i := range s.cTable {
+ s.cTable[i] = cTableEntry{}
+ }
+ }
+
+ var startNode = int16(s.symbolLen)
+ nonNullRank := s.symbolLen - 1
+
+ nodeNb := startNode
+ huffNode := s.nodes[1 : huffNodesLen+1]
+
+ // This overlays the slice above, but allows "-1" index lookups.
+ // Different from reference implementation.
+ huffNode0 := s.nodes[0 : huffNodesLen+1]
+
+ for huffNode[nonNullRank].count() == 0 {
+ nonNullRank--
+ }
+
+ lowS := int16(nonNullRank)
+ nodeRoot := nodeNb + lowS - 1
+ lowN := nodeNb
+ huffNode[nodeNb].setCount(huffNode[lowS].count() + huffNode[lowS-1].count())
+ huffNode[lowS].setParent(nodeNb)
+ huffNode[lowS-1].setParent(nodeNb)
+ nodeNb++
+ lowS -= 2
+ for n := nodeNb; n <= nodeRoot; n++ {
+ huffNode[n].setCount(1 << 30)
+ }
+ // fake entry, strong barrier
+ huffNode0[0].setCount(1 << 31)
+
+ // create parents
+ for nodeNb <= nodeRoot {
+ var n1, n2 int16
+ if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() {
+ n1 = lowS
+ lowS--
+ } else {
+ n1 = lowN
+ lowN++
+ }
+ if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() {
+ n2 = lowS
+ lowS--
+ } else {
+ n2 = lowN
+ lowN++
+ }
+
+ huffNode[nodeNb].setCount(huffNode0[n1+1].count() + huffNode0[n2+1].count())
+ huffNode0[n1+1].setParent(nodeNb)
+ huffNode0[n2+1].setParent(nodeNb)
+ nodeNb++
+ }
+
+ // distribute weights (unlimited tree height)
+ huffNode[nodeRoot].setNbBits(0)
+ for n := nodeRoot - 1; n >= startNode; n-- {
+ huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1)
+ }
+ for n := uint16(0); n <= nonNullRank; n++ {
+ huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1)
+ }
+ s.actualTableLog = s.setMaxHeight(int(nonNullRank))
+ maxNbBits := s.actualTableLog
+
+ // fill result into tree (val, nbBits)
+ if maxNbBits > tableLogMax {
+ return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", maxNbBits, tableLogMax)
+ }
+ var nbPerRank [tableLogMax + 1]uint16
+ var valPerRank [16]uint16
+ for _, v := range huffNode[:nonNullRank+1] {
+ nbPerRank[v.nbBits()]++
+ }
+ // determine stating value per rank
+ {
+ min := uint16(0)
+ for n := maxNbBits; n > 0; n-- {
+ // get starting value within each rank
+ valPerRank[n] = min
+ min += nbPerRank[n]
+ min >>= 1
+ }
+ }
+
+ // push nbBits per symbol, symbol order
+ for _, v := range huffNode[:nonNullRank+1] {
+ s.cTable[v.symbol()].nBits = v.nbBits()
+ }
+
+ // assign value within rank, symbol order
+ t := s.cTable[:s.symbolLen]
+ for n, val := range t {
+ nbits := val.nBits & 15
+ v := valPerRank[nbits]
+ t[n].val = v
+ valPerRank[nbits] = v + 1
+ }
+
+ return nil
+}
+
+// huffSort will sort symbols, decreasing order.
+func (s *Scratch) huffSort() {
+ type rankPos struct {
+ base uint32
+ current uint32
+ }
+
+ // Clear nodes
+ nodes := s.nodes[:huffNodesLen+1]
+ s.nodes = nodes
+ nodes = nodes[1 : huffNodesLen+1]
+
+ // Sort into buckets based on length of symbol count.
+ var rank [32]rankPos
+ for _, v := range s.count[:s.symbolLen] {
+ r := highBit32(v+1) & 31
+ rank[r].base++
+ }
+ // maxBitLength is log2(BlockSizeMax) + 1
+ const maxBitLength = 18 + 1
+ for n := maxBitLength; n > 0; n-- {
+ rank[n-1].base += rank[n].base
+ }
+ for n := range rank[:maxBitLength] {
+ rank[n].current = rank[n].base
+ }
+ for n, c := range s.count[:s.symbolLen] {
+ r := (highBit32(c+1) + 1) & 31
+ pos := rank[r].current
+ rank[r].current++
+ prev := nodes[(pos-1)&huffNodesMask]
+ for pos > rank[r].base && c > prev.count() {
+ nodes[pos&huffNodesMask] = prev
+ pos--
+ prev = nodes[(pos-1)&huffNodesMask]
+ }
+ nodes[pos&huffNodesMask] = makeNodeElt(c, byte(n))
+ }
+}
+
+func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
+ maxNbBits := s.actualTableLog
+ huffNode := s.nodes[1 : huffNodesLen+1]
+ //huffNode = huffNode[: huffNodesLen]
+
+ largestBits := huffNode[lastNonNull].nbBits()
+
+ // early exit : no elt > maxNbBits
+ if largestBits <= maxNbBits {
+ return largestBits
+ }
+ totalCost := int(0)
+ baseCost := int(1) << (largestBits - maxNbBits)
+ n := uint32(lastNonNull)
+
+ for huffNode[n].nbBits() > maxNbBits {
+ totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits()))
+ huffNode[n].setNbBits(maxNbBits)
+ n--
+ }
+ // n stops at huffNode[n].nbBits <= maxNbBits
+
+ for huffNode[n].nbBits() == maxNbBits {
+ n--
+ }
+ // n end at index of smallest symbol using < maxNbBits
+
+ // renorm totalCost
+ totalCost >>= largestBits - maxNbBits /* note : totalCost is necessarily a multiple of baseCost */
+
+ // repay normalized cost
+ {
+ const noSymbol = 0xF0F0F0F0
+ var rankLast [tableLogMax + 2]uint32
+
+ for i := range rankLast[:] {
+ rankLast[i] = noSymbol
+ }
+
+ // Get pos of last (smallest) symbol per rank
+ {
+ currentNbBits := maxNbBits
+ for pos := int(n); pos >= 0; pos-- {
+ if huffNode[pos].nbBits() >= currentNbBits {
+ continue
+ }
+ currentNbBits = huffNode[pos].nbBits() // < maxNbBits
+ rankLast[maxNbBits-currentNbBits] = uint32(pos)
+ }
+ }
+
+ for totalCost > 0 {
+ nBitsToDecrease := uint8(highBit32(uint32(totalCost))) + 1
+
+ for ; nBitsToDecrease > 1; nBitsToDecrease-- {
+ highPos := rankLast[nBitsToDecrease]
+ lowPos := rankLast[nBitsToDecrease-1]
+ if highPos == noSymbol {
+ continue
+ }
+ if lowPos == noSymbol {
+ break
+ }
+ highTotal := huffNode[highPos].count()
+ lowTotal := 2 * huffNode[lowPos].count()
+ if highTotal <= lowTotal {
+ break
+ }
+ }
+ // only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !)
+ // HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary
+ // FIXME: try to remove
+ for (nBitsToDecrease <= tableLogMax) && (rankLast[nBitsToDecrease] == noSymbol) {
+ nBitsToDecrease++
+ }
+ totalCost -= 1 << (nBitsToDecrease - 1)
+ if rankLast[nBitsToDecrease-1] == noSymbol {
+ // this rank is no longer empty
+ rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]
+ }
+ huffNode[rankLast[nBitsToDecrease]].setNbBits(1 +
+ huffNode[rankLast[nBitsToDecrease]].nbBits())
+ if rankLast[nBitsToDecrease] == 0 {
+ /* special case, reached largest symbol */
+ rankLast[nBitsToDecrease] = noSymbol
+ } else {
+ rankLast[nBitsToDecrease]--
+ if huffNode[rankLast[nBitsToDecrease]].nbBits() != maxNbBits-nBitsToDecrease {
+ rankLast[nBitsToDecrease] = noSymbol /* this rank is now empty */
+ }
+ }
+ }
+
+ for totalCost < 0 { /* Sometimes, cost correction overshoot */
+ if rankLast[1] == noSymbol { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
+ for huffNode[n].nbBits() == maxNbBits {
+ n--
+ }
+ huffNode[n+1].setNbBits(huffNode[n+1].nbBits() - 1)
+ rankLast[1] = n + 1
+ totalCost++
+ continue
+ }
+ huffNode[rankLast[1]+1].setNbBits(huffNode[rankLast[1]+1].nbBits() - 1)
+ rankLast[1]++
+ totalCost++
+ }
+ }
+ return maxNbBits
+}
+
+// A nodeElt is the fields
+//
+// count uint32
+// parent uint16
+// symbol byte
+// nbBits uint8
+//
+// in some order, all squashed into an integer so that the compiler
+// always loads and stores entire nodeElts instead of separate fields.
+type nodeElt uint64
+
+func makeNodeElt(count uint32, symbol byte) nodeElt {
+ return nodeElt(count) | nodeElt(symbol)<<48
+}
+
+func (e *nodeElt) count() uint32 { return uint32(*e) }
+func (e *nodeElt) parent() uint16 { return uint16(*e >> 32) }
+func (e *nodeElt) symbol() byte { return byte(*e >> 48) }
+func (e *nodeElt) nbBits() uint8 { return uint8(*e >> 56) }
+
+func (e *nodeElt) setCount(c uint32) { *e = (*e)&0xffffffff00000000 | nodeElt(c) }
+func (e *nodeElt) setParent(p int16) { *e = (*e)&0xffff0000ffffffff | nodeElt(uint16(p))<<32 }
+func (e *nodeElt) setNbBits(n uint8) { *e = (*e)&0x00ffffffffffffff | nodeElt(n)<<56 }
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go
new file mode 100644
index 00000000..7d0efa88
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress.go
@@ -0,0 +1,1161 @@
+package huff0
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "sync"
+
+ "github.com/klauspost/compress/fse"
+)
+
+type dTable struct {
+ single []dEntrySingle
+}
+
+// single-symbols decoding
+type dEntrySingle struct {
+ entry uint16
+}
+
+// Uses special code for all tables that are < 8 bits.
+const use8BitTables = true
+
+// ReadTable will read a table from the input.
+// The size of the input may be larger than the table definition.
+// Any content remaining after the table definition will be returned.
+// If no Scratch is provided a new one is allocated.
+// The returned Scratch can be used for encoding or decoding input using this table.
+func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
+ s, err = s.prepare(nil)
+ if err != nil {
+ return s, nil, err
+ }
+ if len(in) <= 1 {
+ return s, nil, errors.New("input too small for table")
+ }
+ iSize := in[0]
+ in = in[1:]
+ if iSize >= 128 {
+ // Uncompressed
+ oSize := iSize - 127
+ iSize = (oSize + 1) / 2
+ if int(iSize) > len(in) {
+ return s, nil, errors.New("input too small for table")
+ }
+ for n := uint8(0); n < oSize; n += 2 {
+ v := in[n/2]
+ s.huffWeight[n] = v >> 4
+ s.huffWeight[n+1] = v & 15
+ }
+ s.symbolLen = uint16(oSize)
+ in = in[iSize:]
+ } else {
+ if len(in) < int(iSize) {
+ return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in))
+ }
+ // FSE compressed weights
+ s.fse.DecompressLimit = 255
+ hw := s.huffWeight[:]
+ s.fse.Out = hw
+ b, err := fse.Decompress(in[:iSize], s.fse)
+ s.fse.Out = nil
+ if err != nil {
+ return s, nil, fmt.Errorf("fse decompress returned: %w", err)
+ }
+ if len(b) > 255 {
+ return s, nil, errors.New("corrupt input: output table too large")
+ }
+ s.symbolLen = uint16(len(b))
+ in = in[iSize:]
+ }
+
+ // collect weight stats
+ var rankStats [16]uint32
+ weightTotal := uint32(0)
+ for _, v := range s.huffWeight[:s.symbolLen] {
+ if v > tableLogMax {
+ return s, nil, errors.New("corrupt input: weight too large")
+ }
+ v2 := v & 15
+ rankStats[v2]++
+ // (1 << (v2-1)) is slower since the compiler cannot prove that v2 isn't 0.
+ weightTotal += (1 << v2) >> 1
+ }
+ if weightTotal == 0 {
+ return s, nil, errors.New("corrupt input: weights zero")
+ }
+
+ // get last non-null symbol weight (implied, total must be 2^n)
+ {
+ tableLog := highBit32(weightTotal) + 1
+ if tableLog > tableLogMax {
+ return s, nil, errors.New("corrupt input: tableLog too big")
+ }
+ s.actualTableLog = uint8(tableLog)
+ // determine last weight
+ {
+ total := uint32(1) << tableLog
+ rest := total - weightTotal
+ verif := uint32(1) << highBit32(rest)
+ lastWeight := highBit32(rest) + 1
+ if verif != rest {
+ // last value must be a clean power of 2
+ return s, nil, errors.New("corrupt input: last value not power of two")
+ }
+ s.huffWeight[s.symbolLen] = uint8(lastWeight)
+ s.symbolLen++
+ rankStats[lastWeight]++
+ }
+ }
+
+ if (rankStats[1] < 2) || (rankStats[1]&1 != 0) {
+ // by construction : at least 2 elts of rank 1, must be even
+ return s, nil, errors.New("corrupt input: min elt size, even check failed ")
+ }
+
+ // TODO: Choose between single/double symbol decoding
+
+ // Calculate starting value for each rank
+ {
+ var nextRankStart uint32
+ for n := uint8(1); n < s.actualTableLog+1; n++ {
+ current := nextRankStart
+ nextRankStart += rankStats[n] << (n - 1)
+ rankStats[n] = current
+ }
+ }
+
+ // fill DTable (always full size)
+ tSize := 1 << tableLogMax
+ if len(s.dt.single) != tSize {
+ s.dt.single = make([]dEntrySingle, tSize)
+ }
+ cTable := s.prevTable
+ if cap(cTable) < maxSymbolValue+1 {
+ cTable = make([]cTableEntry, 0, maxSymbolValue+1)
+ }
+ cTable = cTable[:maxSymbolValue+1]
+ s.prevTable = cTable[:s.symbolLen]
+ s.prevTableLog = s.actualTableLog
+
+ for n, w := range s.huffWeight[:s.symbolLen] {
+ if w == 0 {
+ cTable[n] = cTableEntry{
+ val: 0,
+ nBits: 0,
+ }
+ continue
+ }
+ length := (uint32(1) << w) >> 1
+ d := dEntrySingle{
+ entry: uint16(s.actualTableLog+1-w) | (uint16(n) << 8),
+ }
+
+ rank := &rankStats[w]
+ cTable[n] = cTableEntry{
+ val: uint16(*rank >> (w - 1)),
+ nBits: uint8(d.entry),
+ }
+
+ single := s.dt.single[*rank : *rank+length]
+ for i := range single {
+ single[i] = d
+ }
+ *rank += length
+ }
+
+ return s, in, nil
+}
+
+// Decompress1X will decompress a 1X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// Before this is called, the table must be initialized with ReadTable unless
+// the encoder re-used the table.
+// deprecated: Use the stateless Decoder() to get a concurrent version.
+func (s *Scratch) Decompress1X(in []byte) (out []byte, err error) {
+ if cap(s.Out) < s.MaxDecodedSize {
+ s.Out = make([]byte, s.MaxDecodedSize)
+ }
+ s.Out = s.Out[:0:s.MaxDecodedSize]
+ s.Out, err = s.Decoder().Decompress1X(s.Out, in)
+ return s.Out, err
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// Before this is called, the table must be initialized with ReadTable unless
+// the encoder re-used the table.
+// The length of the supplied input must match the end of a block exactly.
+// The destination size of the uncompressed data must be known and provided.
+// deprecated: Use the stateless Decoder() to get a concurrent version.
+func (s *Scratch) Decompress4X(in []byte, dstSize int) (out []byte, err error) {
+ if dstSize > s.MaxDecodedSize {
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ if cap(s.Out) < dstSize {
+ s.Out = make([]byte, s.MaxDecodedSize)
+ }
+ s.Out = s.Out[:0:dstSize]
+ s.Out, err = s.Decoder().Decompress4X(s.Out, in)
+ return s.Out, err
+}
+
+// Decoder will return a stateless decoder that can be used by multiple
+// decompressors concurrently.
+// Before this is called, the table must be initialized with ReadTable.
+// The Decoder is still linked to the scratch buffer so that cannot be reused.
+// However, it is safe to discard the scratch.
+func (s *Scratch) Decoder() *Decoder {
+ return &Decoder{
+ dt: s.dt,
+ actualTableLog: s.actualTableLog,
+ bufs: &s.decPool,
+ }
+}
+
+// Decoder provides stateless decoding.
+type Decoder struct {
+ dt dTable
+ actualTableLog uint8
+ bufs *sync.Pool
+}
+
+func (d *Decoder) buffer() *[4][256]byte {
+ buf, ok := d.bufs.Get().(*[4][256]byte)
+ if ok {
+ return buf
+ }
+ return &[4][256]byte{}
+}
+
+// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) {
+ if d.actualTableLog == 8 {
+ return d.decompress1X8BitExactly(dst, src)
+ }
+ var br bitReaderBytes
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ dt := d.dt.single[:256]
+
+ // Use temp table to avoid bound checks/append penalty.
+ bufs := d.buffer()
+ buf := &bufs[0]
+ var off uint8
+
+ switch d.actualTableLog {
+ case 8:
+ const shift = 0
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 7:
+ const shift = 8 - 7
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 6:
+ const shift = 8 - 6
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 5:
+ const shift = 8 - 5
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 4:
+ const shift = 8 - 4
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 3:
+ const shift = 8 - 3
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 2:
+ const shift = 8 - 2
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 1:
+ const shift = 8 - 1
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ default:
+ d.bufs.Put(bufs)
+ return nil, fmt.Errorf("invalid tablelog: %d", d.actualTableLog)
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 4, so uint8 is fine
+ bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead))
+ shift := (8 - d.actualTableLog) & 7
+
+ for bitsLeft > 0 {
+ if br.bitsRead >= 64-8 {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := dt[br.peekByteFast()>>shift]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= int8(nBits)
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ d.bufs.Put(bufs)
+ return dst, br.close()
+}
+
+// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) {
+ var br bitReaderBytes
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ dt := d.dt.single[:256]
+
+ // Use temp table to avoid bound checks/append penalty.
+ bufs := d.buffer()
+ buf := &bufs[0]
+ var off uint8
+
+ const shift = 56
+
+ //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog)
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>shift)]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 4, so uint8 is fine
+ bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead))
+ for bitsLeft > 0 {
+ if br.bitsRead >= 64-8 {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := dt[br.peekByteFast()]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= int8(nBits)
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ d.bufs.Put(bufs)
+ return dst, br.close()
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
+ if d.actualTableLog == 8 {
+ return d.decompress4X8bitExactly(dst, src)
+ }
+
+ var br [4]bitReaderBytes
+ start := 6
+ for i := range 3 {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ shift := (56 + (8 - d.actualTableLog)) & 63
+
+ const tlSize = 1 << 8
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ buf := d.buffer()
+ var off uint8
+ var decoded int
+
+ // Decode 4 values from each decoder/loop.
+ const bufoff = 256
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
+ }
+
+ {
+ // Interleave 2 decodes.
+ const stream = 0
+ const stream2 = 1
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ {
+ const stream = 2
+ const stream2 = 3
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ off += 4
+
+ if off == 0 {
+ if bufoff > dstEvery {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ // There must at least be 3 buffers left.
+ if len(out)-bufoff < dstEvery*3 {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+ //copy(out, buf[0][:])
+ //copy(out[dstEvery:], buf[1][:])
+ //copy(out[dstEvery*2:], buf[2][:])
+ *(*[bufoff]byte)(out) = buf[0]
+ *(*[bufoff]byte)(out[dstEvery:]) = buf[1]
+ *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2]
+ *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3]
+ out = out[bufoff:]
+ decoded += bufoff * 4
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[0][:off])
+ copy(out[dstEvery:], buf[1][:off])
+ copy(out[dstEvery*2:], buf[2][:off])
+ copy(out[dstEvery*3:], buf[3][:off])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := min(offset+remainBytes, len(out))
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ if br.finished() {
+ d.bufs.Put(buf)
+ return nil, io.ErrUnexpectedEOF
+ }
+ if br.bitsRead >= 56 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value |= uint64(low) << (br.bitsRead - 32)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ // end inline...
+ if offset >= endsAt {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ v := single[uint8(br.value>>shift)].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ d.bufs.Put(buf)
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ d.bufs.Put(buf)
+ return nil, err
+ }
+ }
+ d.bufs.Put(buf)
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) {
+ var br [4]bitReaderBytes
+ start := 6
+ for i := range 3 {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const shift = 56
+ const tlSize = 1 << 8
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ buf := d.buffer()
+ var off uint8
+ var decoded int
+
+ // Decode 4 values from each decoder/loop.
+ const bufoff = 256
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
+ }
+
+ {
+ // Interleave 2 decodes.
+ const stream = 0
+ const stream2 = 1
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ {
+ const stream = 2
+ const stream2 = 3
+ br1 := &br[stream]
+ br2 := &br[stream2]
+ br1.fillFast()
+ br2.fillFast()
+
+ v := single[uint8(br1.value>>shift)].entry
+ v2 := single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off] = uint8(v >> 8)
+ buf[stream2][off] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+1] = uint8(v >> 8)
+ buf[stream2][off+1] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+2] = uint8(v >> 8)
+ buf[stream2][off+2] = uint8(v2 >> 8)
+
+ v = single[uint8(br1.value>>shift)].entry
+ v2 = single[uint8(br2.value>>shift)].entry
+ br1.bitsRead += uint8(v)
+ br1.value <<= v & 63
+ br2.bitsRead += uint8(v2)
+ br2.value <<= v2 & 63
+ buf[stream][off+3] = uint8(v >> 8)
+ buf[stream2][off+3] = uint8(v2 >> 8)
+ }
+
+ off += 4
+
+ if off == 0 {
+ if bufoff > dstEvery {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ // There must at least be 3 buffers left.
+ if len(out)-bufoff < dstEvery*3 {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+
+ //copy(out, buf[0][:])
+ //copy(out[dstEvery:], buf[1][:])
+ //copy(out[dstEvery*2:], buf[2][:])
+ // copy(out[dstEvery*3:], buf[3][:])
+ *(*[bufoff]byte)(out) = buf[0]
+ *(*[bufoff]byte)(out[dstEvery:]) = buf[1]
+ *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2]
+ *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3]
+ out = out[bufoff:]
+ decoded += bufoff * 4
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[0][:off])
+ copy(out[dstEvery:], buf[1][:off])
+ copy(out[dstEvery*2:], buf[2][:off])
+ copy(out[dstEvery*3:], buf[3][:off])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := min(offset+remainBytes, len(out))
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ if br.finished() {
+ d.bufs.Put(buf)
+ return nil, io.ErrUnexpectedEOF
+ }
+ if br.bitsRead >= 56 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value |= uint64(low) << (br.bitsRead - 32)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8)
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ // end inline...
+ if offset >= endsAt {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ v := single[br.peekByteFast()].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ d.bufs.Put(buf)
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ d.bufs.Put(buf)
+ return nil, err
+ }
+ }
+ d.bufs.Put(buf)
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// matches will compare a decoding table to a coding table.
+// Errors are written to the writer.
+// Nothing will be written if table is ok.
+func (s *Scratch) matches(ct cTable, w io.Writer) {
+ if s == nil || len(s.dt.single) == 0 {
+ return
+ }
+ dt := s.dt.single[:1<>8) == byte(sym) {
+ fmt.Fprintf(w, "symbol %x has decoder, but no encoder\n", sym)
+ errs++
+ break
+ }
+ }
+ if errs == 0 {
+ broken--
+ }
+ continue
+ }
+ // Unused bits in input
+ ub := tablelog - enc.nBits
+ top := enc.val << ub
+ // decoder looks at top bits.
+ dec := dt[top]
+ if uint8(dec.entry) != enc.nBits {
+ fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", sym, enc.nBits, uint8(dec.entry))
+ errs++
+ }
+ if uint8(dec.entry>>8) != uint8(sym) {
+ fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", sym, sym, uint8(dec.entry>>8))
+ errs++
+ }
+ if errs > 0 {
+ fmt.Fprintf(w, "%d errors in base, stopping\n", errs)
+ continue
+ }
+ // Ensure that all combinations are covered.
+ for i := uint16(0); i < (1 << ub); i++ {
+ vval := top | i
+ dec := dt[vval]
+ if uint8(dec.entry) != enc.nBits {
+ fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", vval, enc.nBits, uint8(dec.entry))
+ errs++
+ }
+ if uint8(dec.entry>>8) != uint8(sym) {
+ fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", vval, sym, uint8(dec.entry>>8))
+ errs++
+ }
+ if errs > 20 {
+ fmt.Fprintf(w, "%d errors, stopping\n", errs)
+ break
+ }
+ }
+ if errs == 0 {
+ ok++
+ broken--
+ }
+ }
+ if broken > 0 {
+ fmt.Fprintf(w, "%d broken, %d ok\n", broken, ok)
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
new file mode 100644
index 00000000..2d6ef64b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go
@@ -0,0 +1,222 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+// This file contains the specialisation of Decoder.Decompress4X
+// and Decoder.Decompress1X that use an asm implementation of thir main loops.
+package huff0
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/klauspost/compress/internal/cpuinfo"
+)
+
+// decompress4x_main_loop_x86 is an x86 assembler implementation
+// of Decompress4X when tablelog > 8.
+//
+//go:noescape
+func decompress4x_main_loop_amd64(ctx *decompress4xContext)
+
+// decompress4x_8b_loop_x86 is an x86 assembler implementation
+// of Decompress4X when tablelog <= 8 which decodes 4 entries
+// per loop.
+//
+//go:noescape
+func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
+
+// fallback8BitSize is the size where using Go version is faster.
+const fallback8BitSize = 800
+
+type decompress4xContext struct {
+ pbr *[4]bitReaderShifted
+ peekBits uint8
+ out *byte
+ dstEvery int
+ tbl *dEntrySingle
+ decoded int
+ limit *byte
+}
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ if len(src) < 6+(4*1) {
+ return nil, errors.New("input too small")
+ }
+
+ use8BitTables := d.actualTableLog <= 8
+ if cap(dst) < fallback8BitSize && use8BitTables {
+ return d.decompress4X8bit(dst, src)
+ }
+
+ var br [4]bitReaderShifted
+ // Decode "jump table"
+ start := 6
+ for i := range 3 {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+ single := d.dt.single[:tlSize]
+
+ var decoded int
+
+ if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) {
+ ctx := decompress4xContext{
+ pbr: &br,
+ peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
+ out: &out[0],
+ dstEvery: dstEvery,
+ tbl: &single[0],
+ limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last.
+ }
+ if use8BitTables {
+ decompress4x_8b_main_loop_amd64(&ctx)
+ } else {
+ decompress4x_main_loop_amd64(&ctx)
+ }
+
+ decoded = ctx.decoded
+ out = out[decoded/4:]
+ }
+
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := min(offset+remainBytes, len(out))
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ br.fill()
+ if offset >= endsAt {
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ val := br.peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ return nil, err
+ }
+ }
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// decompress4x_main_loop_x86 is an x86 assembler implementation
+// of Decompress1X when tablelog > 8.
+//
+//go:noescape
+func decompress1x_main_loop_amd64(ctx *decompress1xContext)
+
+// decompress4x_main_loop_x86 is an x86 with BMI2 assembler implementation
+// of Decompress1X when tablelog > 8.
+//
+//go:noescape
+func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
+
+type decompress1xContext struct {
+ pbr *bitReaderShifted
+ peekBits uint8
+ out *byte
+ outCap int
+ tbl *dEntrySingle
+ decoded int
+}
+
+// Error reported by asm implementations
+const error_max_decoded_size_exeeded = -1
+
+// Decompress1X will decompress a 1X encoded stream.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ var br bitReaderShifted
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:maxDecodedSize]
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+
+ if maxDecodedSize >= 4 {
+ ctx := decompress1xContext{
+ pbr: &br,
+ out: &dst[0],
+ outCap: maxDecodedSize,
+ peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
+ tbl: &d.dt.single[0],
+ }
+
+ if cpuinfo.HasBMI2() {
+ decompress1x_main_loop_bmi2(&ctx)
+ } else {
+ decompress1x_main_loop_amd64(&ctx)
+ }
+ if ctx.decoded == error_max_decoded_size_exeeded {
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+
+ dst = dst[:ctx.decoded]
+ }
+
+ // br < 8, so uint8 is fine
+ bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
+ for bitsLeft > 0 {
+ br.fill()
+ if len(dst) >= maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= nBits
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ return dst, br.close()
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
new file mode 100644
index 00000000..c4c7ab2d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s
@@ -0,0 +1,830 @@
+// Code generated by command: go run gen.go -out ../decompress_amd64.s -pkg=huff0. DO NOT EDIT.
+
+//go:build amd64 && !appengine && !noasm && gc
+
+// func decompress4x_main_loop_amd64(ctx *decompress4xContext)
+TEXT ·decompress4x_main_loop_amd64(SB), $0-8
+ // Preload values
+ MOVQ ctx+0(FP), AX
+ MOVBQZX 8(AX), DI
+ MOVQ 16(AX), BX
+ MOVQ 48(AX), SI
+ MOVQ 24(AX), R8
+ MOVQ 32(AX), R9
+ MOVQ (AX), R10
+
+ // Main loop
+main_loop:
+ XORL DX, DX
+ CMPQ BX, SI
+ SETGE DL
+
+ // br0.fillFast32()
+ MOVQ 32(R10), R11
+ MOVBQZX 40(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill0
+ MOVQ 24(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ (R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 24(R10)
+ ORQ R13, R11
+
+ // exhausted += (br0.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill0:
+ // val0 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br0.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ MOVW AX, (BX)
+
+ // update the bitreader structure
+ MOVQ R11, 32(R10)
+ MOVB R12, 40(R10)
+
+ // br1.fillFast32()
+ MOVQ 80(R10), R11
+ MOVBQZX 88(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill1
+ MOVQ 72(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ 48(R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 72(R10)
+ ORQ R13, R11
+
+ // exhausted += (br1.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill1:
+ // val0 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br1.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ MOVW AX, (BX)(R8*1)
+
+ // update the bitreader structure
+ MOVQ R11, 80(R10)
+ MOVB R12, 88(R10)
+
+ // br2.fillFast32()
+ MOVQ 128(R10), R11
+ MOVBQZX 136(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill2
+ MOVQ 120(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ 96(R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 120(R10)
+ ORQ R13, R11
+
+ // exhausted += (br2.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill2:
+ // val0 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br2.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ MOVW AX, (BX)(R8*2)
+
+ // update the bitreader structure
+ MOVQ R11, 128(R10)
+ MOVB R12, 136(R10)
+
+ // br3.fillFast32()
+ MOVQ 176(R10), R11
+ MOVBQZX 184(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill3
+ MOVQ 168(R10), AX
+ SUBQ $0x20, R12
+ SUBQ $0x04, AX
+ MOVQ 144(R10), R13
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (AX)(R13*1), R13
+ MOVQ R12, CX
+ SHLQ CL, R13
+ MOVQ AX, 168(R10)
+ ORQ R13, R11
+
+ // exhausted += (br3.off < 4)
+ CMPQ AX, $0x04
+ ADCB $+0, DL
+
+skip_fill3:
+ // val0 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br3.peekTopBits(peekBits)
+ MOVQ DI, CX
+ MOVQ R11, R13
+ SHRQ CL, R13
+
+ // v1 := table[val1&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v1.entry))
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // these two writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ LEAQ (R8)(R8*2), CX
+ MOVW AX, (BX)(CX*1)
+
+ // update the bitreader structure
+ MOVQ R11, 176(R10)
+ MOVB R12, 184(R10)
+ ADDQ $0x02, BX
+ TESTB DL, DL
+ JZ main_loop
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), BX
+ SHLQ $0x02, BX
+ MOVQ BX, 40(AX)
+ RET
+
+// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
+TEXT ·decompress4x_8b_main_loop_amd64(SB), $0-8
+ // Preload values
+ MOVQ ctx+0(FP), CX
+ MOVBQZX 8(CX), DI
+ MOVQ 16(CX), BX
+ MOVQ 48(CX), SI
+ MOVQ 24(CX), R8
+ MOVQ 32(CX), R9
+ MOVQ (CX), R10
+
+ // Main loop
+main_loop:
+ XORL DX, DX
+ CMPQ BX, SI
+ SETGE DL
+
+ // br0.fillFast32()
+ MOVQ 32(R10), R11
+ MOVBQZX 40(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill0
+ MOVQ 24(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ (R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 24(R10)
+ ORQ R14, R11
+
+ // exhausted += (br0.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill0:
+ // val0 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br0.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br0.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ MOVL AX, (BX)
+
+ // update the bitreader structure
+ MOVQ R11, 32(R10)
+ MOVB R12, 40(R10)
+
+ // br1.fillFast32()
+ MOVQ 80(R10), R11
+ MOVBQZX 88(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill1
+ MOVQ 72(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ 48(R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 72(R10)
+ ORQ R14, R11
+
+ // exhausted += (br1.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill1:
+ // val0 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br1.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br1.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ MOVL AX, (BX)(R8*1)
+
+ // update the bitreader structure
+ MOVQ R11, 80(R10)
+ MOVB R12, 88(R10)
+
+ // br2.fillFast32()
+ MOVQ 128(R10), R11
+ MOVBQZX 136(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill2
+ MOVQ 120(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ 96(R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 120(R10)
+ ORQ R14, R11
+
+ // exhausted += (br2.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill2:
+ // val0 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br2.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br2.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ MOVL AX, (BX)(R8*2)
+
+ // update the bitreader structure
+ MOVQ R11, 128(R10)
+ MOVB R12, 136(R10)
+
+ // br3.fillFast32()
+ MOVQ 176(R10), R11
+ MOVBQZX 184(R10), R12
+ CMPQ R12, $0x20
+ JBE skip_fill3
+ MOVQ 168(R10), R13
+ SUBQ $0x20, R12
+ SUBQ $0x04, R13
+ MOVQ 144(R10), R14
+
+ // b.value |= uint64(low) << (b.bitsRead & 63)
+ MOVL (R13)(R14*1), R14
+ MOVQ R12, CX
+ SHLQ CL, R14
+ MOVQ R13, 168(R10)
+ ORQ R14, R11
+
+ // exhausted += (br3.off < 4)
+ CMPQ R13, $0x04
+ ADCB $+0, DL
+
+skip_fill3:
+ // val0 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v0 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v0.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val1 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v1 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v1.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // val2 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v2 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v2.entry)
+ MOVB CH, AH
+ SHLQ CL, R11
+ ADDB CL, R12
+
+ // val3 := br3.peekTopBits(peekBits)
+ MOVQ R11, R13
+ MOVQ DI, CX
+ SHRQ CL, R13
+
+ // v3 := table[val0&mask]
+ MOVW (R9)(R13*2), CX
+
+ // br3.advance(uint8(v3.entry)
+ MOVB CH, AL
+ SHLQ CL, R11
+ ADDB CL, R12
+ BSWAPL AX
+
+ // these four writes get coalesced
+ // out[id * dstEvery + 0] = uint8(v0.entry >> 8)
+ // out[id * dstEvery + 1] = uint8(v1.entry >> 8)
+ // out[id * dstEvery + 3] = uint8(v2.entry >> 8)
+ // out[id * dstEvery + 4] = uint8(v3.entry >> 8)
+ LEAQ (R8)(R8*2), CX
+ MOVL AX, (BX)(CX*1)
+
+ // update the bitreader structure
+ MOVQ R11, 176(R10)
+ MOVB R12, 184(R10)
+ ADDQ $0x04, BX
+ TESTB DL, DL
+ JZ main_loop
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), BX
+ SHLQ $0x02, BX
+ MOVQ BX, 40(AX)
+ RET
+
+// func decompress1x_main_loop_amd64(ctx *decompress1xContext)
+TEXT ·decompress1x_main_loop_amd64(SB), $0-8
+ MOVQ ctx+0(FP), CX
+ MOVQ 16(CX), DX
+ MOVQ 24(CX), BX
+ CMPQ BX, $0x04
+ JB error_max_decoded_size_exceeded
+ LEAQ (DX)(BX*1), BX
+ MOVQ (CX), SI
+ MOVQ (SI), R8
+ MOVQ 24(SI), R9
+ MOVQ 32(SI), R10
+ MOVBQZX 40(SI), R11
+ MOVQ 32(CX), SI
+ MOVBQZX 8(CX), DI
+ JMP loop_condition
+
+main_loop:
+ // Check if we have room for 4 bytes in the output buffer
+ LEAQ 4(DX), CX
+ CMPQ CX, BX
+ JGE error_max_decoded_size_exceeded
+
+ // Decode 4 values
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_1_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), R12
+ MOVQ R11, CX
+ SHLQ CL, R12
+ ORQ R12, R10
+
+bitReader_fillFast_1_end:
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ BSWAPL AX
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_2_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), R12
+ MOVQ R11, CX
+ SHLQ CL, R12
+ ORQ R12, R10
+
+bitReader_fillFast_2_end:
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ MOVQ DI, CX
+ MOVQ R10, R12
+ SHRQ CL, R12
+ MOVW (SI)(R12*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLQ CL, R10
+ BSWAPL AX
+
+ // Store the decoded values
+ MOVL AX, (DX)
+ ADDQ $0x04, DX
+
+loop_condition:
+ CMPQ R9, $0x08
+ JGE main_loop
+
+ // Update ctx structure
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), DX
+ MOVQ DX, 40(AX)
+ MOVQ (AX), AX
+ MOVQ R9, 24(AX)
+ MOVQ R10, 32(AX)
+ MOVB R11, 40(AX)
+ RET
+
+ // Report error
+error_max_decoded_size_exceeded:
+ MOVQ ctx+0(FP), AX
+ MOVQ $-1, CX
+ MOVQ CX, 40(AX)
+ RET
+
+// func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
+// Requires: BMI2
+TEXT ·decompress1x_main_loop_bmi2(SB), $0-8
+ MOVQ ctx+0(FP), CX
+ MOVQ 16(CX), DX
+ MOVQ 24(CX), BX
+ CMPQ BX, $0x04
+ JB error_max_decoded_size_exceeded
+ LEAQ (DX)(BX*1), BX
+ MOVQ (CX), SI
+ MOVQ (SI), R8
+ MOVQ 24(SI), R9
+ MOVQ 32(SI), R10
+ MOVBQZX 40(SI), R11
+ MOVQ 32(CX), SI
+ MOVBQZX 8(CX), DI
+ JMP loop_condition
+
+main_loop:
+ // Check if we have room for 4 bytes in the output buffer
+ LEAQ 4(DX), CX
+ CMPQ CX, BX
+ JGE error_max_decoded_size_exceeded
+
+ // Decode 4 values
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_1_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), CX
+ SHLXQ R11, CX, CX
+ ORQ CX, R10
+
+bitReader_fillFast_1_end:
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ BSWAPL AX
+ CMPQ R11, $0x20
+ JL bitReader_fillFast_2_end
+ SUBQ $0x20, R11
+ SUBQ $0x04, R9
+ MOVL (R8)(R9*1), CX
+ SHLXQ R11, CX, CX
+ ORQ CX, R10
+
+bitReader_fillFast_2_end:
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AH
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ SHRXQ DI, R10, CX
+ MOVW (SI)(CX*2), CX
+ MOVB CH, AL
+ MOVBQZX CL, CX
+ ADDQ CX, R11
+ SHLXQ CX, R10, R10
+ BSWAPL AX
+
+ // Store the decoded values
+ MOVL AX, (DX)
+ ADDQ $0x04, DX
+
+loop_condition:
+ CMPQ R9, $0x08
+ JGE main_loop
+
+ // Update ctx structure
+ MOVQ ctx+0(FP), AX
+ SUBQ 16(AX), DX
+ MOVQ DX, 40(AX)
+ MOVQ (AX), AX
+ MOVQ R9, 24(AX)
+ MOVQ R10, 32(AX)
+ MOVB R11, 40(AX)
+ RET
+
+ // Report error
+error_max_decoded_size_exceeded:
+ MOVQ ctx+0(FP), AX
+ MOVQ $-1, CX
+ MOVQ CX, 40(AX)
+ RET
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go
new file mode 100644
index 00000000..61039232
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go
@@ -0,0 +1,298 @@
+//go:build !amd64 || appengine || !gc || noasm
+
+// This file contains a generic implementation of Decoder.Decompress4X.
+package huff0
+
+import (
+ "errors"
+ "fmt"
+)
+
+// Decompress4X will decompress a 4X encoded stream.
+// The length of the supplied input must match the end of a block exactly.
+// The *capacity* of the dst slice must match the destination size of
+// the uncompressed data exactly.
+func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ if len(src) < 6+(4*1) {
+ return nil, errors.New("input too small")
+ }
+ if use8BitTables && d.actualTableLog <= 8 {
+ return d.decompress4X8bit(dst, src)
+ }
+
+ var br [4]bitReaderShifted
+ // Decode "jump table"
+ start := 6
+ for i := 0; i < 3; i++ {
+ length := int(src[i*2]) | (int(src[i*2+1]) << 8)
+ if start+length >= len(src) {
+ return nil, errors.New("truncated input (or invalid offset)")
+ }
+ err := br[i].init(src[start : start+length])
+ if err != nil {
+ return nil, err
+ }
+ start += length
+ }
+ err := br[3].init(src[start:])
+ if err != nil {
+ return nil, err
+ }
+
+ // destination, offset to match first output
+ dstSize := cap(dst)
+ dst = dst[:dstSize]
+ out := dst
+ dstEvery := (dstSize + 3) / 4
+
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+ single := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ buf := d.buffer()
+ var off uint8
+ var decoded int
+
+ // Decode 2 values from each decoder/loop.
+ const bufoff = 256
+ for {
+ if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 {
+ break
+ }
+
+ {
+ const stream = 0
+ const stream2 = 1
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ val := br[stream].peekBitsFast(d.actualTableLog)
+ val2 := br[stream2].peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask]
+ v2 := single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off] = uint8(v.entry >> 8)
+ buf[stream2][off] = uint8(v2.entry >> 8)
+
+ val = br[stream].peekBitsFast(d.actualTableLog)
+ val2 = br[stream2].peekBitsFast(d.actualTableLog)
+ v = single[val&tlMask]
+ v2 = single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off+1] = uint8(v.entry >> 8)
+ buf[stream2][off+1] = uint8(v2.entry >> 8)
+ }
+
+ {
+ const stream = 2
+ const stream2 = 3
+ br[stream].fillFast()
+ br[stream2].fillFast()
+
+ val := br[stream].peekBitsFast(d.actualTableLog)
+ val2 := br[stream2].peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask]
+ v2 := single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off] = uint8(v.entry >> 8)
+ buf[stream2][off] = uint8(v2.entry >> 8)
+
+ val = br[stream].peekBitsFast(d.actualTableLog)
+ val2 = br[stream2].peekBitsFast(d.actualTableLog)
+ v = single[val&tlMask]
+ v2 = single[val2&tlMask]
+ br[stream].advance(uint8(v.entry))
+ br[stream2].advance(uint8(v2.entry))
+ buf[stream][off+1] = uint8(v.entry >> 8)
+ buf[stream2][off+1] = uint8(v2.entry >> 8)
+ }
+
+ off += 2
+
+ if off == 0 {
+ if bufoff > dstEvery {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 1")
+ }
+ // There must at least be 3 buffers left.
+ if len(out)-bufoff < dstEvery*3 {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 2")
+ }
+ //copy(out, buf[0][:])
+ //copy(out[dstEvery:], buf[1][:])
+ //copy(out[dstEvery*2:], buf[2][:])
+ //copy(out[dstEvery*3:], buf[3][:])
+ *(*[bufoff]byte)(out) = buf[0]
+ *(*[bufoff]byte)(out[dstEvery:]) = buf[1]
+ *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2]
+ *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3]
+ out = out[bufoff:]
+ decoded += bufoff * 4
+ }
+ }
+ if off > 0 {
+ ioff := int(off)
+ if len(out) < dstEvery*3+ioff {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 3")
+ }
+ copy(out, buf[0][:off])
+ copy(out[dstEvery:], buf[1][:off])
+ copy(out[dstEvery*2:], buf[2][:off])
+ copy(out[dstEvery*3:], buf[3][:off])
+ decoded += int(off) * 4
+ out = out[off:]
+ }
+
+ // Decode remaining.
+ remainBytes := dstEvery - (decoded / 4)
+ for i := range br {
+ offset := dstEvery * i
+ endsAt := offset + remainBytes
+ if endsAt > len(out) {
+ endsAt = len(out)
+ }
+ br := &br[i]
+ bitsLeft := br.remaining()
+ for bitsLeft > 0 {
+ br.fill()
+ if offset >= endsAt {
+ d.bufs.Put(buf)
+ return nil, errors.New("corruption detected: stream overrun 4")
+ }
+
+ // Read value and increment offset.
+ val := br.peekBitsFast(d.actualTableLog)
+ v := single[val&tlMask].entry
+ nBits := uint8(v)
+ br.advance(nBits)
+ bitsLeft -= uint(nBits)
+ out[offset] = uint8(v >> 8)
+ offset++
+ }
+ if offset != endsAt {
+ d.bufs.Put(buf)
+ return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
+ }
+ decoded += offset - dstEvery*i
+ err = br.close()
+ if err != nil {
+ return nil, err
+ }
+ }
+ d.bufs.Put(buf)
+ if dstSize != decoded {
+ return nil, errors.New("corruption detected: short output block")
+ }
+ return dst, nil
+}
+
+// Decompress1X will decompress a 1X encoded stream.
+// The cap of the output buffer will be the maximum decompressed size.
+// The length of the supplied input must match the end of a block exactly.
+func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
+ if len(d.dt.single) == 0 {
+ return nil, errors.New("no table loaded")
+ }
+ if use8BitTables && d.actualTableLog <= 8 {
+ return d.decompress1X8Bit(dst, src)
+ }
+ var br bitReaderShifted
+ err := br.init(src)
+ if err != nil {
+ return dst, err
+ }
+ maxDecodedSize := cap(dst)
+ dst = dst[:0]
+
+ // Avoid bounds check by always having full sized table.
+ const tlSize = 1 << tableLogMax
+ const tlMask = tlSize - 1
+ dt := d.dt.single[:tlSize]
+
+ // Use temp table to avoid bound checks/append penalty.
+ bufs := d.buffer()
+ buf := &bufs[0]
+ var off uint8
+
+ for br.off >= 8 {
+ br.fillFast()
+ v := dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ // Refill
+ br.fillFast()
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[br.peekBitsFast(d.actualTableLog)&tlMask]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ d.bufs.Put(bufs)
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+
+ if len(dst)+int(off) > maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:off]...)
+
+ // br < 8, so uint8 is fine
+ bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
+ for bitsLeft > 0 {
+ br.fill()
+ if false && br.bitsRead >= 32 {
+ if br.off >= 4 {
+ v := br.in[br.off-4:]
+ v = v[:4]
+ low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
+ br.value = (br.value << 32) | uint64(low)
+ br.bitsRead -= 32
+ br.off -= 4
+ } else {
+ for br.off > 0 {
+ br.value = (br.value << 8) | uint64(br.in[br.off-1])
+ br.bitsRead -= 8
+ br.off--
+ }
+ }
+ }
+ if len(dst) >= maxDecodedSize {
+ d.bufs.Put(bufs)
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
+ nBits := uint8(v.entry)
+ br.advance(nBits)
+ bitsLeft -= nBits
+ dst = append(dst, uint8(v.entry>>8))
+ }
+ d.bufs.Put(bufs)
+ return dst, br.close()
+}
diff --git a/vendor/github.com/klauspost/compress/huff0/huff0.go b/vendor/github.com/klauspost/compress/huff0/huff0.go
new file mode 100644
index 00000000..67d9e05b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/huff0/huff0.go
@@ -0,0 +1,337 @@
+// Package huff0 provides fast huffman encoding as used in zstd.
+//
+// See README.md at https://github.com/klauspost/compress/tree/master/huff0 for details.
+package huff0
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "math/bits"
+ "sync"
+
+ "github.com/klauspost/compress/fse"
+)
+
+const (
+ maxSymbolValue = 255
+
+ // zstandard limits tablelog to 11, see:
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#huffman-tree-description
+ tableLogMax = 11
+ tableLogDefault = 11
+ minTablelog = 5
+ huffNodesLen = 512
+
+ // BlockSizeMax is maximum input size for a single block uncompressed.
+ BlockSizeMax = 1<<18 - 1
+)
+
+var (
+ // ErrIncompressible is returned when input is judged to be too hard to compress.
+ ErrIncompressible = errors.New("input is not compressible")
+
+ // ErrUseRLE is returned from the compressor when the input is a single byte value repeated.
+ ErrUseRLE = errors.New("input is single value repeated")
+
+ // ErrTooBig is return if input is too large for a single block.
+ ErrTooBig = errors.New("input too big")
+
+ // ErrMaxDecodedSizeExceeded is return if input is too large for a single block.
+ ErrMaxDecodedSizeExceeded = errors.New("maximum output size exceeded")
+)
+
+type ReusePolicy uint8
+
+const (
+ // ReusePolicyAllow will allow reuse if it produces smaller output.
+ ReusePolicyAllow ReusePolicy = iota
+
+ // ReusePolicyPrefer will re-use aggressively if possible.
+ // This will not check if a new table will produce smaller output,
+ // except if the current table is impossible to use or
+ // compressed output is bigger than input.
+ ReusePolicyPrefer
+
+ // ReusePolicyNone will disable re-use of tables.
+ // This is slightly faster than ReusePolicyAllow but may produce larger output.
+ ReusePolicyNone
+
+ // ReusePolicyMust must allow reuse and produce smaller output.
+ ReusePolicyMust
+)
+
+type Scratch struct {
+ count [maxSymbolValue + 1]uint32
+
+ // Per block parameters.
+ // These can be used to override compression parameters of the block.
+ // Do not touch, unless you know what you are doing.
+
+ // Out is output buffer.
+ // If the scratch is re-used before the caller is done processing the output,
+ // set this field to nil.
+ // Otherwise the output buffer will be re-used for next Compression/Decompression step
+ // and allocation will be avoided.
+ Out []byte
+
+ // OutTable will contain the table data only, if a new table has been generated.
+ // Slice of the returned data.
+ OutTable []byte
+
+ // OutData will contain the compressed data.
+ // Slice of the returned data.
+ OutData []byte
+
+ // MaxDecodedSize will set the maximum allowed output size.
+ // This value will automatically be set to BlockSizeMax if not set.
+ // Decoders will return ErrMaxDecodedSizeExceeded is this limit is exceeded.
+ MaxDecodedSize int
+
+ srcLen int
+
+ // MaxSymbolValue will override the maximum symbol value of the next block.
+ MaxSymbolValue uint8
+
+ // TableLog will attempt to override the tablelog for the next block.
+ // Must be <= 11 and >= 5.
+ TableLog uint8
+
+ // Reuse will specify the reuse policy
+ Reuse ReusePolicy
+
+ // WantLogLess allows to specify a log 2 reduction that should at least be achieved,
+ // otherwise the block will be returned as incompressible.
+ // The reduction should then at least be (input size >> WantLogLess)
+ // If WantLogLess == 0 any improvement will do.
+ WantLogLess uint8
+
+ symbolLen uint16 // Length of active part of the symbol table.
+ maxCount int // count of the most probable symbol
+ clearCount bool // clear count
+ actualTableLog uint8 // Selected tablelog.
+ prevTableLog uint8 // Tablelog for previous table
+ prevTable cTable // Table used for previous compression.
+ cTable cTable // compression table
+ dt dTable // decompression table
+ nodes []nodeElt
+ tmpOut [4][]byte
+ fse *fse.Scratch
+ decPool sync.Pool // *[4][256]byte buffers.
+ huffWeight [maxSymbolValue + 1]byte
+}
+
+// TransferCTable will transfer the previously used compression table.
+func (s *Scratch) TransferCTable(src *Scratch) {
+ if cap(s.prevTable) < len(src.prevTable) {
+ s.prevTable = make(cTable, 0, maxSymbolValue+1)
+ }
+ s.prevTable = s.prevTable[:len(src.prevTable)]
+ copy(s.prevTable, src.prevTable)
+ s.prevTableLog = src.prevTableLog
+}
+
+func (s *Scratch) prepare(in []byte) (*Scratch, error) {
+ if len(in) > BlockSizeMax {
+ return nil, ErrTooBig
+ }
+ if s == nil {
+ s = &Scratch{}
+ }
+ if s.MaxSymbolValue == 0 {
+ s.MaxSymbolValue = maxSymbolValue
+ }
+ if s.TableLog == 0 {
+ s.TableLog = tableLogDefault
+ }
+ if s.TableLog > tableLogMax || s.TableLog < minTablelog {
+ return nil, fmt.Errorf(" invalid tableLog %d (%d -> %d)", s.TableLog, minTablelog, tableLogMax)
+ }
+ if s.MaxDecodedSize <= 0 || s.MaxDecodedSize > BlockSizeMax {
+ s.MaxDecodedSize = BlockSizeMax
+ }
+ if s.clearCount && s.maxCount == 0 {
+ for i := range s.count {
+ s.count[i] = 0
+ }
+ s.clearCount = false
+ }
+ if cap(s.Out) == 0 {
+ s.Out = make([]byte, 0, len(in))
+ }
+ s.Out = s.Out[:0]
+
+ s.OutTable = nil
+ s.OutData = nil
+ if cap(s.nodes) < huffNodesLen+1 {
+ s.nodes = make([]nodeElt, 0, huffNodesLen+1)
+ }
+ s.nodes = s.nodes[:0]
+ if s.fse == nil {
+ s.fse = &fse.Scratch{}
+ }
+ s.srcLen = len(in)
+
+ return s, nil
+}
+
+type cTable []cTableEntry
+
+func (c cTable) write(s *Scratch) error {
+ var (
+ // precomputed conversion table
+ bitsToWeight [tableLogMax + 1]byte
+ huffLog = s.actualTableLog
+ // last weight is not saved.
+ maxSymbolValue = uint8(s.symbolLen - 1)
+ huffWeight = s.huffWeight[:256]
+ )
+ const (
+ maxFSETableLog = 6
+ )
+ // convert to weight
+ bitsToWeight[0] = 0
+ for n := uint8(1); n < huffLog+1; n++ {
+ bitsToWeight[n] = huffLog + 1 - n
+ }
+
+ // Acquire histogram for FSE.
+ hist := s.fse.Histogram()
+ hist = hist[:256]
+ for i := range hist[:16] {
+ hist[i] = 0
+ }
+ for n := range maxSymbolValue {
+ v := bitsToWeight[c[n].nBits] & 15
+ huffWeight[n] = v
+ hist[v]++
+ }
+
+ // FSE compress if feasible.
+ if maxSymbolValue >= 2 {
+ huffMaxCnt := uint32(0)
+ huffMax := uint8(0)
+ for i, v := range hist[:16] {
+ if v == 0 {
+ continue
+ }
+ huffMax = byte(i)
+ if v > huffMaxCnt {
+ huffMaxCnt = v
+ }
+ }
+ s.fse.HistogramFinished(huffMax, int(huffMaxCnt))
+ s.fse.TableLog = maxFSETableLog
+ b, err := fse.Compress(huffWeight[:maxSymbolValue], s.fse)
+ if err == nil && len(b) < int(s.symbolLen>>1) {
+ s.Out = append(s.Out, uint8(len(b)))
+ s.Out = append(s.Out, b...)
+ return nil
+ }
+ // Unable to compress (RLE/uncompressible)
+ }
+ // write raw values as 4-bits (max : 15)
+ if maxSymbolValue > (256 - 128) {
+ // should not happen : likely means source cannot be compressed
+ return ErrIncompressible
+ }
+ op := s.Out
+ // special case, pack weights 4 bits/weight.
+ op = append(op, 128|(maxSymbolValue-1))
+ // be sure it doesn't cause msan issue in final combination
+ huffWeight[maxSymbolValue] = 0
+ for n := uint16(0); n < uint16(maxSymbolValue); n += 2 {
+ op = append(op, (huffWeight[n]<<4)|huffWeight[n+1])
+ }
+ s.Out = op
+ return nil
+}
+
+func (c cTable) estTableSize(s *Scratch) (sz int, err error) {
+ var (
+ // precomputed conversion table
+ bitsToWeight [tableLogMax + 1]byte
+ huffLog = s.actualTableLog
+ // last weight is not saved.
+ maxSymbolValue = uint8(s.symbolLen - 1)
+ huffWeight = s.huffWeight[:256]
+ )
+ const (
+ maxFSETableLog = 6
+ )
+ // convert to weight
+ bitsToWeight[0] = 0
+ for n := uint8(1); n < huffLog+1; n++ {
+ bitsToWeight[n] = huffLog + 1 - n
+ }
+
+ // Acquire histogram for FSE.
+ hist := s.fse.Histogram()
+ hist = hist[:256]
+ for i := range hist[:16] {
+ hist[i] = 0
+ }
+ for n := range maxSymbolValue {
+ v := bitsToWeight[c[n].nBits] & 15
+ huffWeight[n] = v
+ hist[v]++
+ }
+
+ // FSE compress if feasible.
+ if maxSymbolValue >= 2 {
+ huffMaxCnt := uint32(0)
+ huffMax := uint8(0)
+ for i, v := range hist[:16] {
+ if v == 0 {
+ continue
+ }
+ huffMax = byte(i)
+ if v > huffMaxCnt {
+ huffMaxCnt = v
+ }
+ }
+ s.fse.HistogramFinished(huffMax, int(huffMaxCnt))
+ s.fse.TableLog = maxFSETableLog
+ b, err := fse.Compress(huffWeight[:maxSymbolValue], s.fse)
+ if err == nil && len(b) < int(s.symbolLen>>1) {
+ sz += 1 + len(b)
+ return sz, nil
+ }
+ // Unable to compress (RLE/uncompressible)
+ }
+ // write raw values as 4-bits (max : 15)
+ if maxSymbolValue > (256 - 128) {
+ // should not happen : likely means source cannot be compressed
+ return 0, ErrIncompressible
+ }
+ // special case, pack weights 4 bits/weight.
+ sz += 1 + int(maxSymbolValue/2)
+ return sz, nil
+}
+
+// estimateSize returns the estimated size in bytes of the input represented in the
+// histogram supplied.
+func (c cTable) estimateSize(hist []uint32) int {
+ nbBits := uint32(7)
+ for i, v := range c[:len(hist)] {
+ nbBits += uint32(v.nBits) * hist[i]
+ }
+ return int(nbBits >> 3)
+}
+
+// minSize returns the minimum possible size considering the shannon limit.
+func (s *Scratch) minSize(total int) int {
+ nbBits := float64(7)
+ fTotal := float64(total)
+ for _, v := range s.count[:s.symbolLen] {
+ n := float64(v)
+ if n > 0 {
+ nbBits += math.Log2(fTotal/n) * n
+ }
+ }
+ return int(nbBits) >> 3
+}
+
+func highBit32(val uint32) (n uint32) {
+ return uint32(bits.Len32(val) - 1)
+}
diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go
new file mode 100644
index 00000000..3954c512
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go
@@ -0,0 +1,34 @@
+// Package cpuinfo gives runtime info about the current CPU.
+//
+// This is a very limited module meant for use internally
+// in this project. For more versatile solution check
+// https://github.com/klauspost/cpuid.
+package cpuinfo
+
+// HasBMI1 checks whether an x86 CPU supports the BMI1 extension.
+func HasBMI1() bool {
+ return hasBMI1
+}
+
+// HasBMI2 checks whether an x86 CPU supports the BMI2 extension.
+func HasBMI2() bool {
+ return hasBMI2
+}
+
+// DisableBMI2 will disable BMI2, for testing purposes.
+// Call returned function to restore previous state.
+func DisableBMI2() func() {
+ old := hasBMI2
+ hasBMI2 = false
+ return func() {
+ hasBMI2 = old
+ }
+}
+
+// HasBMI checks whether an x86 CPU supports both BMI1 and BMI2 extensions.
+func HasBMI() bool {
+ return HasBMI1() && HasBMI2()
+}
+
+var hasBMI1 bool
+var hasBMI2 bool
diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
new file mode 100644
index 00000000..b97f9056
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go
@@ -0,0 +1,10 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+package cpuinfo
+
+// go:noescape
+func x86extensions() (bmi1, bmi2 bool)
+
+func init() {
+ hasBMI1, hasBMI2 = x86extensions()
+}
diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s
new file mode 100644
index 00000000..4465fbe9
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s
@@ -0,0 +1,36 @@
+// +build !appengine
+// +build gc
+// +build !noasm
+
+#include "textflag.h"
+#include "funcdata.h"
+#include "go_asm.h"
+
+TEXT ·x86extensions(SB), NOSPLIT, $0
+ // 1. determine max EAX value
+ XORQ AX, AX
+ CPUID
+
+ CMPQ AX, $7
+ JB unsupported
+
+ // 2. EAX = 7, ECX = 0 --- see Table 3-8 "Information Returned by CPUID Instruction"
+ MOVQ $7, AX
+ MOVQ $0, CX
+ CPUID
+
+ BTQ $3, BX // bit 3 = BMI1
+ SETCS AL
+
+ BTQ $8, BX // bit 8 = BMI2
+ SETCS AH
+
+ MOVB AL, bmi1+0(FP)
+ MOVB AH, bmi2+1(FP)
+ RET
+
+unsupported:
+ XORQ AX, AX
+ MOVB AL, bmi1+0(FP)
+ MOVB AL, bmi2+1(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/internal/le/le.go b/vendor/github.com/klauspost/compress/internal/le/le.go
new file mode 100644
index 00000000..e54909e1
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/le/le.go
@@ -0,0 +1,5 @@
+package le
+
+type Indexer interface {
+ int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
+}
diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
new file mode 100644
index 00000000..4f2a0d8c
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go
@@ -0,0 +1,42 @@
+//go:build !(amd64 || arm64 || ppc64le || riscv64) || nounsafe || purego || appengine
+
+package le
+
+import (
+ "encoding/binary"
+)
+
+// Load8 will load from b at index i.
+func Load8[I Indexer](b []byte, i I) byte {
+ return b[i]
+}
+
+// Load16 will load from b at index i.
+func Load16[I Indexer](b []byte, i I) uint16 {
+ return binary.LittleEndian.Uint16(b[i:])
+}
+
+// Load32 will load from b at index i.
+func Load32[I Indexer](b []byte, i I) uint32 {
+ return binary.LittleEndian.Uint32(b[i:])
+}
+
+// Load64 will load from b at index i.
+func Load64[I Indexer](b []byte, i I) uint64 {
+ return binary.LittleEndian.Uint64(b[i:])
+}
+
+// Store16 will store v at b.
+func Store16(b []byte, v uint16) {
+ binary.LittleEndian.PutUint16(b, v)
+}
+
+// Store32 will store v at b.
+func Store32(b []byte, v uint32) {
+ binary.LittleEndian.PutUint32(b, v)
+}
+
+// Store64 will store v at b.
+func Store64[I Indexer](b []byte, i I, v uint64) {
+ binary.LittleEndian.PutUint64(b[i:], v)
+}
diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
new file mode 100644
index 00000000..218a38bc
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go
@@ -0,0 +1,52 @@
+// We enable 64 bit LE platforms:
+
+//go:build (amd64 || arm64 || ppc64le || riscv64) && !nounsafe && !purego && !appengine
+
+package le
+
+import (
+ "unsafe"
+)
+
+// Load8 will load from b at index i.
+func Load8[I Indexer](b []byte, i I) byte {
+ //return binary.LittleEndian.Uint16(b[i:])
+ //return *(*uint16)(unsafe.Pointer(&b[i]))
+ return *(*byte)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Load16 will load from b at index i.
+func Load16[I Indexer](b []byte, i I) uint16 {
+ //return binary.LittleEndian.Uint16(b[i:])
+ //return *(*uint16)(unsafe.Pointer(&b[i]))
+ return *(*uint16)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Load32 will load from b at index i.
+func Load32[I Indexer](b []byte, i I) uint32 {
+ //return binary.LittleEndian.Uint32(b[i:])
+ //return *(*uint32)(unsafe.Pointer(&b[i]))
+ return *(*uint32)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Load64 will load from b at index i.
+func Load64[I Indexer](b []byte, i I) uint64 {
+ //return binary.LittleEndian.Uint64(b[i:])
+ //return *(*uint64)(unsafe.Pointer(&b[i]))
+ return *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i))
+}
+
+// Store16 will store v at b.
+func Store16(b []byte, v uint16) {
+ *(*uint16)(unsafe.Pointer(unsafe.SliceData(b))) = v
+}
+
+// Store32 will store v at b.
+func Store32(b []byte, v uint32) {
+ *(*uint32)(unsafe.Pointer(unsafe.SliceData(b))) = v
+}
+
+// Store64 will store v at b[i:].
+func Store64[I Indexer](b []byte, i I, v uint64) {
+ *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) = v
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/LICENSE b/vendor/github.com/klauspost/compress/internal/snapref/LICENSE
new file mode 100644
index 00000000..6050c10f
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/LICENSE
@@ -0,0 +1,27 @@
+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.
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/decode.go b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
new file mode 100644
index 00000000..a2c82fcd
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/decode.go
@@ -0,0 +1,264 @@
+// Copyright 2011 The Snappy-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 snapref
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+var (
+ // ErrCorrupt reports that the input is invalid.
+ ErrCorrupt = errors.New("snappy: corrupt input")
+ // ErrTooLarge reports that the uncompressed length is too large.
+ ErrTooLarge = errors.New("snappy: decoded block is too large")
+ // ErrUnsupported reports that the input isn't supported.
+ ErrUnsupported = errors.New("snappy: unsupported input")
+
+ errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
+)
+
+// DecodedLen returns the length of the decoded block.
+func DecodedLen(src []byte) (int, error) {
+ v, _, err := decodedLen(src)
+ return v, err
+}
+
+// decodedLen returns the length of the decoded block and the number of bytes
+// that the length header occupied.
+func decodedLen(src []byte) (blockLen, headerLen int, err error) {
+ v, n := binary.Uvarint(src)
+ if n <= 0 || v > 0xffffffff {
+ return 0, 0, ErrCorrupt
+ }
+
+ const wordSize = 32 << (^uint(0) >> 32 & 1)
+ if wordSize == 32 && v > 0x7fffffff {
+ return 0, 0, ErrTooLarge
+ }
+ return int(v), n, nil
+}
+
+const (
+ decodeErrCodeCorrupt = 1
+ decodeErrCodeUnsupportedLiteralLength = 2
+)
+
+// Decode returns the decoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire decoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// Decode handles the Snappy block format, not the Snappy stream format.
+func Decode(dst, src []byte) ([]byte, error) {
+ dLen, s, err := decodedLen(src)
+ if err != nil {
+ return nil, err
+ }
+ if dLen <= len(dst) {
+ dst = dst[:dLen]
+ } else {
+ dst = make([]byte, dLen)
+ }
+ switch decode(dst, src[s:]) {
+ case 0:
+ return dst, nil
+ case decodeErrCodeUnsupportedLiteralLength:
+ return nil, errUnsupportedLiteralLength
+ }
+ return nil, ErrCorrupt
+}
+
+// NewReader returns a new Reader that decompresses from r, using the framing
+// format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ r: r,
+ decoded: make([]byte, maxBlockSize),
+ buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize),
+ }
+}
+
+// Reader is an io.Reader that can read Snappy-compressed bytes.
+//
+// Reader handles the Snappy stream format, not the Snappy block format.
+type Reader struct {
+ r io.Reader
+ err error
+ decoded []byte
+ buf []byte
+ // decoded[i:j] contains decoded bytes that have not yet been passed on.
+ i, j int
+ readHeader bool
+}
+
+// Reset discards any buffered data, resets all state, and switches the Snappy
+// reader to read from r. This permits reusing a Reader rather than allocating
+// a new one.
+func (r *Reader) Reset(reader io.Reader) {
+ r.r = reader
+ r.err = nil
+ r.i = 0
+ r.j = 0
+ r.readHeader = false
+}
+
+func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) {
+ if _, r.err = io.ReadFull(r.r, p); r.err != nil {
+ if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
+ r.err = ErrCorrupt
+ }
+ return false
+ }
+ return true
+}
+
+func (r *Reader) fill() error {
+ for r.i >= r.j {
+ if !r.readFull(r.buf[:4], true) {
+ return r.err
+ }
+ chunkType := r.buf[0]
+ if !r.readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.readHeader = true
+ }
+ chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
+ if chunkLen > len(r.buf) {
+ r.err = ErrUnsupported
+ return r.err
+ }
+
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ // Section 4.2. Compressed data (chunk type 0x00).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ buf := r.buf[:chunkLen]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ buf = buf[checksumSize:]
+
+ n, err := DecodedLen(buf)
+ if err != nil {
+ r.err = err
+ return r.err
+ }
+ if n > len(r.decoded) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if _, err := Decode(r.decoded, buf); err != nil {
+ r.err = err
+ return r.err
+ }
+ if crc(r.decoded[:n]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeUncompressedData:
+ // Section 4.3. Uncompressed data (chunk type 0x01).
+ if chunkLen < checksumSize {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ buf := r.buf[:checksumSize]
+ if !r.readFull(buf, false) {
+ return r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ // Read directly into r.decoded instead of via r.buf.
+ n := chunkLen - checksumSize
+ if n > len(r.decoded) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.readFull(r.decoded[:n], false) {
+ return r.err
+ }
+ if crc(r.decoded[:n]) != checksum {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ r.i, r.j = 0, n
+ continue
+
+ case chunkTypeStreamIdentifier:
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(magicBody) {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ if !r.readFull(r.buf[:len(magicBody)], false) {
+ return r.err
+ }
+ for i := range len(magicBody) {
+ if r.buf[i] != magicBody[i] {
+ r.err = ErrCorrupt
+ return r.err
+ }
+ }
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ r.err = ErrUnsupported
+ return r.err
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if !r.readFull(r.buf[:chunkLen], false) {
+ return r.err
+ }
+ }
+
+ return nil
+}
+
+// Read satisfies the io.Reader interface.
+func (r *Reader) Read(p []byte) (int, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+
+ if err := r.fill(); err != nil {
+ return 0, err
+ }
+
+ n := copy(p, r.decoded[r.i:r.j])
+ r.i += n
+ return n, nil
+}
+
+// ReadByte satisfies the io.ByteReader interface.
+func (r *Reader) ReadByte() (byte, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+
+ if err := r.fill(); err != nil {
+ return 0, err
+ }
+
+ c := r.decoded[r.i]
+ r.i++
+ return c, nil
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go
new file mode 100644
index 00000000..77395a6b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go
@@ -0,0 +1,113 @@
+// Copyright 2016 The Snappy-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 snapref
+
+// decode writes the decoding of src to dst. It assumes that the varint-encoded
+// length of the decompressed bytes has already been read, and that len(dst)
+// equals that length.
+//
+// It returns 0 on success or a decodeErrCodeXxx error code on failure.
+func decode(dst, src []byte) int {
+ var d, s, offset, length int
+ for s < len(src) {
+ switch src[s] & 0x03 {
+ case tagLiteral:
+ x := uint32(src[s] >> 2)
+ switch {
+ case x < 60:
+ s++
+ case x == 60:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-1])
+ case x == 61:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ case x == 62:
+ s += 4
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ case x == 63:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ }
+ length = int(x) + 1
+ if length <= 0 {
+ return decodeErrCodeUnsupportedLiteralLength
+ }
+ if length > len(dst)-d || length > len(src)-s {
+ return decodeErrCodeCorrupt
+ }
+ copy(dst[d:], src[s:s+length])
+ d += length
+ s += length
+ continue
+
+ case tagCopy1:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 4 + int(src[s-2])>>2&0x7
+ offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]))
+
+ case tagCopy2:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-3])>>2
+ offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8)
+
+ case tagCopy4:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ return decodeErrCodeCorrupt
+ }
+ length = 1 + int(src[s-5])>>2
+ offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24)
+ }
+
+ if offset <= 0 || d < offset || length > len(dst)-d {
+ return decodeErrCodeCorrupt
+ }
+ // Copy from an earlier sub-slice of dst to a later sub-slice.
+ // If no overlap, use the built-in copy:
+ if offset >= length {
+ copy(dst[d:d+length], dst[d-offset:])
+ d += length
+ continue
+ }
+
+ // Unlike the built-in copy function, this byte-by-byte copy always runs
+ // forwards, even if the slices overlap. Conceptually, this is:
+ //
+ // d += forwardCopy(dst[d:d+length], dst[d-offset:])
+ //
+ // We align the slices into a and b and show the compiler they are the same size.
+ // This allows the loop to run without bounds checks.
+ a := dst[d : d+length]
+ b := dst[d-offset:]
+ b = b[:len(a)]
+ for i := range a {
+ a[i] = b[i]
+ }
+ d += length
+ }
+ if d != len(dst) {
+ return decodeErrCodeCorrupt
+ }
+ return 0
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode.go b/vendor/github.com/klauspost/compress/internal/snapref/encode.go
new file mode 100644
index 00000000..860a9941
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/encode.go
@@ -0,0 +1,291 @@
+// Copyright 2011 The Snappy-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 snapref
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+// Encode returns the encoded form of src. The returned slice may be a sub-
+// slice of dst if dst was large enough to hold the entire encoded block.
+// Otherwise, a newly allocated slice will be returned.
+//
+// The dst and src must not overlap. It is valid to pass a nil dst.
+//
+// Encode handles the Snappy block format, not the Snappy stream format.
+func Encode(dst, src []byte) []byte {
+ if n := MaxEncodedLen(len(src)); n < 0 {
+ panic(ErrTooLarge)
+ } else if cap(dst) < n {
+ dst = make([]byte, n)
+ } else {
+ dst = dst[:n]
+ }
+
+ // The block starts with the varint-encoded length of the decompressed bytes.
+ d := binary.PutUvarint(dst, uint64(len(src)))
+
+ for len(src) > 0 {
+ p := src
+ src = nil
+ if len(p) > maxBlockSize {
+ p, src = p[:maxBlockSize], p[maxBlockSize:]
+ }
+ if len(p) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], p)
+ } else {
+ d += encodeBlock(dst[d:], p)
+ }
+ }
+ return dst[:d]
+}
+
+// inputMargin is the minimum number of extra input bytes to keep, inside
+// encodeBlock's inner loop. On some architectures, this margin lets us
+// implement a fast path for emitLiteral, where the copy of short (<= 16 byte)
+// literals can be implemented as a single load to and store from a 16-byte
+// register. That literal's actual length can be as short as 1 byte, so this
+// can copy up to 15 bytes too much, but that's OK as subsequent iterations of
+// the encoding loop will fix up the copy overrun, and this inputMargin ensures
+// that we don't overrun the dst and src buffers.
+const inputMargin = 16 - 1
+
+// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that
+// could be encoded with a copy tag. This is the minimum with respect to the
+// algorithm used by encodeBlock, not a minimum enforced by the file format.
+//
+// The encoded output must start with at least a 1 byte literal, as there are
+// no previous bytes to copy. A minimal (1 byte) copy after that, generated
+// from an emitCopy call in encodeBlock's main loop, would require at least
+// another inputMargin bytes, for the reason above: we want any emitLiteral
+// calls inside encodeBlock's main loop to use the fast path if possible, which
+// requires being able to overrun by inputMargin bytes. Thus,
+// minNonLiteralBlockSize equals 1 + 1 + inputMargin.
+//
+// The C++ code doesn't use this exact threshold, but it could, as discussed at
+// https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion
+// The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an
+// optimization. It should not affect the encoded form. This is tested by
+// TestSameEncodingAsCppShortCopies.
+const minNonLiteralBlockSize = 1 + 1 + inputMargin
+
+// MaxEncodedLen returns the maximum length of a snappy block, given its
+// uncompressed length.
+//
+// It will return a negative value if srcLen is too large to encode.
+func MaxEncodedLen(srcLen int) int {
+ n := uint64(srcLen)
+ if n > 0xffffffff {
+ return -1
+ }
+ // Compressed data can be defined as:
+ // compressed := item* literal*
+ // item := literal* copy
+ //
+ // The trailing literal sequence has a space blowup of at most 62/60
+ // since a literal of length 60 needs one tag byte + one extra byte
+ // for length information.
+ //
+ // Item blowup is trickier to measure. Suppose the "copy" op copies
+ // 4 bytes of data. Because of a special check in the encoding code,
+ // we produce a 4-byte copy only if the offset is < 65536. Therefore
+ // the copy op takes 3 bytes to encode, and this type of item leads
+ // to at most the 62/60 blowup for representing literals.
+ //
+ // Suppose the "copy" op copies 5 bytes of data. If the offset is big
+ // enough, it will take 5 bytes to encode the copy op. Therefore the
+ // worst case here is a one-byte literal followed by a five-byte copy.
+ // That is, 6 bytes of input turn into 7 bytes of "compressed" data.
+ //
+ // This last factor dominates the blowup, so the final estimate is:
+ n = 32 + n + n/6
+ if n > 0xffffffff {
+ return -1
+ }
+ return int(n)
+}
+
+var errClosed = errors.New("snappy: Writer is closed")
+
+// NewWriter returns a new Writer that compresses to w.
+//
+// The Writer returned does not buffer writes. There is no need to Flush or
+// Close such a Writer.
+//
+// Deprecated: the Writer returned is not suitable for many small writes, only
+// for few large writes. Use NewBufferedWriter instead, which is efficient
+// regardless of the frequency and shape of the writes, and remember to Close
+// that Writer when done.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{
+ w: w,
+ obuf: make([]byte, obufLen),
+ }
+}
+
+// NewBufferedWriter returns a new Writer that compresses to w, using the
+// framing format described at
+// https://github.com/google/snappy/blob/master/framing_format.txt
+//
+// The Writer returned buffers writes. Users must call Close to guarantee all
+// data has been forwarded to the underlying io.Writer. They may also call
+// Flush zero or more times before calling Close.
+func NewBufferedWriter(w io.Writer) *Writer {
+ return &Writer{
+ w: w,
+ ibuf: make([]byte, 0, maxBlockSize),
+ obuf: make([]byte, obufLen),
+ }
+}
+
+// Writer is an io.Writer that can write Snappy-compressed bytes.
+//
+// Writer handles the Snappy stream format, not the Snappy block format.
+type Writer struct {
+ w io.Writer
+ err error
+
+ // ibuf is a buffer for the incoming (uncompressed) bytes.
+ //
+ // Its use is optional. For backwards compatibility, Writers created by the
+ // NewWriter function have ibuf == nil, do not buffer incoming bytes, and
+ // therefore do not need to be Flush'ed or Close'd.
+ ibuf []byte
+
+ // obuf is a buffer for the outgoing (compressed) bytes.
+ obuf []byte
+
+ // wroteStreamHeader is whether we have written the stream header.
+ wroteStreamHeader bool
+}
+
+// Reset discards the writer's state and switches the Snappy writer to write to
+// w. This permits reusing a Writer rather than allocating a new one.
+func (w *Writer) Reset(writer io.Writer) {
+ w.w = writer
+ w.err = nil
+ if w.ibuf != nil {
+ w.ibuf = w.ibuf[:0]
+ }
+ w.wroteStreamHeader = false
+}
+
+// Write satisfies the io.Writer interface.
+func (w *Writer) Write(p []byte) (nRet int, errRet error) {
+ if w.ibuf == nil {
+ // Do not buffer incoming bytes. This does not perform or compress well
+ // if the caller of Writer.Write writes many small slices. This
+ // behavior is therefore deprecated, but still supported for backwards
+ // compatibility with code that doesn't explicitly Flush or Close.
+ return w.write(p)
+ }
+
+ // The remainder of this method is based on bufio.Writer.Write from the
+ // standard library.
+
+ for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil {
+ var n int
+ if len(w.ibuf) == 0 {
+ // Large write, empty buffer.
+ // Write directly from p to avoid copy.
+ n, _ = w.write(p)
+ } else {
+ n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ w.Flush()
+ }
+ nRet += n
+ p = p[n:]
+ }
+ if w.err != nil {
+ return nRet, w.err
+ }
+ n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
+ w.ibuf = w.ibuf[:len(w.ibuf)+n]
+ nRet += n
+ return nRet, nil
+}
+
+func (w *Writer) write(p []byte) (nRet int, errRet error) {
+ if w.err != nil {
+ return 0, w.err
+ }
+ for len(p) > 0 {
+ obufStart := len(magicChunk)
+ if !w.wroteStreamHeader {
+ w.wroteStreamHeader = true
+ copy(w.obuf, magicChunk)
+ obufStart = 0
+ }
+
+ var uncompressed []byte
+ if len(p) > maxBlockSize {
+ uncompressed, p = p[:maxBlockSize], p[maxBlockSize:]
+ } else {
+ uncompressed, p = p, nil
+ }
+ checksum := crc(uncompressed)
+
+ // Compress the buffer, discarding the result if the improvement
+ // isn't at least 12.5%.
+ compressed := Encode(w.obuf[obufHeaderLen:], uncompressed)
+ chunkType := uint8(chunkTypeCompressedData)
+ chunkLen := 4 + len(compressed)
+ obufEnd := obufHeaderLen + len(compressed)
+ if len(compressed) >= len(uncompressed)-len(uncompressed)/8 {
+ chunkType = chunkTypeUncompressedData
+ chunkLen = 4 + len(uncompressed)
+ obufEnd = obufHeaderLen
+ }
+
+ // Fill in the per-chunk header that comes before the body.
+ w.obuf[len(magicChunk)+0] = chunkType
+ w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0)
+ w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8)
+ w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16)
+ w.obuf[len(magicChunk)+4] = uint8(checksum >> 0)
+ w.obuf[len(magicChunk)+5] = uint8(checksum >> 8)
+ w.obuf[len(magicChunk)+6] = uint8(checksum >> 16)
+ w.obuf[len(magicChunk)+7] = uint8(checksum >> 24)
+
+ if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil {
+ w.err = err
+ return nRet, err
+ }
+ if chunkType == chunkTypeUncompressedData {
+ if _, err := w.w.Write(uncompressed); err != nil {
+ w.err = err
+ return nRet, err
+ }
+ }
+ nRet += len(uncompressed)
+ }
+ return nRet, nil
+}
+
+// Flush flushes the Writer to its underlying io.Writer.
+func (w *Writer) Flush() error {
+ if w.err != nil {
+ return w.err
+ }
+ if len(w.ibuf) == 0 {
+ return nil
+ }
+ w.write(w.ibuf)
+ w.ibuf = w.ibuf[:0]
+ return w.err
+}
+
+// Close calls Flush and then closes the Writer.
+func (w *Writer) Close() error {
+ w.Flush()
+ ret := w.err
+ if w.err == nil {
+ w.err = errClosed
+ }
+ return ret
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go
new file mode 100644
index 00000000..2754bac6
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go
@@ -0,0 +1,250 @@
+// Copyright 2016 The Snappy-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 snapref
+
+func load32(b []byte, i int) uint32 {
+ b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func load64(b []byte, i int) uint64 {
+ b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+ 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
+}
+
+// emitLiteral writes a literal chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= len(lit) && len(lit) <= 65536
+func emitLiteral(dst, lit []byte) int {
+ i, n := 0, uint(len(lit)-1)
+ switch {
+ case n < 60:
+ dst[0] = uint8(n)<<2 | tagLiteral
+ i = 1
+ case n < 1<<8:
+ dst[0] = 60<<2 | tagLiteral
+ dst[1] = uint8(n)
+ i = 2
+ default:
+ dst[0] = 61<<2 | tagLiteral
+ dst[1] = uint8(n)
+ dst[2] = uint8(n >> 8)
+ i = 3
+ }
+ return i + copy(dst[i:], lit)
+}
+
+// emitCopy writes a copy chunk and returns the number of bytes written.
+//
+// It assumes that:
+//
+// dst is long enough to hold the encoded bytes
+// 1 <= offset && offset <= 65535
+// 4 <= length && length <= 65535
+func emitCopy(dst []byte, offset, length int) int {
+ i := 0
+ // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The
+ // threshold for this loop is a little higher (at 68 = 64 + 4), and the
+ // length emitted down below is a little lower (at 60 = 64 - 4), because
+ // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed
+ // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as
+ // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as
+ // 3+3 bytes). The magic 4 in the 64±4 is because the minimum length for a
+ // tagCopy1 op is 4 bytes, which is why a length 3 copy has to be an
+ // encodes-as-3-bytes tagCopy2 instead of an encodes-as-2-bytes tagCopy1.
+ for length >= 68 {
+ // Emit a length 64 copy, encoded as 3 bytes.
+ dst[i+0] = 63<<2 | tagCopy2
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ i += 3
+ length -= 64
+ }
+ if length > 64 {
+ // Emit a length 60 copy, encoded as 3 bytes.
+ dst[i+0] = 59<<2 | tagCopy2
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ i += 3
+ length -= 60
+ }
+ if length >= 12 || offset >= 2048 {
+ // Emit the remaining copy, encoded as 3 bytes.
+ dst[i+0] = uint8(length-1)<<2 | tagCopy2
+ dst[i+1] = uint8(offset)
+ dst[i+2] = uint8(offset >> 8)
+ return i + 3
+ }
+ // Emit the remaining copy, encoded as 2 bytes.
+ dst[i+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1
+ dst[i+1] = uint8(offset)
+ return i + 2
+}
+
+func hash(u, shift uint32) uint32 {
+ return (u * 0x1e35a7bd) >> shift
+}
+
+// EncodeBlockInto exposes encodeBlock but checks dst size.
+func EncodeBlockInto(dst, src []byte) (d int) {
+ if MaxEncodedLen(len(src)) > len(dst) {
+ return 0
+ }
+
+ // encodeBlock breaks on too big blocks, so split.
+ for len(src) > 0 {
+ p := src
+ src = nil
+ if len(p) > maxBlockSize {
+ p, src = p[:maxBlockSize], p[maxBlockSize:]
+ }
+ if len(p) < minNonLiteralBlockSize {
+ d += emitLiteral(dst[d:], p)
+ } else {
+ d += encodeBlock(dst[d:], p)
+ }
+ }
+ return d
+}
+
+// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It
+// assumes that the varint-encoded length of the decompressed bytes has already
+// been written.
+//
+// It also assumes that:
+//
+// len(dst) >= MaxEncodedLen(len(src)) &&
+// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize
+func encodeBlock(dst, src []byte) (d int) {
+ // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
+ // The table element type is uint16, as s < sLimit and sLimit < len(src)
+ // and len(src) <= maxBlockSize and maxBlockSize == 65536.
+ const (
+ maxTableSize = 1 << 14
+ // tableMask is redundant, but helps the compiler eliminate bounds
+ // checks.
+ tableMask = maxTableSize - 1
+ )
+ shift := uint32(32 - 8)
+ for tableSize := 1 << 8; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 {
+ shift--
+ }
+ // In Go, all array elements are zero-initialized, so there is no advantage
+ // to a smaller tableSize per se. However, it matches the C++ algorithm,
+ // and in the asm versions of this code, we can get away with zeroing only
+ // the first tableSize elements.
+ var table [maxTableSize]uint16
+
+ // 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 := len(src) - inputMargin
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := 0
+
+ // The encoded form must start with a literal, as there are no previous
+ // bytes to copy, so we start looking for hash matches at s == 1.
+ s := 1
+ nextHash := hash(load32(src, s), shift)
+
+ for {
+ // Copied from the C++ snappy implementation:
+ //
+ // 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 (or skipped), 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.
+ skip := 32
+
+ nextS := s
+ candidate := 0
+ for {
+ s = nextS
+ bytesBetweenHashLookups := skip >> 5
+ nextS = s + bytesBetweenHashLookups
+ skip += bytesBetweenHashLookups
+ if nextS > sLimit {
+ goto emitRemainder
+ }
+ candidate = int(table[nextHash&tableMask])
+ table[nextHash&tableMask] = uint16(s)
+ nextHash = hash(load32(src, nextS), shift)
+ if load32(src, s) == load32(src, candidate) {
+ break
+ }
+ }
+
+ // 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.
+ d += emitLiteral(dst[d:], src[nextEmit:s])
+
+ // 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.
+ base := s
+
+ // Extend the 4-byte match as long as possible.
+ //
+ // This is an inlined version of:
+ // s = extendMatch(src, candidate+4, s+4)
+ s += 4
+ for i := candidate + 4; s < len(src) && src[i] == src[s]; i, s = i+1, s+1 {
+ }
+
+ d += emitCopy(dst[d:], base-candidate, s-base)
+ nextEmit = s
+ 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-1 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 := load64(src, s-1)
+ prevHash := hash(uint32(x>>0), shift)
+ table[prevHash&tableMask] = uint16(s - 1)
+ currHash := hash(uint32(x>>8), shift)
+ candidate = int(table[currHash&tableMask])
+ table[currHash&tableMask] = uint16(s)
+ if uint32(x>>8) != load32(src, candidate) {
+ nextHash = hash(uint32(x>>16), shift)
+ s++
+ break
+ }
+ }
+ }
+
+emitRemainder:
+ if nextEmit < len(src) {
+ d += emitLiteral(dst[d:], src[nextEmit:])
+ }
+ return d
+}
diff --git a/vendor/github.com/klauspost/compress/internal/snapref/snappy.go b/vendor/github.com/klauspost/compress/internal/snapref/snappy.go
new file mode 100644
index 00000000..34d01f4a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/internal/snapref/snappy.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Snappy-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 snapref implements the Snappy compression format. It aims for very
+// high speeds and reasonable compression.
+//
+// There are actually two Snappy formats: block and stream. They are related,
+// but different: trying to decompress block-compressed data as a Snappy stream
+// will fail, and vice versa. The block format is the Decode and Encode
+// functions and the stream format is the Reader and Writer types.
+//
+// The block format, the more common case, is used when the complete size (the
+// number of bytes) of the original data is known upfront, at the time
+// compression starts. The stream format, also known as the framing format, is
+// for when that isn't always true.
+//
+// The canonical, C++ implementation is at https://github.com/google/snappy and
+// it only implements the block format.
+package snapref
+
+import (
+ "hash/crc32"
+)
+
+/*
+Each encoded block begins with the varint-encoded length of the decoded data,
+followed by a sequence of chunks. Chunks begin and end on byte boundaries. The
+first byte of each chunk is broken into its 2 least and 6 most significant bits
+called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag.
+Zero means a literal tag. All other values mean a copy tag.
+
+For literal tags:
+ - If m < 60, the next 1 + m bytes are literal bytes.
+ - Otherwise, let n be the little-endian unsigned integer denoted by the next
+ m - 59 bytes. The next 1 + n bytes after that are literal bytes.
+
+For copy tags, length bytes are copied from offset bytes ago, in the style of
+Lempel-Ziv compression algorithms. In particular:
+ - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12).
+ The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10
+ of the offset. The next byte is bits 0-7 of the offset.
+ - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65).
+ The length is 1 + m. The offset is the little-endian unsigned integer
+ denoted by the next 2 bytes.
+ - For l == 3, this tag is a legacy format that is no longer issued by most
+ encoders. Nonetheless, the offset ranges in [0, 1<<32) and the length in
+ [1, 65). The length is 1 + m. The offset is the little-endian unsigned
+ integer denoted by the next 4 bytes.
+*/
+const (
+ tagLiteral = 0x00
+ tagCopy1 = 0x01
+ tagCopy2 = 0x02
+ tagCopy4 = 0x03
+)
+
+const (
+ checksumSize = 4
+ chunkHeaderSize = 4
+ magicChunk = "\xff\x06\x00\x00" + magicBody
+ magicBody = "sNaPpY"
+
+ // maxBlockSize is the maximum size of the input to encodeBlock. It is not
+ // part of the wire format per se, but some parts of the encoder assume
+ // that an offset fits into a uint16.
+ //
+ // Also, for the framing format (Writer type instead of Encode function),
+ // https://github.com/google/snappy/blob/master/framing_format.txt says
+ // that "the uncompressed data in a chunk must be no longer than 65536
+ // bytes".
+ maxBlockSize = 65536
+
+ // maxEncodedLenOfMaxBlockSize equals MaxEncodedLen(maxBlockSize), but is
+ // hard coded to be a const instead of a variable, so that obufLen can also
+ // be a const. Their equivalence is confirmed by
+ // TestMaxEncodedLenOfMaxBlockSize.
+ maxEncodedLenOfMaxBlockSize = 76490
+
+ obufHeaderLen = len(magicChunk) + checksumSize + chunkHeaderSize
+ obufLen = obufHeaderLen + maxEncodedLenOfMaxBlockSize
+)
+
+const (
+ chunkTypeCompressedData = 0x00
+ chunkTypeUncompressedData = 0x01
+ chunkTypePadding = 0xfe
+ chunkTypeStreamIdentifier = 0xff
+)
+
+var crcTable = crc32.MakeTable(crc32.Castagnoli)
+
+// crc implements the checksum specified in section 3 of
+// https://github.com/google/snappy/blob/master/framing_format.txt
+func crc(b []byte) uint32 {
+ c := crc32.Update(0, crcTable, b)
+ return uint32(c>>15|c<<17) + 0xa282ead8
+}
diff --git a/vendor/github.com/klauspost/compress/s2sx.mod b/vendor/github.com/klauspost/compress/s2sx.mod
new file mode 100644
index 00000000..81bda5e2
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/s2sx.mod
@@ -0,0 +1,3 @@
+module github.com/klauspost/compress
+
+go 1.22
diff --git a/vendor/github.com/klauspost/compress/s2sx.sum b/vendor/github.com/klauspost/compress/s2sx.sum
new file mode 100644
index 00000000..e69de29b
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
new file mode 100644
index 00000000..c11d7fa2
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -0,0 +1,441 @@
+# zstd
+
+[Zstandard](https://facebook.github.io/zstd/) is a real-time compression algorithm, providing high compression ratios.
+It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder.
+A high performance compression algorithm is implemented. For now focused on speed.
+
+This package provides [compression](#Compressor) to and [decompression](#Decompressor) of Zstandard content.
+
+This package is pure Go. Use `noasm` and `nounsafe` to disable relevant features.
+
+The `zstd` package is provided as open source software using a Go standard license.
+
+Currently the package is heavily optimized for 64 bit processors and will be significantly slower on 32 bit processors.
+
+For seekable zstd streams, see [this excellent package](https://github.com/SaveTheRbtz/zstd-seekable-format-go).
+
+## Installation
+
+Install using `go get -u github.com/klauspost/compress`. The package is located in `github.com/klauspost/compress/zstd`.
+
+[](https://pkg.go.dev/github.com/klauspost/compress/zstd)
+
+## Compressor
+
+### Status:
+
+STABLE - there may always be subtle bugs, a wide variety of content has been tested and the library is actively
+used by several projects. This library is being [fuzz-tested](https://github.com/klauspost/compress-fuzz) for all updates.
+
+There may still be specific combinations of data types/size/settings that could lead to edge cases,
+so as always, testing is recommended.
+
+For now, a high speed (fastest) and medium-fast (default) compressor has been implemented.
+
+* The "Fastest" compression ratio is roughly equivalent to zstd level 1.
+* The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
+* The "Better" compression ratio is roughly equivalent to zstd level 7.
+* The "Best" compression ratio is roughly equivalent to zstd level 11.
+
+In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode.
+The compression ratio compared to stdlib is around level 3, but usually 3x as fast.
+
+
+### Usage
+
+An Encoder can be used for either compressing a stream via the
+`io.WriteCloser` interface supported by the Encoder or as multiple independent
+tasks via the `EncodeAll` function.
+Smaller encodes are encouraged to use the EncodeAll function.
+Use `NewWriter` to create a new instance that can be used for both.
+
+To create a writer with default options, do like this:
+
+```Go
+// Compress input to output.
+func Compress(in io.Reader, out io.Writer) error {
+ enc, err := zstd.NewWriter(out)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(enc, in)
+ if err != nil {
+ enc.Close()
+ return err
+ }
+ return enc.Close()
+}
+```
+
+Now you can encode by writing data to `enc`. The output will be finished writing when `Close()` is called.
+Even if your encode fails, you should still call `Close()` to release any resources that may be held up.
+
+The above is fine for big encodes. However, whenever possible try to *reuse* the writer.
+
+To reuse the encoder, you can use the `Reset(io.Writer)` function to change to another output.
+This will allow the encoder to reuse all resources and avoid wasteful allocations.
+
+Currently stream encoding has 'light' concurrency, meaning up to 2 goroutines can be working on part
+of a stream. This is independent of the `WithEncoderConcurrency(n)`, but that is likely to change
+in the future. So if you want to limit concurrency for future updates, specify the concurrency
+you would like.
+
+If you would like stream encoding to be done without spawning async goroutines, use `WithEncoderConcurrency(1)`
+which will compress input as each block is completed, blocking on writes until each has completed.
+
+You can specify your desired compression level using `WithEncoderLevel()` option. Currently only pre-defined
+compression settings can be specified.
+
+#### Future Compatibility Guarantees
+
+This will be an evolving project. When using this package it is important to note that both the compression efficiency and speed may change.
+
+The goal will be to keep the default efficiency at the default zstd (level 3).
+However the encoding should never be assumed to remain the same,
+and you should not use hashes of compressed output for similarity checks.
+
+The Encoder can be assumed to produce the same output from the exact same code version.
+However, the may be modes in the future that break this,
+although they will not be enabled without an explicit option.
+
+This encoder is not designed to (and will probably never) output the exact same bitstream as the reference encoder.
+
+Also note, that the cgo decompressor currently does not [report all errors on invalid input](https://github.com/DataDog/zstd/issues/59),
+[omits error checks](https://github.com/DataDog/zstd/issues/61), [ignores checksums](https://github.com/DataDog/zstd/issues/43)
+and seems to ignore concatenated streams, even though [it is part of the spec](https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frames).
+
+#### Blocks
+
+For compressing small blocks, the returned encoder has a function called `EncodeAll(src, dst []byte) []byte`.
+
+`EncodeAll` will encode all input in src and append it to dst.
+This function can be called concurrently.
+Each call will only run on a same goroutine as the caller.
+
+Encoded blocks can be concatenated and the result will be the combined input stream.
+Data compressed with EncodeAll can be decoded with the Decoder, using either a stream or `DecodeAll`.
+
+Especially when encoding blocks you should take special care to reuse the encoder.
+This will effectively make it run without allocations after a warmup period.
+To make it run completely without allocations, supply a destination buffer with space for all content.
+
+```Go
+import "github.com/klauspost/compress/zstd"
+
+// Create a writer that caches compressors.
+// For this operation type we supply a nil Reader.
+var encoder, _ = zstd.NewWriter(nil)
+
+// Compress a buffer.
+// If you have a destination buffer, the allocation in the call can also be eliminated.
+func Compress(src []byte) []byte {
+ return encoder.EncodeAll(src, make([]byte, 0, len(src)))
+}
+```
+
+You can control the maximum number of concurrent encodes using the `WithEncoderConcurrency(n)`
+option when creating the writer.
+
+Using the Encoder for both a stream and individual blocks concurrently is safe.
+
+### Performance
+
+I have collected some speed examples to compare speed and compression against other compressors.
+
+* `file` is the input file.
+* `out` is the compressor used. `zskp` is this package. `zstd` is the Datadog cgo library. `gzstd/gzkp` is gzip standard and this library.
+* `level` is the compression level used. For `zskp` level 1 is "fastest", level 2 is "default"; 3 is "better", 4 is "best".
+* `insize`/`outsize` is the input/output size.
+* `millis` is the number of milliseconds used for compression.
+* `mb/s` is megabytes (2^20 bytes) per second.
+
+```
+Silesia Corpus:
+http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip
+
+This package:
+file out level insize outsize millis mb/s
+silesia.tar zskp 1 211947520 73821326 634 318.47
+silesia.tar zskp 2 211947520 67655404 1508 133.96
+silesia.tar zskp 3 211947520 64746933 3000 67.37
+silesia.tar zskp 4 211947520 60073508 16926 11.94
+
+cgo zstd:
+silesia.tar zstd 1 211947520 73605392 543 371.56
+silesia.tar zstd 3 211947520 66793289 864 233.68
+silesia.tar zstd 6 211947520 62916450 1913 105.66
+silesia.tar zstd 9 211947520 60212393 5063 39.92
+
+gzip, stdlib/this package:
+silesia.tar gzstd 1 211947520 80007735 1498 134.87
+silesia.tar gzkp 1 211947520 80088272 1009 200.31
+
+GOB stream of binary data. Highly compressible.
+https://files.klauspost.com/compress/gob-stream.7z
+
+file out level insize outsize millis mb/s
+gob-stream zskp 1 1911399616 233948096 3230 564.34
+gob-stream zskp 2 1911399616 203997694 4997 364.73
+gob-stream zskp 3 1911399616 173526523 13435 135.68
+gob-stream zskp 4 1911399616 162195235 47559 38.33
+
+gob-stream zstd 1 1911399616 249810424 2637 691.26
+gob-stream zstd 3 1911399616 208192146 3490 522.31
+gob-stream zstd 6 1911399616 193632038 6687 272.56
+gob-stream zstd 9 1911399616 177620386 16175 112.70
+
+gob-stream gzstd 1 1911399616 357382013 9046 201.49
+gob-stream gzkp 1 1911399616 359136669 4885 373.08
+
+The test data for the Large Text Compression Benchmark is the first
+10^9 bytes of the English Wikipedia dump on Mar. 3, 2006.
+http://mattmahoney.net/dc/textdata.html
+
+file out level insize outsize millis mb/s
+enwik9 zskp 1 1000000000 343833605 3687 258.64
+enwik9 zskp 2 1000000000 317001237 7672 124.29
+enwik9 zskp 3 1000000000 291915823 15923 59.89
+enwik9 zskp 4 1000000000 261710291 77697 12.27
+
+enwik9 zstd 1 1000000000 358072021 3110 306.65
+enwik9 zstd 3 1000000000 313734672 4784 199.35
+enwik9 zstd 6 1000000000 295138875 10290 92.68
+enwik9 zstd 9 1000000000 278348700 28549 33.40
+
+enwik9 gzstd 1 1000000000 382578136 8608 110.78
+enwik9 gzkp 1 1000000000 382781160 5628 169.45
+
+Highly compressible JSON file.
+https://files.klauspost.com/compress/github-june-2days-2019.json.zst
+
+file out level insize outsize millis mb/s
+github-june-2days-2019.json zskp 1 6273951764 697439532 9789 611.17
+github-june-2days-2019.json zskp 2 6273951764 610876538 18553 322.49
+github-june-2days-2019.json zskp 3 6273951764 517662858 44186 135.41
+github-june-2days-2019.json zskp 4 6273951764 464617114 165373 36.18
+
+github-june-2days-2019.json zstd 1 6273951764 766284037 8450 708.00
+github-june-2days-2019.json zstd 3 6273951764 661889476 10927 547.57
+github-june-2days-2019.json zstd 6 6273951764 642756859 22996 260.18
+github-june-2days-2019.json zstd 9 6273951764 601974523 52413 114.16
+
+github-june-2days-2019.json gzstd 1 6273951764 1164397768 26793 223.32
+github-june-2days-2019.json gzkp 1 6273951764 1120631856 17693 338.16
+
+VM Image, Linux mint with a few installed applications:
+https://files.klauspost.com/compress/rawstudio-mint14.7z
+
+file out level insize outsize millis mb/s
+rawstudio-mint14.tar zskp 1 8558382592 3718400221 18206 448.29
+rawstudio-mint14.tar zskp 2 8558382592 3326118337 37074 220.15
+rawstudio-mint14.tar zskp 3 8558382592 3163842361 87306 93.49
+rawstudio-mint14.tar zskp 4 8558382592 2970480650 783862 10.41
+
+rawstudio-mint14.tar zstd 1 8558382592 3609250104 17136 476.27
+rawstudio-mint14.tar zstd 3 8558382592 3341679997 29262 278.92
+rawstudio-mint14.tar zstd 6 8558382592 3235846406 77904 104.77
+rawstudio-mint14.tar zstd 9 8558382592 3160778861 140946 57.91
+
+rawstudio-mint14.tar gzstd 1 8558382592 3926234992 51345 158.96
+rawstudio-mint14.tar gzkp 1 8558382592 3960117298 36722 222.26
+
+CSV data:
+https://files.klauspost.com/compress/nyc-taxi-data-10M.csv.zst
+
+file out level insize outsize millis mb/s
+nyc-taxi-data-10M.csv zskp 1 3325605752 641319332 9462 335.17
+nyc-taxi-data-10M.csv zskp 2 3325605752 588976126 17570 180.50
+nyc-taxi-data-10M.csv zskp 3 3325605752 529329260 32432 97.79
+nyc-taxi-data-10M.csv zskp 4 3325605752 474949772 138025 22.98
+
+nyc-taxi-data-10M.csv zstd 1 3325605752 687399637 8233 385.18
+nyc-taxi-data-10M.csv zstd 3 3325605752 598514411 10065 315.07
+nyc-taxi-data-10M.csv zstd 6 3325605752 570522953 20038 158.27
+nyc-taxi-data-10M.csv zstd 9 3325605752 517554797 64565 49.12
+
+nyc-taxi-data-10M.csv gzstd 1 3325605752 928654908 21270 149.11
+nyc-taxi-data-10M.csv gzkp 1 3325605752 922273214 13929 227.68
+```
+
+## Decompressor
+
+Status: STABLE - there may still be subtle bugs, but a wide variety of content has been tested.
+
+This library is being continuously [fuzz-tested](https://github.com/klauspost/compress-fuzz),
+kindly supplied by [fuzzit.dev](https://fuzzit.dev/).
+The main purpose of the fuzz testing is to ensure that it is not possible to crash the decoder,
+or run it past its limits with ANY input provided.
+
+### Usage
+
+The package has been designed for two main usages, big streams of data and smaller in-memory buffers.
+There are two main usages of the package for these. Both of them are accessed by creating a `Decoder`.
+
+For streaming use a simple setup could look like this:
+
+```Go
+import "github.com/klauspost/compress/zstd"
+
+func Decompress(in io.Reader, out io.Writer) error {
+ d, err := zstd.NewReader(in)
+ if err != nil {
+ return err
+ }
+ defer d.Close()
+
+ // Copy content...
+ _, err = io.Copy(out, d)
+ return err
+}
+```
+
+It is important to use the "Close" function when you no longer need the Reader to stop running goroutines,
+when running with default settings.
+Goroutines will exit once an error has been returned, including `io.EOF` at the end of a stream.
+
+Streams are decoded concurrently in 4 asynchronous stages to give the best possible throughput.
+However, if you prefer synchronous decompression, use `WithDecoderConcurrency(1)` which will decompress data
+as it is being requested only.
+
+For decoding buffers, it could look something like this:
+
+```Go
+import "github.com/klauspost/compress/zstd"
+
+// Create a reader that caches decompressors.
+// For this operation type we supply a nil Reader.
+var decoder, _ = zstd.NewReader(nil, zstd.WithDecoderConcurrency(0))
+
+// Decompress a buffer. We don't supply a destination buffer,
+// so it will be allocated by the decoder.
+func Decompress(src []byte) ([]byte, error) {
+ return decoder.DecodeAll(src, nil)
+}
+```
+
+Both of these cases should provide the functionality needed.
+The decoder can be used for *concurrent* decompression of multiple buffers.
+By default 4 decompressors will be created.
+
+It will only allow a certain number of concurrent operations to run.
+To tweak that yourself use the `WithDecoderConcurrency(n)` option when creating the decoder.
+It is possible to use `WithDecoderConcurrency(0)` to create GOMAXPROCS decoders.
+
+### Dictionaries
+
+Data compressed with [dictionaries](https://github.com/facebook/zstd#the-case-for-small-data-compression) can be decompressed.
+
+Dictionaries are added individually to Decoders.
+Dictionaries are generated by the `zstd --train` command and contains an initial state for the decoder.
+To add a dictionary use the `WithDecoderDicts(dicts ...[]byte)` option with the dictionary data.
+Several dictionaries can be added at once.
+
+The dictionary will be used automatically for the data that specifies them.
+A re-used Decoder will still contain the dictionaries registered.
+
+When registering multiple dictionaries with the same ID, the last one will be used.
+
+It is possible to use dictionaries when compressing data.
+
+To enable a dictionary use `WithEncoderDict(dict []byte)`. Here only one dictionary will be used
+and it will likely be used even if it doesn't improve compression.
+
+The used dictionary must be used to decompress the content.
+
+For any real gains, the dictionary should be built with similar data.
+If an unsuitable dictionary is used the output may be slightly larger than using no dictionary.
+Use the [zstd commandline tool](https://github.com/facebook/zstd/releases) to build a dictionary from sample data.
+For information see [zstd dictionary information](https://github.com/facebook/zstd#the-case-for-small-data-compression).
+
+For now there is a fixed startup performance penalty for compressing content with dictionaries.
+This will likely be improved over time. Just be aware to test performance when implementing.
+
+### Allocation-less operation
+
+The decoder has been designed to operate without allocations after a warmup.
+
+This means that you should *store* the decoder for best performance.
+To re-use a stream decoder, use the `Reset(r io.Reader) error` to switch to another stream.
+A decoder can safely be re-used even if the previous stream failed.
+
+To release the resources, you must call the `Close()` function on a decoder.
+After this it can *no longer be reused*, but all running goroutines will be stopped.
+So you *must* use this if you will no longer need the Reader.
+
+For decompressing smaller buffers a single decoder can be used.
+When decoding buffers, you can supply a destination slice with length 0 and your expected capacity.
+In this case no unneeded allocations should be made.
+
+### Concurrency
+
+The buffer decoder does everything on the same goroutine and does nothing concurrently.
+It can however decode several buffers concurrently. Use `WithDecoderConcurrency(n)` to limit that.
+
+The stream decoder will create goroutines that:
+
+1) Reads input and splits the input into blocks.
+2) Decompression of literals.
+3) Decompression of sequences.
+4) Reconstruction of output stream.
+
+So effectively this also means the decoder will "read ahead" and prepare data to always be available for output.
+
+The concurrency level will, for streams, determine how many blocks ahead the compression will start.
+
+Since "blocks" are quite dependent on the output of the previous block stream decoding will only have limited concurrency.
+
+In practice this means that concurrency is often limited to utilizing about 3 cores effectively.
+
+### Benchmarks
+
+The first two are streaming decodes and the last are smaller inputs.
+
+Running on AMD Ryzen 9 3950X 16-Core Processor. AMD64 assembly used.
+
+```
+BenchmarkDecoderSilesia-32 5 206878840 ns/op 1024.50 MB/s 49808 B/op 43 allocs/op
+BenchmarkDecoderEnwik9-32 1 1271809000 ns/op 786.28 MB/s 72048 B/op 52 allocs/op
+
+Concurrent blocks, performance:
+
+BenchmarkDecoder_DecodeAllParallel/kppkn.gtb.zst-32 67356 17857 ns/op 10321.96 MB/s 22.48 pct 102 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/geo.protodata.zst-32 266656 4421 ns/op 26823.21 MB/s 11.89 pct 19 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/plrabn12.txt.zst-32 20992 56842 ns/op 8477.17 MB/s 39.90 pct 754 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/lcet10.txt.zst-32 27456 43932 ns/op 9714.01 MB/s 33.27 pct 524 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/asyoulik.txt.zst-32 78432 15047 ns/op 8319.15 MB/s 40.34 pct 66 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/alice29.txt.zst-32 65800 18436 ns/op 8249.63 MB/s 37.75 pct 88 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/html_x_4.zst-32 102993 11523 ns/op 35546.09 MB/s 3.637 pct 143 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/paper-100k.pdf.zst-32 1000000 1070 ns/op 95720.98 MB/s 80.53 pct 3 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/fireworks.jpeg.zst-32 749802 1752 ns/op 70272.35 MB/s 100.0 pct 5 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/urls.10K.zst-32 22640 52934 ns/op 13263.37 MB/s 26.25 pct 1014 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/html.zst-32 226412 5232 ns/op 19572.27 MB/s 14.49 pct 20 B/op 0 allocs/op
+BenchmarkDecoder_DecodeAllParallel/comp-data.bin.zst-32 923041 1276 ns/op 3194.71 MB/s 31.26 pct 0 B/op 0 allocs/op
+```
+
+This reflects the performance around May 2022, but this may be out of date.
+
+## Zstd inside ZIP files
+
+It is possible to use zstandard to compress individual files inside zip archives.
+While this isn't widely supported it can be useful for internal files.
+
+To support the compression and decompression of these files you must register a compressor and decompressor.
+
+It is highly recommended registering the (de)compressors on individual zip Reader/Writer and NOT
+use the global registration functions. The main reason for this is that 2 registrations from
+different packages will result in a panic.
+
+It is a good idea to only have a single compressor and decompressor, since they can be used for multiple zip
+files concurrently, and using a single instance will allow reusing some resources.
+
+See [this example](https://pkg.go.dev/github.com/klauspost/compress/zstd#example-ZipCompressor) for
+how to compress and decompress files inside zip archives.
+
+# Contributions
+
+Contributions are always welcome.
+For new features/fixes, remember to add tests and for performance enhancements include benchmarks.
+
+For general feedback and experience reports, feel free to open an issue or write me on [Twitter](https://twitter.com/sh0dan).
+
+This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare.
diff --git a/vendor/github.com/klauspost/compress/zstd/bitreader.go b/vendor/github.com/klauspost/compress/zstd/bitreader.go
new file mode 100644
index 00000000..d41e3e17
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bitreader.go
@@ -0,0 +1,135 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "math/bits"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+// bitReader reads a bitstream in reverse.
+// The last set bit indicates the start of the stream and is used
+// for aligning the input.
+type bitReader struct {
+ in []byte
+ value uint64 // Maybe use [16]byte, but shifting is awkward.
+ cursor int // offset where next read should end
+ bitsRead uint8
+}
+
+// init initializes and resets the bit reader.
+func (b *bitReader) init(in []byte) error {
+ if len(in) < 1 {
+ return errors.New("corrupt stream: too short")
+ }
+ b.in = in
+ // The highest bit of the last byte indicates where to start
+ v := in[len(in)-1]
+ if v == 0 {
+ return errors.New("corrupt stream, did not find end of stream")
+ }
+ b.cursor = len(in)
+ b.bitsRead = 64
+ b.value = 0
+ if len(in) >= 8 {
+ b.fillFastStart()
+ } else {
+ b.fill()
+ b.fill()
+ }
+ b.bitsRead += 8 - uint8(highBits(uint32(v)))
+ return nil
+}
+
+// getBits will return n bits. n can be 0.
+func (b *bitReader) getBits(n uint8) int {
+ if n == 0 /*|| b.bitsRead >= 64 */ {
+ return 0
+ }
+ return int(b.get32BitsFast(n))
+}
+
+// get32BitsFast requires that at least one bit is requested every time.
+// There are no checks if the buffer is filled.
+func (b *bitReader) get32BitsFast(n uint8) uint32 {
+ const regMask = 64 - 1
+ v := uint32((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask))
+ b.bitsRead += n
+ return v
+}
+
+// fillFast() will make sure at least 32 bits are available.
+// There must be at least 4 bytes available.
+func (b *bitReader) fillFast() {
+ if b.bitsRead < 32 {
+ return
+ }
+ b.cursor -= 4
+ b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor))
+ b.bitsRead -= 32
+}
+
+// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read.
+func (b *bitReader) fillFastStart() {
+ b.cursor -= 8
+ b.value = le.Load64(b.in, b.cursor)
+ b.bitsRead = 0
+}
+
+// fill() will make sure at least 32 bits are available.
+func (b *bitReader) fill() {
+ if b.bitsRead < 32 {
+ return
+ }
+ if b.cursor >= 4 {
+ b.cursor -= 4
+ b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor))
+ b.bitsRead -= 32
+ return
+ }
+
+ b.bitsRead -= uint8(8 * b.cursor)
+ for b.cursor > 0 {
+ b.cursor -= 1
+ b.value = (b.value << 8) | uint64(b.in[b.cursor])
+ }
+}
+
+// finished returns true if all bits have been read from the bit stream.
+func (b *bitReader) finished() bool {
+ return b.cursor == 0 && b.bitsRead >= 64
+}
+
+// overread returns true if more bits have been requested than is on the stream.
+func (b *bitReader) overread() bool {
+ return b.bitsRead > 64
+}
+
+// remain returns the number of bits remaining.
+func (b *bitReader) remain() uint {
+ return 8*uint(b.cursor) + 64 - uint(b.bitsRead)
+}
+
+// close the bitstream and returns an error if out-of-buffer reads occurred.
+func (b *bitReader) close() error {
+ // Release reference.
+ b.in = nil
+ b.cursor = 0
+ if !b.finished() {
+ return fmt.Errorf("%d extra bits on block, should be 0", b.remain())
+ }
+ if b.bitsRead > 64 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
+func highBits(val uint32) (n uint32) {
+ return uint32(bits.Len32(val) - 1)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/bitwriter.go b/vendor/github.com/klauspost/compress/zstd/bitwriter.go
new file mode 100644
index 00000000..b22b297e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bitwriter.go
@@ -0,0 +1,112 @@
+// Copyright 2018 Klaus Post. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Based on work Copyright (c) 2013, Yann Collet, released under BSD License.
+
+package zstd
+
+// bitWriter will write bits.
+// First bit will be LSB of the first byte of output.
+type bitWriter struct {
+ bitContainer uint64
+ nBits uint8
+ out []byte
+}
+
+// bitMask16 is bitmasks. Has extra to avoid bounds check.
+var bitMask16 = [32]uint16{
+ 0, 1, 3, 7, 0xF, 0x1F,
+ 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF} /* up to 16 bits */
+
+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
+
+// addBits16NC will add up to 16 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16NC(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits32NC will add up to 31 bits.
+// It will not check if there is space for them,
+// so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits32NC(value uint32, bits uint8) {
+ b.bitContainer |= uint64(value&bitMask32[bits&31]) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits64NC will add up to 64 bits.
+// There must be space for 32 bits.
+func (b *bitWriter) addBits64NC(value uint64, bits uint8) {
+ if bits <= 31 {
+ b.addBits32Clean(uint32(value), bits)
+ return
+ }
+ b.addBits32Clean(uint32(value), 32)
+ b.flush32()
+ b.addBits32Clean(uint32(value>>32), bits-32)
+}
+
+// addBits32Clean will add up to 32 bits.
+// It will not check if there is space for them.
+// The input must not contain more bits than specified.
+func (b *bitWriter) addBits32Clean(value uint32, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
+ b.bitContainer |= uint64(value) << (b.nBits & 63)
+ b.nBits += bits
+}
+
+// flush32 will flush out, so there are at least 32 bits available for writing.
+func (b *bitWriter) flush32() {
+ if b.nBits < 32 {
+ return
+ }
+ b.out = append(b.out,
+ byte(b.bitContainer),
+ byte(b.bitContainer>>8),
+ byte(b.bitContainer>>16),
+ byte(b.bitContainer>>24))
+ b.nBits -= 32
+ b.bitContainer >>= 32
+}
+
+// flushAlign will flush remaining full bytes and align to next byte boundary.
+func (b *bitWriter) flushAlign() {
+ nbBytes := (b.nBits + 7) >> 3
+ for i := range nbBytes {
+ b.out = append(b.out, byte(b.bitContainer>>(i*8)))
+ }
+ b.nBits = 0
+ b.bitContainer = 0
+}
+
+// close will write the alignment bit and write the final byte(s)
+// to the output.
+func (b *bitWriter) close() {
+ // End mark
+ b.addBits16Clean(1, 1)
+ // flush until next byte.
+ b.flushAlign()
+}
+
+// reset and continue writing by appending to out.
+func (b *bitWriter) reset(out []byte) {
+ b.bitContainer = 0
+ b.nBits = 0
+ b.out = out
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
new file mode 100644
index 00000000..2329e996
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -0,0 +1,712 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "hash/crc32"
+ "io"
+ "sync"
+
+ "github.com/klauspost/compress/huff0"
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+type blockType uint8
+
+//go:generate stringer -type=blockType,literalsBlockType,seqCompMode,tableIndex
+
+const (
+ blockTypeRaw blockType = iota
+ blockTypeRLE
+ blockTypeCompressed
+ blockTypeReserved
+)
+
+type literalsBlockType uint8
+
+const (
+ literalsBlockRaw literalsBlockType = iota
+ literalsBlockRLE
+ literalsBlockCompressed
+ literalsBlockTreeless
+)
+
+const (
+ // maxCompressedBlockSize is the biggest allowed compressed block size (128KB)
+ maxCompressedBlockSize = 128 << 10
+
+ compressedBlockOverAlloc = 16
+ maxCompressedBlockSizeAlloc = 128<<10 + compressedBlockOverAlloc
+
+ // Maximum possible block size (all Raw+Uncompressed).
+ maxBlockSize = (1 << 21) - 1
+
+ maxMatchLen = 131074
+ maxSequences = 0x7f00 + 0xffff
+
+ // We support slightly less than the reference decoder to be able to
+ // use ints on 32 bit archs.
+ maxOffsetBits = 30
+)
+
+var (
+ huffDecoderPool = sync.Pool{New: func() any {
+ return &huff0.Scratch{}
+ }}
+
+ fseDecoderPool = sync.Pool{New: func() any {
+ return &fseDecoder{}
+ }}
+)
+
+type blockDec struct {
+ // Raw source data of the block.
+ data []byte
+ dataStorage []byte
+
+ // Destination of the decoded data.
+ dst []byte
+
+ // Buffer for literals data.
+ literalBuf []byte
+
+ // Window size of the block.
+ WindowSize uint64
+
+ err error
+
+ // Check against this crc, if hasCRC is true.
+ checkCRC uint32
+ hasCRC bool
+
+ // Frame to use for singlethreaded decoding.
+ // Should not be used by the decoder itself since parent may be another frame.
+ localFrame *frameDec
+
+ sequence []seqVals
+
+ async struct {
+ newHist *history
+ literals []byte
+ seqData []byte
+ seqSize int // Size of uncompressed sequences
+ fcs uint64
+ }
+
+ // Block is RLE, this is the size.
+ RLESize uint32
+
+ Type blockType
+
+ // Is this the last block of a frame?
+ Last bool
+
+ // Use less memory
+ lowMem bool
+}
+
+func (b *blockDec) String() string {
+ if b == nil {
+ return ""
+ }
+ return fmt.Sprintf("Steam Size: %d, Type: %v, Last: %t, Window: %d", len(b.data), b.Type, b.Last, b.WindowSize)
+}
+
+func newBlockDec(lowMem bool) *blockDec {
+ b := blockDec{
+ lowMem: lowMem,
+ }
+ return &b
+}
+
+// reset will reset the block.
+// Input must be a start of a block and will be at the end of the block when returned.
+func (b *blockDec) reset(br byteBuffer, windowSize uint64) error {
+ b.WindowSize = windowSize
+ tmp, err := br.readSmall(3)
+ if err != nil {
+ println("Reading block header:", err)
+ return err
+ }
+ bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16)
+ b.Last = bh&1 != 0
+ b.Type = blockType((bh >> 1) & 3)
+ // find size.
+ cSize := int(bh >> 3)
+ maxSize := maxCompressedBlockSizeAlloc
+ switch b.Type {
+ case blockTypeReserved:
+ return ErrReservedBlockType
+ case blockTypeRLE:
+ if cSize > maxCompressedBlockSize || cSize > int(b.WindowSize) {
+ if debugDecoder {
+ printf("rle block too big: csize:%d block: %+v\n", uint64(cSize), b)
+ }
+ return ErrWindowSizeExceeded
+ }
+ b.RLESize = uint32(cSize)
+ if b.lowMem {
+ maxSize = cSize
+ }
+ cSize = 1
+ case blockTypeCompressed:
+ if debugDecoder {
+ println("Data size on stream:", cSize)
+ }
+ b.RLESize = 0
+ maxSize = maxCompressedBlockSizeAlloc
+ if windowSize < maxCompressedBlockSize && b.lowMem {
+ maxSize = int(windowSize) + compressedBlockOverAlloc
+ }
+ if cSize > maxCompressedBlockSize || uint64(cSize) > b.WindowSize {
+ if debugDecoder {
+ printf("compressed block too big: csize:%d block: %+v\n", uint64(cSize), b)
+ }
+ return ErrCompressedSizeTooBig
+ }
+ // Empty compressed blocks must at least be 2 bytes
+ // for Literals_Block_Type and one for Sequences_Section_Header.
+ if cSize < 2 {
+ return ErrBlockTooSmall
+ }
+ case blockTypeRaw:
+ if cSize > maxCompressedBlockSize || cSize > int(b.WindowSize) {
+ if debugDecoder {
+ printf("rle block too big: csize:%d block: %+v\n", uint64(cSize), b)
+ }
+ return ErrWindowSizeExceeded
+ }
+
+ b.RLESize = 0
+ // We do not need a destination for raw blocks.
+ maxSize = -1
+ default:
+ panic("Invalid block type")
+ }
+
+ // Read block data.
+ if _, ok := br.(*byteBuf); !ok && cap(b.dataStorage) < cSize {
+ // byteBuf doesn't need a destination buffer.
+ if b.lowMem || cSize > maxCompressedBlockSize {
+ b.dataStorage = make([]byte, 0, cSize+compressedBlockOverAlloc)
+ } else {
+ b.dataStorage = make([]byte, 0, maxCompressedBlockSizeAlloc)
+ }
+ }
+ b.data, err = br.readBig(cSize, b.dataStorage)
+ if err != nil {
+ if debugDecoder {
+ println("Reading block:", err, "(", cSize, ")", len(b.data))
+ printf("%T", br)
+ }
+ return err
+ }
+ if cap(b.dst) <= maxSize {
+ b.dst = make([]byte, 0, maxSize+1)
+ }
+ return nil
+}
+
+// sendEOF will make the decoder send EOF on this frame.
+func (b *blockDec) sendErr(err error) {
+ b.Last = true
+ b.Type = blockTypeReserved
+ b.err = err
+}
+
+// Close will release resources.
+// Closed blockDec cannot be reset.
+func (b *blockDec) Close() {
+}
+
+// decodeBuf
+func (b *blockDec) decodeBuf(hist *history) error {
+ switch b.Type {
+ case blockTypeRLE:
+ if cap(b.dst) < int(b.RLESize) {
+ if b.lowMem {
+ b.dst = make([]byte, b.RLESize)
+ } else {
+ b.dst = make([]byte, maxCompressedBlockSize)
+ }
+ }
+ b.dst = b.dst[:b.RLESize]
+ v := b.data[0]
+ for i := range b.dst {
+ b.dst[i] = v
+ }
+ hist.appendKeep(b.dst)
+ return nil
+ case blockTypeRaw:
+ hist.appendKeep(b.data)
+ return nil
+ case blockTypeCompressed:
+ saved := b.dst
+ // Append directly to history
+ if hist.ignoreBuffer == 0 {
+ b.dst = hist.b
+ hist.b = nil
+ } else {
+ b.dst = b.dst[:0]
+ }
+ err := b.decodeCompressed(hist)
+ if debugDecoder {
+ println("Decompressed to total", len(b.dst), "bytes, hash:", xxhash.Sum64(b.dst), "error:", err)
+ }
+ if hist.ignoreBuffer == 0 {
+ hist.b = b.dst
+ b.dst = saved
+ } else {
+ hist.appendKeep(b.dst)
+ }
+ return err
+ case blockTypeReserved:
+ // Used for returning errors.
+ return b.err
+ default:
+ panic("Invalid block type")
+ }
+}
+
+func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err error) {
+ // There must be at least one byte for Literals_Block_Type and one for Sequences_Section_Header
+ if len(in) < 2 {
+ return in, ErrBlockTooSmall
+ }
+
+ litType := literalsBlockType(in[0] & 3)
+ var litRegenSize int
+ var litCompSize int
+ sizeFormat := (in[0] >> 2) & 3
+ var fourStreams bool
+ var literals []byte
+ switch litType {
+ case literalsBlockRaw, literalsBlockRLE:
+ switch sizeFormat {
+ case 0, 2:
+ // Regenerated_Size uses 5 bits (0-31). Literals_Section_Header uses 1 byte.
+ litRegenSize = int(in[0] >> 3)
+ in = in[1:]
+ case 1:
+ // Regenerated_Size uses 12 bits (0-4095). Literals_Section_Header uses 2 bytes.
+ litRegenSize = int(in[0]>>4) + (int(in[1]) << 4)
+ in = in[2:]
+ case 3:
+ // Regenerated_Size uses 20 bits (0-1048575). Literals_Section_Header uses 3 bytes.
+ if len(in) < 3 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ litRegenSize = int(in[0]>>4) + (int(in[1]) << 4) + (int(in[2]) << 12)
+ in = in[3:]
+ }
+ case literalsBlockCompressed, literalsBlockTreeless:
+ switch sizeFormat {
+ case 0, 1:
+ // Both Regenerated_Size and Compressed_Size use 10 bits (0-1023).
+ if len(in) < 3 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12)
+ litRegenSize = int(n & 1023)
+ litCompSize = int(n >> 10)
+ fourStreams = sizeFormat == 1
+ in = in[3:]
+ case 2:
+ fourStreams = true
+ if len(in) < 4 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12) + (uint64(in[3]) << 20)
+ litRegenSize = int(n & 16383)
+ litCompSize = int(n >> 14)
+ in = in[4:]
+ case 3:
+ fourStreams = true
+ if len(in) < 5 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in))
+ return in, ErrBlockTooSmall
+ }
+ n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12) + (uint64(in[3]) << 20) + (uint64(in[4]) << 28)
+ litRegenSize = int(n & 262143)
+ litCompSize = int(n >> 18)
+ in = in[5:]
+ }
+ }
+ if debugDecoder {
+ println("literals type:", litType, "litRegenSize:", litRegenSize, "litCompSize:", litCompSize, "sizeFormat:", sizeFormat, "4X:", fourStreams)
+ }
+ if litRegenSize > int(b.WindowSize) || litRegenSize > maxCompressedBlockSize {
+ return in, ErrWindowSizeExceeded
+ }
+
+ switch litType {
+ case literalsBlockRaw:
+ if len(in) < litRegenSize {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litRegenSize)
+ return in, ErrBlockTooSmall
+ }
+ literals = in[:litRegenSize]
+ in = in[litRegenSize:]
+ //printf("Found %d uncompressed literals\n", litRegenSize)
+ case literalsBlockRLE:
+ if len(in) < 1 {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", 1)
+ return in, ErrBlockTooSmall
+ }
+ if cap(b.literalBuf) < litRegenSize {
+ if b.lowMem {
+ b.literalBuf = make([]byte, litRegenSize, litRegenSize+compressedBlockOverAlloc)
+ } else {
+ b.literalBuf = make([]byte, litRegenSize, maxCompressedBlockSize+compressedBlockOverAlloc)
+ }
+ }
+ literals = b.literalBuf[:litRegenSize]
+ v := in[0]
+ for i := range literals {
+ literals[i] = v
+ }
+ in = in[1:]
+ if debugDecoder {
+ printf("Found %d RLE compressed literals\n", litRegenSize)
+ }
+ case literalsBlockTreeless:
+ if len(in) < litCompSize {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litCompSize)
+ return in, ErrBlockTooSmall
+ }
+ // Store compressed literals, so we defer decoding until we get history.
+ literals = in[:litCompSize]
+ in = in[litCompSize:]
+ if debugDecoder {
+ printf("Found %d compressed literals\n", litCompSize)
+ }
+ huff := hist.huffTree
+ if huff == nil {
+ return in, errors.New("literal block was treeless, but no history was defined")
+ }
+ // Ensure we have space to store it.
+ if cap(b.literalBuf) < litRegenSize {
+ if b.lowMem {
+ b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc)
+ } else {
+ b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc)
+ }
+ }
+ var err error
+ // Use our out buffer.
+ huff.MaxDecodedSize = litRegenSize
+ if fourStreams {
+ literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
+ } else {
+ literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals)
+ }
+ // Make sure we don't leak our literals buffer
+ if err != nil {
+ println("decompressing literals:", err)
+ return in, err
+ }
+ if len(literals) != litRegenSize {
+ return in, fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals))
+ }
+
+ case literalsBlockCompressed:
+ if len(in) < litCompSize {
+ println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litCompSize)
+ return in, ErrBlockTooSmall
+ }
+ literals = in[:litCompSize]
+ in = in[litCompSize:]
+ // Ensure we have space to store it.
+ if cap(b.literalBuf) < litRegenSize {
+ if b.lowMem {
+ b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc)
+ } else {
+ b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc)
+ }
+ }
+ huff := hist.huffTree
+ if huff == nil || (hist.dict != nil && huff == hist.dict.litEnc) {
+ huff = huffDecoderPool.Get().(*huff0.Scratch)
+ if huff == nil {
+ huff = &huff0.Scratch{}
+ }
+ }
+ var err error
+ if debugDecoder {
+ println("huff table input:", len(literals), "CRC:", crc32.ChecksumIEEE(literals))
+ }
+ huff, literals, err = huff0.ReadTable(literals, huff)
+ if err != nil {
+ println("reading huffman table:", err)
+ return in, err
+ }
+ hist.huffTree = huff
+ huff.MaxDecodedSize = litRegenSize
+ // Use our out buffer.
+ if fourStreams {
+ literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
+ } else {
+ literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals)
+ }
+ if err != nil {
+ println("decoding compressed literals:", err)
+ return in, err
+ }
+ // Make sure we don't leak our literals buffer
+ if len(literals) != litRegenSize {
+ return in, fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals))
+ }
+ // Re-cap to get extra size.
+ literals = b.literalBuf[:len(literals)]
+ if debugDecoder {
+ printf("Decompressed %d literals into %d bytes\n", litCompSize, litRegenSize)
+ }
+ }
+ hist.decoders.literals = literals
+ return in, nil
+}
+
+// decodeCompressed will start decompressing a block.
+func (b *blockDec) decodeCompressed(hist *history) error {
+ in := b.data
+ in, err := b.decodeLiterals(in, hist)
+ if err != nil {
+ return err
+ }
+ err = b.prepareSequences(in, hist)
+ if err != nil {
+ return err
+ }
+ if hist.decoders.nSeqs == 0 {
+ b.dst = append(b.dst, hist.decoders.literals...)
+ return nil
+ }
+ before := len(hist.decoders.out)
+ err = hist.decoders.decodeSync(hist.b[hist.ignoreBuffer:])
+ if err != nil {
+ return err
+ }
+ if hist.decoders.maxSyncLen > 0 {
+ hist.decoders.maxSyncLen += uint64(before)
+ hist.decoders.maxSyncLen -= uint64(len(hist.decoders.out))
+ }
+ b.dst = hist.decoders.out
+ hist.recentOffsets = hist.decoders.prevOffset
+ return nil
+}
+
+func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) {
+ if debugDecoder {
+ printf("prepareSequences: %d byte(s) input\n", len(in))
+ }
+ // Decode Sequences
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#sequences-section
+ if len(in) < 1 {
+ return ErrBlockTooSmall
+ }
+ var nSeqs int
+ seqHeader := in[0]
+ switch {
+ case seqHeader < 128:
+ nSeqs = int(seqHeader)
+ in = in[1:]
+ case seqHeader < 255:
+ if len(in) < 2 {
+ return ErrBlockTooSmall
+ }
+ nSeqs = int(seqHeader-128)<<8 | int(in[1])
+ in = in[2:]
+ case seqHeader == 255:
+ if len(in) < 3 {
+ return ErrBlockTooSmall
+ }
+ nSeqs = 0x7f00 + int(in[1]) + (int(in[2]) << 8)
+ in = in[3:]
+ }
+ if nSeqs == 0 && len(in) != 0 {
+ // When no sequences, there should not be any more data...
+ if debugDecoder {
+ printf("prepareSequences: 0 sequences, but %d byte(s) left on stream\n", len(in))
+ }
+ return ErrUnexpectedBlockSize
+ }
+
+ var seqs = &hist.decoders
+ seqs.nSeqs = nSeqs
+ if nSeqs > 0 {
+ if len(in) < 1 {
+ return ErrBlockTooSmall
+ }
+ br := byteReader{b: in, off: 0}
+ compMode := br.Uint8()
+ br.advance(1)
+ if debugDecoder {
+ printf("Compression modes: 0b%b", compMode)
+ }
+ if compMode&3 != 0 {
+ return errors.New("corrupt block: reserved bits not zero")
+ }
+ for i := range uint(3) {
+ mode := seqCompMode((compMode >> (6 - i*2)) & 3)
+ if debugDecoder {
+ println("Table", tableIndex(i), "is", mode)
+ }
+ var seq *sequenceDec
+ switch tableIndex(i) {
+ case tableLiteralLengths:
+ seq = &seqs.litLengths
+ case tableOffsets:
+ seq = &seqs.offsets
+ case tableMatchLengths:
+ seq = &seqs.matchLengths
+ default:
+ panic("unknown table")
+ }
+ switch mode {
+ case compModePredefined:
+ if seq.fse != nil && !seq.fse.preDefined {
+ fseDecoderPool.Put(seq.fse)
+ }
+ seq.fse = &fsePredef[i]
+ case compModeRLE:
+ if br.remain() < 1 {
+ return ErrBlockTooSmall
+ }
+ v := br.Uint8()
+ br.advance(1)
+ if seq.fse == nil || seq.fse.preDefined {
+ seq.fse = fseDecoderPool.Get().(*fseDecoder)
+ }
+ symb, err := decSymbolValue(v, symbolTableX[i])
+ if err != nil {
+ printf("RLE Transform table (%v) error: %v", tableIndex(i), err)
+ return err
+ }
+ seq.fse.setRLE(symb)
+ if debugDecoder {
+ printf("RLE set to 0x%x, code: %v", symb, v)
+ }
+ case compModeFSE:
+ if debugDecoder {
+ println("Reading table for", tableIndex(i))
+ }
+ if seq.fse == nil || seq.fse.preDefined {
+ seq.fse = fseDecoderPool.Get().(*fseDecoder)
+ }
+ err := seq.fse.readNCount(&br, uint16(maxTableSymbol[i]))
+ if err != nil {
+ println("Read table error:", err)
+ return err
+ }
+ err = seq.fse.transform(symbolTableX[i])
+ if err != nil {
+ println("Transform table error:", err)
+ return err
+ }
+ if debugDecoder {
+ println("Read table ok", "symbolLen:", seq.fse.symbolLen)
+ }
+ case compModeRepeat:
+ seq.repeat = true
+ }
+ if br.overread() {
+ return io.ErrUnexpectedEOF
+ }
+ }
+ in = br.unread()
+ }
+ if debugDecoder {
+ println("Literals:", len(seqs.literals), "hash:", xxhash.Sum64(seqs.literals), "and", seqs.nSeqs, "sequences.")
+ }
+
+ if nSeqs == 0 {
+ if len(b.sequence) > 0 {
+ b.sequence = b.sequence[:0]
+ }
+ return nil
+ }
+ br := seqs.br
+ if br == nil {
+ br = &bitReader{}
+ }
+ if err := br.init(in); err != nil {
+ return err
+ }
+
+ if err := seqs.initialize(br, hist, b.dst); err != nil {
+ println("initializing sequences:", err)
+ return err
+ }
+
+ return nil
+}
+
+func (b *blockDec) decodeSequences(hist *history) error {
+ if cap(b.sequence) < hist.decoders.nSeqs {
+ if b.lowMem {
+ b.sequence = make([]seqVals, 0, hist.decoders.nSeqs)
+ } else {
+ b.sequence = make([]seqVals, 0, 0x7F00+0xffff)
+ }
+ }
+ b.sequence = b.sequence[:hist.decoders.nSeqs]
+ if hist.decoders.nSeqs == 0 {
+ hist.decoders.seqSize = len(hist.decoders.literals)
+ return nil
+ }
+ hist.decoders.windowSize = hist.windowSize
+ hist.decoders.prevOffset = hist.recentOffsets
+
+ err := hist.decoders.decode(b.sequence)
+ hist.recentOffsets = hist.decoders.prevOffset
+ return err
+}
+
+func (b *blockDec) executeSequences(hist *history) error {
+ hbytes := hist.b
+ if len(hbytes) > hist.windowSize {
+ hbytes = hbytes[len(hbytes)-hist.windowSize:]
+ // We do not need history anymore.
+ if hist.dict != nil {
+ hist.dict.content = nil
+ }
+ }
+ hist.decoders.windowSize = hist.windowSize
+ hist.decoders.out = b.dst[:0]
+ err := hist.decoders.execute(b.sequence, hbytes)
+ if err != nil {
+ return err
+ }
+ return b.updateHistory(hist)
+}
+
+func (b *blockDec) updateHistory(hist *history) error {
+ if len(b.data) > maxCompressedBlockSize {
+ return fmt.Errorf("compressed block size too large (%d)", len(b.data))
+ }
+ // Set output and release references.
+ b.dst = hist.decoders.out
+ hist.recentOffsets = hist.decoders.prevOffset
+
+ if b.Last {
+ // if last block we don't care about history.
+ println("Last block, no history returned")
+ hist.b = hist.b[:0]
+ return nil
+ } else {
+ hist.append(b.dst)
+ if debugDecoder {
+ println("Finished block with ", len(b.sequence), "sequences. Added", len(b.dst), "to history, now length", len(hist.b))
+ }
+ }
+ hist.decoders.out, hist.decoders.literals = nil, nil
+
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go
new file mode 100644
index 00000000..0e33aea4
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go
@@ -0,0 +1,893 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "math/bits"
+ "slices"
+
+ "github.com/klauspost/compress/huff0"
+)
+
+type blockEnc struct {
+ size int
+ literals []byte
+ sequences []seq
+ coders seqCoders
+ litEnc *huff0.Scratch
+ dictLitEnc *huff0.Scratch
+ wr bitWriter
+
+ extraLits int
+ output []byte
+ recentOffsets [3]uint32
+ prevRecentOffsets [3]uint32
+
+ last bool
+ lowMem bool
+}
+
+// init should be used once the block has been created.
+// If called more than once, the effect is the same as calling reset.
+func (b *blockEnc) init() {
+ if b.lowMem {
+ // 1K literals
+ if cap(b.literals) < 1<<10 {
+ b.literals = make([]byte, 0, 1<<10)
+ }
+ const defSeqs = 20
+ if cap(b.sequences) < defSeqs {
+ b.sequences = make([]seq, 0, defSeqs)
+ }
+ // 1K
+ if cap(b.output) < 1<<10 {
+ b.output = make([]byte, 0, 1<<10)
+ }
+ } else {
+ if cap(b.literals) < maxCompressedBlockSize {
+ b.literals = make([]byte, 0, maxCompressedBlockSize)
+ }
+ const defSeqs = 2000
+ if cap(b.sequences) < defSeqs {
+ b.sequences = make([]seq, 0, defSeqs)
+ }
+ if cap(b.output) < maxCompressedBlockSize {
+ b.output = make([]byte, 0, maxCompressedBlockSize)
+ }
+ }
+
+ if b.coders.mlEnc == nil {
+ b.coders.mlEnc = &fseEncoder{}
+ b.coders.mlPrev = &fseEncoder{}
+ b.coders.ofEnc = &fseEncoder{}
+ b.coders.ofPrev = &fseEncoder{}
+ b.coders.llEnc = &fseEncoder{}
+ b.coders.llPrev = &fseEncoder{}
+ }
+ b.litEnc = &huff0.Scratch{WantLogLess: 4}
+ b.reset(nil)
+}
+
+// initNewEncode can be used to reset offsets and encoders to the initial state.
+func (b *blockEnc) initNewEncode() {
+ b.recentOffsets = [3]uint32{1, 4, 8}
+ b.litEnc.Reuse = huff0.ReusePolicyNone
+ b.coders.setPrev(nil, nil, nil)
+ b.dictLitEnc = nil
+}
+
+// reset will reset the block for a new encode, but in the same stream,
+// meaning that state will be carried over, but the block content is reset.
+// If a previous block is provided, the recent offsets are carried over.
+func (b *blockEnc) reset(prev *blockEnc) {
+ b.extraLits = 0
+ b.literals = b.literals[:0]
+ b.size = 0
+ b.sequences = b.sequences[:0]
+ b.output = b.output[:0]
+ b.last = false
+ if prev != nil {
+ b.recentOffsets = prev.prevRecentOffsets
+ }
+ b.dictLitEnc = nil
+}
+
+// reset will reset the block for a new encode, but in the same stream,
+// meaning that state will be carried over, but the block content is reset.
+// If a previous block is provided, the recent offsets are carried over.
+func (b *blockEnc) swapEncoders(prev *blockEnc) {
+ b.coders.swap(&prev.coders)
+ b.litEnc, prev.litEnc = prev.litEnc, b.litEnc
+}
+
+// blockHeader contains the information for a block header.
+type blockHeader uint32
+
+// setLast sets the 'last' indicator on a block.
+func (h *blockHeader) setLast(b bool) {
+ if b {
+ *h = *h | 1
+ } else {
+ const mask = (1 << 24) - 2
+ *h = *h & mask
+ }
+}
+
+// setSize will store the compressed size of a block.
+func (h *blockHeader) setSize(v uint32) {
+ const mask = 7
+ *h = (*h)&mask | blockHeader(v<<3)
+}
+
+// setType sets the block type.
+func (h *blockHeader) setType(t blockType) {
+ const mask = 1 | (((1 << 24) - 1) ^ 7)
+ *h = (*h & mask) | blockHeader(t<<1)
+}
+
+// appendTo will append the block header to a slice.
+func (h blockHeader) appendTo(b []byte) []byte {
+ return append(b, uint8(h), uint8(h>>8), uint8(h>>16))
+}
+
+// String returns a string representation of the block.
+func (h blockHeader) String() string {
+ return fmt.Sprintf("Type: %d, Size: %d, Last:%t", (h>>1)&3, h>>3, h&1 == 1)
+}
+
+// literalsHeader contains literals header information.
+type literalsHeader uint64
+
+// setType can be used to set the type of literal block.
+func (h *literalsHeader) setType(t literalsBlockType) {
+ const mask = math.MaxUint64 - 3
+ *h = (*h & mask) | literalsHeader(t)
+}
+
+// setSize can be used to set a single size, for uncompressed and RLE content.
+func (h *literalsHeader) setSize(regenLen int) {
+ inBits := bits.Len32(uint32(regenLen))
+ // Only retain 2 bits
+ const mask = 3
+ lh := uint64(*h & mask)
+ switch {
+ case inBits < 5:
+ lh |= (uint64(regenLen) << 3) | (1 << 60)
+ if debugEncoder {
+ got := int(lh>>3) & 0xff
+ if got != regenLen {
+ panic(fmt.Sprint("litRegenSize = ", regenLen, "(want) != ", got, "(got)"))
+ }
+ }
+ case inBits < 12:
+ lh |= (1 << 2) | (uint64(regenLen) << 4) | (2 << 60)
+ case inBits < 20:
+ lh |= (3 << 2) | (uint64(regenLen) << 4) | (3 << 60)
+ default:
+ panic(fmt.Errorf("internal error: block too big (%d)", regenLen))
+ }
+ *h = literalsHeader(lh)
+}
+
+// setSizes will set the size of a compressed literals section and the input length.
+func (h *literalsHeader) setSizes(compLen, inLen int, single bool) {
+ compBits, inBits := bits.Len32(uint32(compLen)), bits.Len32(uint32(inLen))
+ // Only retain 2 bits
+ const mask = 3
+ lh := uint64(*h & mask)
+ switch {
+ case compBits <= 10 && inBits <= 10:
+ if !single {
+ lh |= 1 << 2
+ }
+ lh |= (uint64(inLen) << 4) | (uint64(compLen) << (10 + 4)) | (3 << 60)
+ if debugEncoder {
+ const mmask = (1 << 24) - 1
+ n := (lh >> 4) & mmask
+ if int(n&1023) != inLen {
+ panic(fmt.Sprint("regensize:", int(n&1023), "!=", inLen, inBits))
+ }
+ if int(n>>10) != compLen {
+ panic(fmt.Sprint("compsize:", int(n>>10), "!=", compLen, compBits))
+ }
+ }
+ case compBits <= 14 && inBits <= 14:
+ lh |= (2 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (14 + 4)) | (4 << 60)
+ if single {
+ panic("single stream used with more than 10 bits length.")
+ }
+ case compBits <= 18 && inBits <= 18:
+ lh |= (3 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (18 + 4)) | (5 << 60)
+ if single {
+ panic("single stream used with more than 10 bits length.")
+ }
+ default:
+ panic("internal error: block too big")
+ }
+ *h = literalsHeader(lh)
+}
+
+// appendTo will append the literals header to a byte slice.
+func (h literalsHeader) appendTo(b []byte) []byte {
+ size := uint8(h >> 60)
+ switch size {
+ case 1:
+ b = append(b, uint8(h))
+ case 2:
+ b = append(b, uint8(h), uint8(h>>8))
+ case 3:
+ b = append(b, uint8(h), uint8(h>>8), uint8(h>>16))
+ case 4:
+ b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24))
+ case 5:
+ b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24), uint8(h>>32))
+ default:
+ panic(fmt.Errorf("internal error: literalsHeader has invalid size (%d)", size))
+ }
+ return b
+}
+
+// size returns the output size with currently set values.
+func (h literalsHeader) size() int {
+ return int(h >> 60)
+}
+
+func (h literalsHeader) String() string {
+ return fmt.Sprintf("Type: %d, SizeFormat: %d, Size: 0x%d, Bytes:%d", literalsBlockType(h&3), (h>>2)&3, h&((1<<60)-1)>>4, h>>60)
+}
+
+// pushOffsets will push the recent offsets to the backup store.
+func (b *blockEnc) pushOffsets() {
+ b.prevRecentOffsets = b.recentOffsets
+}
+
+// pushOffsets will push the recent offsets to the backup store.
+func (b *blockEnc) popOffsets() {
+ b.recentOffsets = b.prevRecentOffsets
+}
+
+// matchOffset will adjust recent offsets and return the adjusted one,
+// if it matches a previous offset.
+func (b *blockEnc) matchOffset(offset, lits uint32) uint32 {
+ // Check if offset is one of the recent offsets.
+ // Adjusts the output offset accordingly.
+ // Gives a tiny bit of compression, typically around 1%.
+ if true {
+ if lits > 0 {
+ switch offset {
+ case b.recentOffsets[0]:
+ offset = 1
+ case b.recentOffsets[1]:
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 2
+ case b.recentOffsets[2]:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 3
+ default:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset += 3
+ }
+ } else {
+ switch offset {
+ case b.recentOffsets[1]:
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 1
+ case b.recentOffsets[2]:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 2
+ case b.recentOffsets[0] - 1:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset = 3
+ default:
+ b.recentOffsets[2] = b.recentOffsets[1]
+ b.recentOffsets[1] = b.recentOffsets[0]
+ b.recentOffsets[0] = offset
+ offset += 3
+ }
+ }
+ } else {
+ offset += 3
+ }
+ return offset
+}
+
+// encodeRaw can be used to set the output to a raw representation of supplied bytes.
+func (b *blockEnc) encodeRaw(a []byte) {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(uint32(len(a)))
+ bh.setType(blockTypeRaw)
+ b.output = bh.appendTo(b.output[:0])
+ b.output = append(b.output, a...)
+ if debugEncoder {
+ println("Adding RAW block, length", len(a), "last:", b.last)
+ }
+}
+
+// encodeRaw can be used to set the output to a raw representation of supplied bytes.
+func (b *blockEnc) encodeRawTo(dst, src []byte) []byte {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(uint32(len(src)))
+ bh.setType(blockTypeRaw)
+ dst = bh.appendTo(dst)
+ dst = append(dst, src...)
+ if debugEncoder {
+ println("Adding RAW block, length", len(src), "last:", b.last)
+ }
+ return dst
+}
+
+// encodeLits can be used if the block is only litLen.
+func (b *blockEnc) encodeLits(lits []byte, raw bool) error {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(uint32(len(lits)))
+
+ // Don't compress extremely small blocks
+ if len(lits) < 8 || (len(lits) < 32 && b.dictLitEnc == nil) || raw {
+ if debugEncoder {
+ println("Adding RAW block, length", len(lits), "last:", b.last)
+ }
+ bh.setType(blockTypeRaw)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, lits...)
+ return nil
+ }
+
+ var (
+ out []byte
+ reUsed, single bool
+ err error
+ )
+ if b.dictLitEnc != nil {
+ b.litEnc.TransferCTable(b.dictLitEnc)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ b.dictLitEnc = nil
+ }
+ if len(lits) >= 1024 {
+ // Use 4 Streams.
+ out, reUsed, err = huff0.Compress4X(lits, b.litEnc)
+ } else if len(lits) > 16 {
+ // Use 1 stream
+ single = true
+ out, reUsed, err = huff0.Compress1X(lits, b.litEnc)
+ } else {
+ err = huff0.ErrIncompressible
+ }
+ if err == nil && len(out)+5 > len(lits) {
+ // If we are close, we may still be worse or equal to raw.
+ var lh literalsHeader
+ lh.setSizes(len(out), len(lits), single)
+ if len(out)+lh.size() >= len(lits) {
+ err = huff0.ErrIncompressible
+ }
+ }
+ switch err {
+ case huff0.ErrIncompressible:
+ if debugEncoder {
+ println("Adding RAW block, length", len(lits), "last:", b.last)
+ }
+ bh.setType(blockTypeRaw)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, lits...)
+ return nil
+ case huff0.ErrUseRLE:
+ if debugEncoder {
+ println("Adding RLE block, length", len(lits))
+ }
+ bh.setType(blockTypeRLE)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, lits[0])
+ return nil
+ case nil:
+ default:
+ return err
+ }
+ // Compressed...
+ // Now, allow reuse
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ bh.setType(blockTypeCompressed)
+ var lh literalsHeader
+ if reUsed {
+ if debugEncoder {
+ println("Reused tree, compressed to", len(out))
+ }
+ lh.setType(literalsBlockTreeless)
+ } else {
+ if debugEncoder {
+ println("New tree, compressed to", len(out), "tree size:", len(b.litEnc.OutTable))
+ }
+ lh.setType(literalsBlockCompressed)
+ }
+ // Set sizes
+ lh.setSizes(len(out), len(lits), single)
+ bh.setSize(uint32(len(out) + lh.size() + 1))
+
+ // Write block headers.
+ b.output = bh.appendTo(b.output)
+ b.output = lh.appendTo(b.output)
+ // Add compressed data.
+ b.output = append(b.output, out...)
+ // No sequences.
+ b.output = append(b.output, 0)
+ return nil
+}
+
+// encodeRLE will encode an RLE block.
+func (b *blockEnc) encodeRLE(val byte, length uint32) {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(length)
+ bh.setType(blockTypeRLE)
+ b.output = bh.appendTo(b.output)
+ b.output = append(b.output, val)
+}
+
+// fuzzFseEncoder can be used to fuzz the FSE encoder.
+func fuzzFseEncoder(data []byte) int {
+ if len(data) > maxSequences || len(data) < 2 {
+ return 0
+ }
+ enc := fseEncoder{}
+ hist := enc.Histogram()
+ maxSym := uint8(0)
+ for i, v := range data {
+ v = v & 63
+ data[i] = v
+ hist[v]++
+ if v > maxSym {
+ maxSym = v
+ }
+ }
+ if maxSym == 0 {
+ // All 0
+ return 0
+ }
+ cnt := int(slices.Max(hist[:maxSym]))
+ if cnt == len(data) {
+ // RLE
+ return 0
+ }
+ enc.HistogramFinished(maxSym, cnt)
+ err := enc.normalizeCount(len(data))
+ if err != nil {
+ return 0
+ }
+ _, err = enc.writeCount(nil)
+ if err != nil {
+ panic(err)
+ }
+ return 1
+}
+
+// encode will encode the block and append the output in b.output.
+// Previous offset codes must be pushed if more blocks are expected.
+func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
+ if len(b.sequences) == 0 {
+ return b.encodeLits(b.literals, rawAllLits)
+ }
+ if len(b.sequences) == 1 && len(org) > 0 && len(b.literals) <= 1 {
+ // Check common RLE cases.
+ seq := b.sequences[0]
+ if seq.litLen == uint32(len(b.literals)) && seq.offset-3 == 1 {
+ // Offset == 1 and 0 or 1 literals.
+ b.encodeRLE(org[0], b.sequences[0].matchLen+zstdMinMatch+seq.litLen)
+ return nil
+ }
+ }
+
+ // We want some difference to at least account for the headers.
+ saved := b.size - len(b.literals) - (b.size >> 6)
+ if saved < 16 {
+ if org == nil {
+ return errIncompressible
+ }
+ b.popOffsets()
+ return b.encodeLits(org, rawAllLits)
+ }
+
+ var bh blockHeader
+ var lh literalsHeader
+ bh.setLast(b.last)
+ bh.setType(blockTypeCompressed)
+ // Store offset of the block header. Needed when we know the size.
+ bhOffset := len(b.output)
+ b.output = bh.appendTo(b.output)
+
+ var (
+ out []byte
+ reUsed, single bool
+ err error
+ )
+ if b.dictLitEnc != nil {
+ b.litEnc.TransferCTable(b.dictLitEnc)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ b.dictLitEnc = nil
+ }
+ if len(b.literals) >= 1024 && !raw {
+ // Use 4 Streams.
+ out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc)
+ } else if len(b.literals) > 16 && !raw {
+ // Use 1 stream
+ single = true
+ out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc)
+ } else {
+ err = huff0.ErrIncompressible
+ }
+
+ if err == nil && len(out)+5 > len(b.literals) {
+ // If we are close, we may still be worse or equal to raw.
+ var lh literalsHeader
+ lh.setSize(len(b.literals))
+ szRaw := lh.size()
+ lh.setSizes(len(out), len(b.literals), single)
+ szComp := lh.size()
+ if len(out)+szComp >= len(b.literals)+szRaw {
+ err = huff0.ErrIncompressible
+ }
+ }
+ switch err {
+ case huff0.ErrIncompressible:
+ lh.setType(literalsBlockRaw)
+ lh.setSize(len(b.literals))
+ b.output = lh.appendTo(b.output)
+ b.output = append(b.output, b.literals...)
+ if debugEncoder {
+ println("Adding literals RAW, length", len(b.literals))
+ }
+ case huff0.ErrUseRLE:
+ lh.setType(literalsBlockRLE)
+ lh.setSize(len(b.literals))
+ b.output = lh.appendTo(b.output)
+ b.output = append(b.output, b.literals[0])
+ if debugEncoder {
+ println("Adding literals RLE")
+ }
+ case nil:
+ // Compressed litLen...
+ if reUsed {
+ if debugEncoder {
+ println("reused tree")
+ }
+ lh.setType(literalsBlockTreeless)
+ } else {
+ if debugEncoder {
+ println("new tree, size:", len(b.litEnc.OutTable))
+ }
+ lh.setType(literalsBlockCompressed)
+ if debugEncoder {
+ _, _, err := huff0.ReadTable(out, nil)
+ if err != nil {
+ panic(err)
+ }
+ }
+ }
+ lh.setSizes(len(out), len(b.literals), single)
+ if debugEncoder {
+ printf("Compressed %d literals to %d bytes", len(b.literals), len(out))
+ println("Adding literal header:", lh)
+ }
+ b.output = lh.appendTo(b.output)
+ b.output = append(b.output, out...)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ if debugEncoder {
+ println("Adding literals compressed")
+ }
+ default:
+ if debugEncoder {
+ println("Adding literals ERROR:", err)
+ }
+ return err
+ }
+ // Sequence compression
+
+ // Write the number of sequences
+ switch {
+ case len(b.sequences) < 128:
+ b.output = append(b.output, uint8(len(b.sequences)))
+ case len(b.sequences) < 0x7f00: // TODO: this could be wrong
+ n := len(b.sequences)
+ b.output = append(b.output, 128+uint8(n>>8), uint8(n))
+ default:
+ n := len(b.sequences) - 0x7f00
+ b.output = append(b.output, 255, uint8(n), uint8(n>>8))
+ }
+ if debugEncoder {
+ println("Encoding", len(b.sequences), "sequences")
+ }
+ b.genCodes()
+ llEnc := b.coders.llEnc
+ ofEnc := b.coders.ofEnc
+ mlEnc := b.coders.mlEnc
+ err = llEnc.normalizeCount(len(b.sequences))
+ if err != nil {
+ return err
+ }
+ err = ofEnc.normalizeCount(len(b.sequences))
+ if err != nil {
+ return err
+ }
+ err = mlEnc.normalizeCount(len(b.sequences))
+ if err != nil {
+ return err
+ }
+
+ // Choose the best compression mode for each type.
+ // Will evaluate the new vs predefined and previous.
+ chooseComp := func(cur, prev, preDef *fseEncoder) (*fseEncoder, seqCompMode) {
+ // See if predefined/previous is better
+ hist := cur.count[:cur.symbolLen]
+ nSize := cur.approxSize(hist) + cur.maxHeaderSize()
+ predefSize := preDef.approxSize(hist)
+ prevSize := prev.approxSize(hist)
+
+ // Add a small penalty for new encoders.
+ // Don't bother with extremely small (<2 byte gains).
+ nSize = nSize + (nSize+2*8*16)>>4
+ switch {
+ case predefSize <= prevSize && predefSize <= nSize || forcePreDef:
+ if debugEncoder {
+ println("Using predefined", predefSize>>3, "<=", nSize>>3)
+ }
+ return preDef, compModePredefined
+ case prevSize <= nSize:
+ if debugEncoder {
+ println("Using previous", prevSize>>3, "<=", nSize>>3)
+ }
+ return prev, compModeRepeat
+ default:
+ if debugEncoder {
+ println("Using new, predef", predefSize>>3, ". previous:", prevSize>>3, ">", nSize>>3, "header max:", cur.maxHeaderSize()>>3, "bytes")
+ println("tl:", cur.actualTableLog, "symbolLen:", cur.symbolLen, "norm:", cur.norm[:cur.symbolLen], "hist", cur.count[:cur.symbolLen])
+ }
+ return cur, compModeFSE
+ }
+ }
+
+ // Write compression mode
+ var mode uint8
+ if llEnc.useRLE {
+ mode |= uint8(compModeRLE) << 6
+ llEnc.setRLE(b.sequences[0].llCode)
+ if debugEncoder {
+ println("llEnc.useRLE")
+ }
+ } else {
+ var m seqCompMode
+ llEnc, m = chooseComp(llEnc, b.coders.llPrev, &fsePredefEnc[tableLiteralLengths])
+ mode |= uint8(m) << 6
+ }
+ if ofEnc.useRLE {
+ mode |= uint8(compModeRLE) << 4
+ ofEnc.setRLE(b.sequences[0].ofCode)
+ if debugEncoder {
+ println("ofEnc.useRLE")
+ }
+ } else {
+ var m seqCompMode
+ ofEnc, m = chooseComp(ofEnc, b.coders.ofPrev, &fsePredefEnc[tableOffsets])
+ mode |= uint8(m) << 4
+ }
+
+ if mlEnc.useRLE {
+ mode |= uint8(compModeRLE) << 2
+ mlEnc.setRLE(b.sequences[0].mlCode)
+ if debugEncoder {
+ println("mlEnc.useRLE, code: ", b.sequences[0].mlCode, "value", b.sequences[0].matchLen)
+ }
+ } else {
+ var m seqCompMode
+ mlEnc, m = chooseComp(mlEnc, b.coders.mlPrev, &fsePredefEnc[tableMatchLengths])
+ mode |= uint8(m) << 2
+ }
+ b.output = append(b.output, mode)
+ if debugEncoder {
+ printf("Compression modes: 0b%b", mode)
+ }
+ b.output, err = llEnc.writeCount(b.output)
+ if err != nil {
+ return err
+ }
+ start := len(b.output)
+ b.output, err = ofEnc.writeCount(b.output)
+ if err != nil {
+ return err
+ }
+ if false {
+ println("block:", b.output[start:], "tablelog", ofEnc.actualTableLog, "maxcount:", ofEnc.maxCount)
+ fmt.Printf("selected TableLog: %d, Symbol length: %d\n", ofEnc.actualTableLog, ofEnc.symbolLen)
+ for i, v := range ofEnc.norm[:ofEnc.symbolLen] {
+ fmt.Printf("%3d: %5d -> %4d \n", i, ofEnc.count[i], v)
+ }
+ }
+ b.output, err = mlEnc.writeCount(b.output)
+ if err != nil {
+ return err
+ }
+
+ // Maybe in block?
+ wr := &b.wr
+ wr.reset(b.output)
+
+ var ll, of, ml cState
+
+ // Current sequence
+ seq := len(b.sequences) - 1
+ s := b.sequences[seq]
+ llEnc.setBits(llBitsTable[:])
+ mlEnc.setBits(mlBitsTable[:])
+ ofEnc.setBits(nil)
+
+ llTT, ofTT, mlTT := llEnc.ct.symbolTT[:256], ofEnc.ct.symbolTT[:256], mlEnc.ct.symbolTT[:256]
+
+ // We have 3 bounds checks here (and in the loop).
+ // Since we are iterating backwards it is kinda hard to avoid.
+ llB, ofB, mlB := llTT[s.llCode], ofTT[s.ofCode], mlTT[s.mlCode]
+ ll.init(wr, &llEnc.ct, llB)
+ of.init(wr, &ofEnc.ct, ofB)
+ wr.flush32()
+ ml.init(wr, &mlEnc.ct, mlB)
+
+ // Each of these lookups also generates a bounds check.
+ wr.addBits32NC(s.litLen, llB.outBits)
+ wr.addBits32NC(s.matchLen, mlB.outBits)
+ wr.flush32()
+ wr.addBits32NC(s.offset, ofB.outBits)
+ if debugSequences {
+ println("Encoded seq", seq, s, "codes:", s.llCode, s.mlCode, s.ofCode, "states:", ll.state, ml.state, of.state, "bits:", llB, mlB, ofB)
+ }
+ seq--
+ // Store sequences in reverse...
+ for seq >= 0 {
+ s = b.sequences[seq]
+
+ ofB := ofTT[s.ofCode]
+ wr.flush32() // tablelog max is below 8 for each, so it will fill max 24 bits.
+ //of.encode(ofB)
+ nbBitsOut := (uint32(of.state) + ofB.deltaNbBits) >> 16
+ dstState := int32(of.state>>(nbBitsOut&15)) + int32(ofB.deltaFindState)
+ wr.addBits16NC(of.state, uint8(nbBitsOut))
+ of.state = of.stateTable[dstState]
+
+ // Accumulate extra bits.
+ outBits := ofB.outBits & 31
+ extraBits := uint64(s.offset & bitMask32[outBits])
+ extraBitsN := outBits
+
+ mlB := mlTT[s.mlCode]
+ //ml.encode(mlB)
+ nbBitsOut = (uint32(ml.state) + mlB.deltaNbBits) >> 16
+ dstState = int32(ml.state>>(nbBitsOut&15)) + int32(mlB.deltaFindState)
+ wr.addBits16NC(ml.state, uint8(nbBitsOut))
+ ml.state = ml.stateTable[dstState]
+
+ outBits = mlB.outBits & 31
+ extraBits = extraBits<> 16
+ dstState = int32(ll.state>>(nbBitsOut&15)) + int32(llB.deltaFindState)
+ wr.addBits16NC(ll.state, uint8(nbBitsOut))
+ ll.state = ll.stateTable[dstState]
+
+ outBits = llB.outBits & 31
+ extraBits = extraBits<= b.size {
+ // Discard and encode as raw block.
+ b.output = b.encodeRawTo(b.output[:bhOffset], org)
+ b.popOffsets()
+ b.litEnc.Reuse = huff0.ReusePolicyNone
+ return nil
+ }
+
+ // Size is output minus block header.
+ bh.setSize(uint32(len(b.output)-bhOffset) - 3)
+ if debugEncoder {
+ println("Rewriting block header", bh)
+ }
+ _ = bh.appendTo(b.output[bhOffset:bhOffset])
+ b.coders.setPrev(llEnc, mlEnc, ofEnc)
+ return nil
+}
+
+var errIncompressible = errors.New("incompressible")
+
+func (b *blockEnc) genCodes() {
+ if len(b.sequences) == 0 {
+ // nothing to do
+ return
+ }
+ if len(b.sequences) > math.MaxUint16 {
+ panic("can only encode up to 64K sequences")
+ }
+ // No bounds checks after here:
+ llH := b.coders.llEnc.Histogram()
+ ofH := b.coders.ofEnc.Histogram()
+ mlH := b.coders.mlEnc.Histogram()
+ for i := range llH {
+ llH[i] = 0
+ }
+ for i := range ofH {
+ ofH[i] = 0
+ }
+ for i := range mlH {
+ mlH[i] = 0
+ }
+
+ var llMax, ofMax, mlMax uint8
+ for i := range b.sequences {
+ seq := &b.sequences[i]
+ v := llCode(seq.litLen)
+ seq.llCode = v
+ llH[v]++
+ if v > llMax {
+ llMax = v
+ }
+
+ v = ofCode(seq.offset)
+ seq.ofCode = v
+ ofH[v]++
+ if v > ofMax {
+ ofMax = v
+ }
+
+ v = mlCode(seq.matchLen)
+ seq.mlCode = v
+ mlH[v]++
+ if v > mlMax {
+ mlMax = v
+ if debugAsserts && mlMax > maxMatchLengthSymbol {
+ panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d), matchlen: %d", mlMax, seq.matchLen))
+ }
+ }
+ }
+ if debugAsserts && mlMax > maxMatchLengthSymbol {
+ panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d)", mlMax))
+ }
+ if debugAsserts && ofMax > maxOffsetBits {
+ panic(fmt.Errorf("ofMax > maxOffsetBits (%d)", ofMax))
+ }
+ if debugAsserts && llMax > maxLiteralLengthSymbol {
+ panic(fmt.Errorf("llMax > maxLiteralLengthSymbol (%d)", llMax))
+ }
+
+ b.coders.mlEnc.HistogramFinished(mlMax, int(slices.Max(mlH[:mlMax+1])))
+ b.coders.ofEnc.HistogramFinished(ofMax, int(slices.Max(ofH[:ofMax+1])))
+ b.coders.llEnc.HistogramFinished(llMax, int(slices.Max(llH[:llMax+1])))
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/blocktype_string.go b/vendor/github.com/klauspost/compress/zstd/blocktype_string.go
new file mode 100644
index 00000000..01a01e48
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/blocktype_string.go
@@ -0,0 +1,85 @@
+// Code generated by "stringer -type=blockType,literalsBlockType,seqCompMode,tableIndex"; DO NOT EDIT.
+
+package zstd
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[blockTypeRaw-0]
+ _ = x[blockTypeRLE-1]
+ _ = x[blockTypeCompressed-2]
+ _ = x[blockTypeReserved-3]
+}
+
+const _blockType_name = "blockTypeRawblockTypeRLEblockTypeCompressedblockTypeReserved"
+
+var _blockType_index = [...]uint8{0, 12, 24, 43, 60}
+
+func (i blockType) String() string {
+ if i >= blockType(len(_blockType_index)-1) {
+ return "blockType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _blockType_name[_blockType_index[i]:_blockType_index[i+1]]
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[literalsBlockRaw-0]
+ _ = x[literalsBlockRLE-1]
+ _ = x[literalsBlockCompressed-2]
+ _ = x[literalsBlockTreeless-3]
+}
+
+const _literalsBlockType_name = "literalsBlockRawliteralsBlockRLEliteralsBlockCompressedliteralsBlockTreeless"
+
+var _literalsBlockType_index = [...]uint8{0, 16, 32, 55, 76}
+
+func (i literalsBlockType) String() string {
+ if i >= literalsBlockType(len(_literalsBlockType_index)-1) {
+ return "literalsBlockType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _literalsBlockType_name[_literalsBlockType_index[i]:_literalsBlockType_index[i+1]]
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[compModePredefined-0]
+ _ = x[compModeRLE-1]
+ _ = x[compModeFSE-2]
+ _ = x[compModeRepeat-3]
+}
+
+const _seqCompMode_name = "compModePredefinedcompModeRLEcompModeFSEcompModeRepeat"
+
+var _seqCompMode_index = [...]uint8{0, 18, 29, 40, 54}
+
+func (i seqCompMode) String() string {
+ if i >= seqCompMode(len(_seqCompMode_index)-1) {
+ return "seqCompMode(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _seqCompMode_name[_seqCompMode_index[i]:_seqCompMode_index[i+1]]
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[tableLiteralLengths-0]
+ _ = x[tableOffsets-1]
+ _ = x[tableMatchLengths-2]
+}
+
+const _tableIndex_name = "tableLiteralLengthstableOffsetstableMatchLengths"
+
+var _tableIndex_index = [...]uint8{0, 19, 31, 48}
+
+func (i tableIndex) String() string {
+ if i >= tableIndex(len(_tableIndex_index)-1) {
+ return "tableIndex(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _tableIndex_name[_tableIndex_index[i]:_tableIndex_index[i+1]]
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/bytebuf.go b/vendor/github.com/klauspost/compress/zstd/bytebuf.go
new file mode 100644
index 00000000..55a38855
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bytebuf.go
@@ -0,0 +1,131 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "fmt"
+ "io"
+)
+
+type byteBuffer interface {
+ // Read up to 8 bytes.
+ // Returns io.ErrUnexpectedEOF if this cannot be satisfied.
+ readSmall(n int) ([]byte, error)
+
+ // Read >8 bytes.
+ // MAY use the destination slice.
+ readBig(n int, dst []byte) ([]byte, error)
+
+ // Read a single byte.
+ readByte() (byte, error)
+
+ // Skip n bytes.
+ skipN(n int64) error
+}
+
+// in-memory buffer
+type byteBuf []byte
+
+func (b *byteBuf) readSmall(n int) ([]byte, error) {
+ if debugAsserts && n > 8 {
+ panic(fmt.Errorf("small read > 8 (%d). use readBig", n))
+ }
+ bb := *b
+ if len(bb) < n {
+ return nil, io.ErrUnexpectedEOF
+ }
+ r := bb[:n]
+ *b = bb[n:]
+ return r, nil
+}
+
+func (b *byteBuf) readBig(n int, dst []byte) ([]byte, error) {
+ bb := *b
+ if len(bb) < n {
+ return nil, io.ErrUnexpectedEOF
+ }
+ r := bb[:n]
+ *b = bb[n:]
+ return r, nil
+}
+
+func (b *byteBuf) readByte() (byte, error) {
+ bb := *b
+ if len(bb) < 1 {
+ return 0, io.ErrUnexpectedEOF
+ }
+ r := bb[0]
+ *b = bb[1:]
+ return r, nil
+}
+
+func (b *byteBuf) skipN(n int64) error {
+ bb := *b
+ if n < 0 {
+ return fmt.Errorf("negative skip (%d) requested", n)
+ }
+ if int64(len(bb)) < n {
+ return io.ErrUnexpectedEOF
+ }
+ *b = bb[n:]
+ return nil
+}
+
+// wrapper around a reader.
+type readerWrapper struct {
+ r io.Reader
+ tmp [8]byte
+}
+
+func (r *readerWrapper) readSmall(n int) ([]byte, error) {
+ if debugAsserts && n > 8 {
+ panic(fmt.Errorf("small read > 8 (%d). use readBig", n))
+ }
+ n2, err := io.ReadFull(r.r, r.tmp[:n])
+ // We only really care about the actual bytes read.
+ if err != nil {
+ if err == io.EOF {
+ return nil, io.ErrUnexpectedEOF
+ }
+ if debugDecoder {
+ println("readSmall: got", n2, "want", n, "err", err)
+ }
+ return nil, err
+ }
+ return r.tmp[:n], nil
+}
+
+func (r *readerWrapper) readBig(n int, dst []byte) ([]byte, error) {
+ if cap(dst) < n {
+ dst = make([]byte, n)
+ }
+ n2, err := io.ReadFull(r.r, dst[:n])
+ if err == io.EOF && n > 0 {
+ err = io.ErrUnexpectedEOF
+ }
+ return dst[:n2], err
+}
+
+func (r *readerWrapper) readByte() (byte, error) {
+ n2, err := io.ReadFull(r.r, r.tmp[:1])
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ if n2 != 1 {
+ return 0, io.ErrUnexpectedEOF
+ }
+ return r.tmp[0], nil
+}
+
+func (r *readerWrapper) skipN(n int64) error {
+ n2, err := io.CopyN(io.Discard, r.r, n)
+ if n2 != n {
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/bytereader.go b/vendor/github.com/klauspost/compress/zstd/bytereader.go
new file mode 100644
index 00000000..0e59a242
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/bytereader.go
@@ -0,0 +1,82 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+// byteReader provides a byte reader that reads
+// little endian values from a byte stream.
+// The input stream is manually advanced.
+// The reader performs no bounds checks.
+type byteReader struct {
+ b []byte
+ off int
+}
+
+// advance the stream b n bytes.
+func (b *byteReader) advance(n uint) {
+ b.off += int(n)
+}
+
+// overread returns whether we have advanced too far.
+func (b *byteReader) overread() bool {
+ return b.off > len(b.b)
+}
+
+// Int32 returns a little endian int32 starting at current offset.
+func (b byteReader) Int32() int32 {
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := int32(b2[3])
+ v2 := int32(b2[2])
+ v1 := int32(b2[1])
+ v0 := int32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// Uint8 returns the next byte
+func (b *byteReader) Uint8() uint8 {
+ v := b.b[b.off]
+ return v
+}
+
+// Uint32 returns a little endian uint32 starting at current offset.
+func (b byteReader) Uint32() uint32 {
+ if r := b.remain(); r < 4 {
+ // Very rare
+ v := uint32(0)
+ for i := 1; i <= r; i++ {
+ v = (v << 8) | uint32(b.b[len(b.b)-i])
+ }
+ return v
+ }
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// Uint32NC returns a little endian uint32 starting at current offset.
+// The caller must be sure if there are at least 4 bytes left.
+func (b byteReader) Uint32NC() uint32 {
+ b2 := b.b[b.off:]
+ b2 = b2[:4]
+ v3 := uint32(b2[3])
+ v2 := uint32(b2[2])
+ v1 := uint32(b2[1])
+ v0 := uint32(b2[0])
+ return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24)
+}
+
+// unread returns the unread portion of the input.
+func (b byteReader) unread() []byte {
+ return b.b[b.off:]
+}
+
+// remain will return the number of bytes remaining.
+func (b byteReader) remain() int {
+ return len(b.b) - b.off
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/decodeheader.go b/vendor/github.com/klauspost/compress/zstd/decodeheader.go
new file mode 100644
index 00000000..6a5a2988
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/decodeheader.go
@@ -0,0 +1,261 @@
+// Copyright 2020+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+// HeaderMaxSize is the maximum size of a Frame and Block Header.
+// If less is sent to Header.Decode it *may* still contain enough information.
+const HeaderMaxSize = 14 + 3
+
+// Header contains information about the first frame and block within that.
+type Header struct {
+ // SingleSegment specifies whether the data is to be decompressed into a
+ // single contiguous memory segment.
+ // It implies that WindowSize is invalid and that FrameContentSize is valid.
+ SingleSegment bool
+
+ // WindowSize is the window of data to keep while decoding.
+ // Will only be set if SingleSegment is false.
+ WindowSize uint64
+
+ // Dictionary ID.
+ // If 0, no dictionary.
+ DictionaryID uint32
+
+ // HasFCS specifies whether FrameContentSize has a valid value.
+ HasFCS bool
+
+ // FrameContentSize is the expected uncompressed size of the entire frame.
+ FrameContentSize uint64
+
+ // Skippable will be true if the frame is meant to be skipped.
+ // This implies that FirstBlock.OK is false.
+ Skippable bool
+
+ // SkippableID is the user-specific ID for the skippable frame.
+ // Valid values are between 0 to 15, inclusive.
+ SkippableID int
+
+ // SkippableSize is the length of the user data to skip following
+ // the header.
+ SkippableSize uint32
+
+ // HeaderSize is the raw size of the frame header.
+ //
+ // For normal frames, it includes the size of the magic number and
+ // the size of the header (per section 3.1.1.1).
+ // It does not include the size for any data blocks (section 3.1.1.2) nor
+ // the size for the trailing content checksum.
+ //
+ // For skippable frames, this counts the size of the magic number
+ // along with the size of the size field of the payload.
+ // It does not include the size of the skippable payload itself.
+ // The total frame size is the HeaderSize plus the SkippableSize.
+ HeaderSize int
+
+ // First block information.
+ FirstBlock struct {
+ // OK will be set if first block could be decoded.
+ OK bool
+
+ // Is this the last block of a frame?
+ Last bool
+
+ // Is the data compressed?
+ // If true CompressedSize will be populated.
+ // Unfortunately DecompressedSize cannot be determined
+ // without decoding the blocks.
+ Compressed bool
+
+ // DecompressedSize is the expected decompressed size of the block.
+ // Will be 0 if it cannot be determined.
+ DecompressedSize int
+
+ // CompressedSize of the data in the block.
+ // Does not include the block header.
+ // Will be equal to DecompressedSize if not Compressed.
+ CompressedSize int
+ }
+
+ // If set there is a checksum present for the block content.
+ // The checksum field at the end is always 4 bytes long.
+ HasCheckSum bool
+}
+
+// Decode the header from the beginning of the stream.
+// This will decode the frame header and the first block header if enough bytes are provided.
+// It is recommended to provide at least HeaderMaxSize bytes.
+// If the frame header cannot be read an error will be returned.
+// If there isn't enough input, io.ErrUnexpectedEOF is returned.
+// The FirstBlock.OK will indicate if enough information was available to decode the first block header.
+func (h *Header) Decode(in []byte) error {
+ _, err := h.DecodeAndStrip(in)
+ return err
+}
+
+// DecodeAndStrip will decode the header from the beginning of the stream
+// and on success return the remaining bytes.
+// This will decode the frame header and the first block header if enough bytes are provided.
+// It is recommended to provide at least HeaderMaxSize bytes.
+// If the frame header cannot be read an error will be returned.
+// If there isn't enough input, io.ErrUnexpectedEOF is returned.
+// The FirstBlock.OK will indicate if enough information was available to decode the first block header.
+func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) {
+ *h = Header{}
+ if len(in) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ h.HeaderSize += 4
+ b, in := in[:4], in[4:]
+ if string(b) != frameMagic {
+ if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 {
+ return nil, ErrMagicMismatch
+ }
+ if len(in) < 4 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ h.HeaderSize += 4
+ h.Skippable = true
+ h.SkippableID = int(b[0] & 0xf)
+ h.SkippableSize = binary.LittleEndian.Uint32(in)
+ return in[4:], nil
+ }
+
+ // Read Window_Descriptor
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
+ if len(in) < 1 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ fhd, in := in[0], in[1:]
+ h.HeaderSize++
+ h.SingleSegment = fhd&(1<<5) != 0
+ h.HasCheckSum = fhd&(1<<2) != 0
+ if fhd&(1<<3) != 0 {
+ return nil, errors.New("reserved bit set on frame header")
+ }
+
+ if !h.SingleSegment {
+ if len(in) < 1 {
+ return nil, io.ErrUnexpectedEOF
+ }
+ var wd byte
+ wd, in = in[0], in[1:]
+ h.HeaderSize++
+ windowLog := 10 + (wd >> 3)
+ windowBase := uint64(1) << windowLog
+ windowAdd := (windowBase / 8) * uint64(wd&0x7)
+ h.WindowSize = windowBase + windowAdd
+ }
+
+ // Read Dictionary_ID
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
+ if size := fhd & 3; size != 0 {
+ if size == 3 {
+ size = 4
+ }
+ if len(in) < int(size) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b, in = in[:size], in[size:]
+ h.HeaderSize += int(size)
+ switch len(b) {
+ case 1:
+ h.DictionaryID = uint32(b[0])
+ case 2:
+ h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8)
+ case 4:
+ h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ }
+ }
+
+ // Read Frame_Content_Size
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size
+ var fcsSize int
+ v := fhd >> 6
+ switch v {
+ case 0:
+ if h.SingleSegment {
+ fcsSize = 1
+ }
+ default:
+ fcsSize = 1 << v
+ }
+
+ if fcsSize > 0 {
+ h.HasFCS = true
+ if len(in) < fcsSize {
+ return nil, io.ErrUnexpectedEOF
+ }
+ b, in = in[:fcsSize], in[fcsSize:]
+ h.HeaderSize += int(fcsSize)
+ switch len(b) {
+ case 1:
+ h.FrameContentSize = uint64(b[0])
+ case 2:
+ // When FCS_Field_Size is 2, the offset of 256 is added.
+ h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
+ case 4:
+ h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
+ case 8:
+ d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
+ h.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
+ }
+ }
+
+ // Frame Header done, we will not fail from now on.
+ if len(in) < 3 {
+ return in, nil
+ }
+ tmp := in[:3]
+ bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16)
+ h.FirstBlock.Last = bh&1 != 0
+ blockType := blockType((bh >> 1) & 3)
+ // find size.
+ cSize := int(bh >> 3)
+ switch blockType {
+ case blockTypeReserved:
+ return in, nil
+ case blockTypeRLE:
+ h.FirstBlock.Compressed = true
+ h.FirstBlock.DecompressedSize = cSize
+ h.FirstBlock.CompressedSize = 1
+ case blockTypeCompressed:
+ h.FirstBlock.Compressed = true
+ h.FirstBlock.CompressedSize = cSize
+ case blockTypeRaw:
+ h.FirstBlock.DecompressedSize = cSize
+ h.FirstBlock.CompressedSize = cSize
+ default:
+ panic("Invalid block type")
+ }
+
+ h.FirstBlock.OK = true
+ return in, nil
+}
+
+// AppendTo will append the encoded header to the dst slice.
+// There is no error checking performed on the header values.
+func (h *Header) AppendTo(dst []byte) ([]byte, error) {
+ if h.Skippable {
+ magic := [4]byte{0x50, 0x2a, 0x4d, 0x18}
+ magic[0] |= byte(h.SkippableID & 0xf)
+ dst = append(dst, magic[:]...)
+ f := h.SkippableSize
+ return append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24)), nil
+ }
+ f := frameHeader{
+ ContentSize: h.FrameContentSize,
+ WindowSize: uint32(h.WindowSize),
+ SingleSegment: h.SingleSegment,
+ Checksum: h.HasCheckSum,
+ DictID: h.DictionaryID,
+ }
+ return f.appendTo(dst), nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
new file mode 100644
index 00000000..c7e500f0
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -0,0 +1,957 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "context"
+ "encoding/binary"
+ "io"
+ "sync"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+// Decoder provides decoding of zstandard streams.
+// The decoder has been designed to operate without allocations after a warmup.
+// This means that you should store the decoder for best performance.
+// To re-use a stream decoder, use the Reset(r io.Reader) error to switch to another stream.
+// A decoder can safely be re-used even if the previous stream failed.
+// To release the resources, you must call the Close() function on a decoder.
+type Decoder struct {
+ o decoderOptions
+
+ // Unreferenced decoders, ready for use.
+ decoders chan *blockDec
+
+ // Current read position used for Reader functionality.
+ current decoderState
+
+ // sync stream decoding
+ syncStream struct {
+ decodedFrame uint64
+ br readerWrapper
+ enabled bool
+ inFrame bool
+ dstBuf []byte
+ }
+
+ frame *frameDec
+
+ // streamWg is the waitgroup for all streams
+ streamWg sync.WaitGroup
+}
+
+// decoderState is used for maintaining state when the decoder
+// is used for streaming.
+type decoderState struct {
+ // current block being written to stream.
+ decodeOutput
+
+ // output in order to be written to stream.
+ output chan decodeOutput
+
+ // cancel remaining output.
+ cancel context.CancelFunc
+
+ // crc of current frame
+ crc *xxhash.Digest
+
+ flushed bool
+}
+
+var (
+ // Check the interfaces we want to support.
+ _ = io.WriterTo(&Decoder{})
+ _ = io.Reader(&Decoder{})
+)
+
+// NewReader creates a new decoder.
+// A nil Reader can be provided in which case Reset can be used to start a decode.
+//
+// A Decoder can be used in two modes:
+//
+// 1) As a stream, or
+// 2) For stateless decoding using DecodeAll.
+//
+// Only a single stream can be decoded concurrently, but the same decoder
+// can run multiple concurrent stateless decodes. It is even possible to
+// use stateless decodes while a stream is being decoded.
+//
+// The Reset function can be used to initiate a new stream, which will considerably
+// reduce the allocations normally caused by NewReader.
+func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
+ initPredefined()
+ var d Decoder
+ d.o.setDefault()
+ for _, o := range opts {
+ err := o(&d.o)
+ if err != nil {
+ return nil, err
+ }
+ }
+ d.current.crc = xxhash.New()
+ d.current.flushed = true
+
+ if r == nil {
+ d.current.err = ErrDecoderNilInput
+ }
+
+ // Initialize dict map if needed.
+ if d.o.dicts == nil {
+ d.o.dicts = make(map[uint32]*dict)
+ }
+
+ // Create decoders
+ d.decoders = make(chan *blockDec, d.o.concurrent)
+ for i := 0; i < d.o.concurrent; i++ {
+ dec := newBlockDec(d.o.lowMem)
+ dec.localFrame = newFrameDec(d.o)
+ d.decoders <- dec
+ }
+
+ if r == nil {
+ return &d, nil
+ }
+ return &d, d.Reset(r)
+}
+
+// Read bytes from the decompressed stream into p.
+// Returns the number of bytes read and any error that occurred.
+// When the stream is done, io.EOF will be returned.
+func (d *Decoder) Read(p []byte) (int, error) {
+ var n int
+ for {
+ if len(d.current.b) > 0 {
+ filled := copy(p, d.current.b)
+ p = p[filled:]
+ d.current.b = d.current.b[filled:]
+ n += filled
+ }
+ if len(p) == 0 {
+ break
+ }
+ if len(d.current.b) == 0 {
+ // We have an error and no more data
+ if d.current.err != nil {
+ break
+ }
+ if !d.nextBlock(n == 0) {
+ return n, d.current.err
+ }
+ }
+ }
+ if len(d.current.b) > 0 {
+ if debugDecoder {
+ println("returning", n, "still bytes left:", len(d.current.b))
+ }
+ // Only return error at end of block
+ return n, nil
+ }
+ if d.current.err != nil {
+ d.drainOutput()
+ }
+ if debugDecoder {
+ println("returning", n, d.current.err, len(d.decoders))
+ }
+ return n, d.current.err
+}
+
+// Reset will reset the decoder the supplied stream after the current has finished processing.
+// Note that this functionality cannot be used after Close has been called.
+// Reset can be called with a nil reader to release references to the previous reader.
+// After being called with a nil reader, no other operations than Reset or DecodeAll or Close
+// should be used.
+func (d *Decoder) Reset(r io.Reader) error {
+ if d.current.err == ErrDecoderClosed {
+ return d.current.err
+ }
+
+ d.drainOutput()
+
+ d.syncStream.br.r = nil
+ if r == nil {
+ d.current.err = ErrDecoderNilInput
+ if len(d.current.b) > 0 {
+ d.current.b = d.current.b[:0]
+ }
+ d.current.flushed = true
+ return nil
+ }
+
+ // If bytes buffer and < 5MB, do sync decoding anyway.
+ if bb, ok := r.(byter); ok && bb.Len() < d.o.decodeBufsBelow && !d.o.limitToCap {
+ bb2 := bb
+ if debugDecoder {
+ println("*bytes.Buffer detected, doing sync decode, len:", bb.Len())
+ }
+ b := bb2.Bytes()
+ var dst []byte
+ if cap(d.syncStream.dstBuf) > 0 {
+ dst = d.syncStream.dstBuf[:0]
+ }
+
+ dst, err := d.DecodeAll(b, dst)
+ if err == nil {
+ err = io.EOF
+ }
+ // Save output buffer
+ d.syncStream.dstBuf = dst
+ d.current.b = dst
+ d.current.err = err
+ d.current.flushed = true
+ if debugDecoder {
+ println("sync decode to", len(dst), "bytes, err:", err)
+ }
+ return nil
+ }
+ // Remove current block.
+ d.stashDecoder()
+ d.current.decodeOutput = decodeOutput{}
+ d.current.err = nil
+ d.current.flushed = false
+ d.current.d = nil
+ d.syncStream.dstBuf = nil
+
+ // Ensure no-one else is still running...
+ d.streamWg.Wait()
+ if d.frame == nil {
+ d.frame = newFrameDec(d.o)
+ }
+
+ if d.o.concurrent == 1 {
+ return d.startSyncDecoder(r)
+ }
+
+ d.current.output = make(chan decodeOutput, d.o.concurrent)
+ ctx, cancel := context.WithCancel(context.Background())
+ d.current.cancel = cancel
+ d.streamWg.Add(1)
+ go d.startStreamDecoder(ctx, r, d.current.output)
+
+ return nil
+}
+
+// ResetWithOptions will reset the decoder and apply the given options
+// for the next stream or DecodeAll operation.
+// Options are applied on top of the existing options.
+// Some options cannot be changed on reset and will return an error.
+func (d *Decoder) ResetWithOptions(r io.Reader, opts ...DOption) error {
+ d.o.resetOpt = true
+ defer func() { d.o.resetOpt = false }()
+ for _, o := range opts {
+ if err := o(&d.o); err != nil {
+ return err
+ }
+ }
+ return d.Reset(r)
+}
+
+// drainOutput will drain the output until errEndOfStream is sent.
+func (d *Decoder) drainOutput() {
+ if d.current.cancel != nil {
+ if debugDecoder {
+ println("cancelling current")
+ }
+ d.current.cancel()
+ d.current.cancel = nil
+ }
+ if d.current.d != nil {
+ if debugDecoder {
+ printf("re-adding current decoder %p, decoders: %d", d.current.d, len(d.decoders))
+ }
+ d.decoders <- d.current.d
+ d.current.d = nil
+ d.current.b = nil
+ }
+ if d.current.output == nil || d.current.flushed {
+ println("current already flushed")
+ return
+ }
+ for v := range d.current.output {
+ if v.d != nil {
+ if debugDecoder {
+ printf("re-adding decoder %p", v.d)
+ }
+ d.decoders <- v.d
+ }
+ }
+ d.current.output = nil
+ d.current.flushed = true
+}
+
+// WriteTo writes data to w until there's no more data to write or when an error occurs.
+// The return value n is the number of bytes written.
+// Any error encountered during the write is also returned.
+func (d *Decoder) WriteTo(w io.Writer) (int64, error) {
+ var n int64
+ for {
+ if len(d.current.b) > 0 {
+ n2, err2 := w.Write(d.current.b)
+ n += int64(n2)
+ if err2 != nil && (d.current.err == nil || d.current.err == io.EOF) {
+ d.current.err = err2
+ } else if n2 != len(d.current.b) {
+ d.current.err = io.ErrShortWrite
+ }
+ }
+ if d.current.err != nil {
+ break
+ }
+ d.nextBlock(true)
+ }
+ err := d.current.err
+ if err != nil {
+ d.drainOutput()
+ }
+ if err == io.EOF {
+ err = nil
+ }
+ return n, err
+}
+
+// DecodeAll allows stateless decoding of a blob of bytes.
+// Output will be appended to dst, so if the destination size is known
+// you can pre-allocate the destination slice to avoid allocations.
+// DecodeAll can be used concurrently.
+// The Decoder concurrency limits will be respected.
+func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
+ if d.decoders == nil {
+ return dst, ErrDecoderClosed
+ }
+
+ // Grab a block decoder and frame decoder.
+ block := <-d.decoders
+ frame := block.localFrame
+ initialSize := len(dst)
+ defer func() {
+ if debugDecoder {
+ printf("re-adding decoder: %p", block)
+ }
+ frame.rawInput = nil
+ frame.bBuf = nil
+ if frame.history.decoders.br != nil {
+ frame.history.decoders.br.in = nil
+ frame.history.decoders.br.cursor = 0
+ }
+ d.decoders <- block
+ }()
+ frame.bBuf = input
+
+ for {
+ frame.history.reset()
+ err := frame.reset(&frame.bBuf)
+ if err != nil {
+ if err == io.EOF {
+ if debugDecoder {
+ println("frame reset return EOF")
+ }
+ return dst, nil
+ }
+ return dst, err
+ }
+ if err = d.setDict(frame); err != nil {
+ return nil, err
+ }
+ if frame.WindowSize > d.o.maxWindowSize {
+ if debugDecoder {
+ println("window size exceeded:", frame.WindowSize, ">", d.o.maxWindowSize)
+ }
+ return dst, ErrWindowSizeExceeded
+ }
+ if frame.FrameContentSize != fcsUnknown {
+ if frame.FrameContentSize > d.o.maxDecodedSize-uint64(len(dst)-initialSize) {
+ if debugDecoder {
+ println("decoder size exceeded; fcs:", frame.FrameContentSize, "> mcs:", d.o.maxDecodedSize-uint64(len(dst)-initialSize), "len:", len(dst))
+ }
+ return dst, ErrDecoderSizeExceeded
+ }
+ if d.o.limitToCap && frame.FrameContentSize > uint64(cap(dst)-len(dst)) {
+ if debugDecoder {
+ println("decoder size exceeded; fcs:", frame.FrameContentSize, "> (cap-len)", cap(dst)-len(dst))
+ }
+ return dst, ErrDecoderSizeExceeded
+ }
+ if cap(dst)-len(dst) < int(frame.FrameContentSize) {
+ dst2 := make([]byte, len(dst), len(dst)+int(frame.FrameContentSize)+compressedBlockOverAlloc)
+ copy(dst2, dst)
+ dst = dst2
+ }
+ }
+
+ if cap(dst) == 0 && !d.o.limitToCap {
+ // Allocate len(input) * 2 by default if nothing is provided
+ // and we didn't get frame content size.
+ size := min(
+ // Cap to 1 MB.
+ len(input)*2, 1<<20)
+ if uint64(size) > d.o.maxDecodedSize {
+ size = int(d.o.maxDecodedSize)
+ }
+ dst = make([]byte, 0, size)
+ }
+
+ dst, err = frame.runDecoder(dst, block)
+ if err != nil {
+ return dst, err
+ }
+ if uint64(len(dst)-initialSize) > d.o.maxDecodedSize {
+ return dst, ErrDecoderSizeExceeded
+ }
+ if len(frame.bBuf) == 0 {
+ if debugDecoder {
+ println("frame dbuf empty")
+ }
+ break
+ }
+ }
+ return dst, nil
+}
+
+// nextBlock returns the next block.
+// If an error occurs d.err will be set.
+// Optionally the function can block for new output.
+// If non-blocking mode is used the returned boolean will be false
+// if no data was available without blocking.
+func (d *Decoder) nextBlock(blocking bool) (ok bool) {
+ if d.current.err != nil {
+ // Keep error state.
+ return false
+ }
+ d.current.b = d.current.b[:0]
+
+ // SYNC:
+ if d.syncStream.enabled {
+ if !blocking {
+ return false
+ }
+ ok = d.nextBlockSync()
+ if !ok {
+ d.stashDecoder()
+ }
+ return ok
+ }
+
+ //ASYNC:
+ d.stashDecoder()
+ if blocking {
+ d.current.decodeOutput, ok = <-d.current.output
+ } else {
+ select {
+ case d.current.decodeOutput, ok = <-d.current.output:
+ default:
+ return false
+ }
+ }
+ if !ok {
+ // This should not happen, so signal error state...
+ d.current.err = io.ErrUnexpectedEOF
+ return false
+ }
+ next := d.current.decodeOutput
+ if next.d != nil && next.d.async.newHist != nil {
+ d.current.crc.Reset()
+ }
+ if debugDecoder {
+ var tmp [4]byte
+ binary.LittleEndian.PutUint32(tmp[:], uint32(xxhash.Sum64(next.b)))
+ println("got", len(d.current.b), "bytes, error:", d.current.err, "data crc:", tmp)
+ }
+
+ if d.o.ignoreChecksum {
+ return true
+ }
+
+ if len(next.b) > 0 {
+ d.current.crc.Write(next.b)
+ }
+ if next.err == nil && next.d != nil && next.d.hasCRC {
+ got := uint32(d.current.crc.Sum64())
+ if got != next.d.checkCRC {
+ if debugDecoder {
+ printf("CRC Check Failed: %08x (got) != %08x (on stream)\n", got, next.d.checkCRC)
+ }
+ d.current.err = ErrCRCMismatch
+ } else {
+ if debugDecoder {
+ printf("CRC ok %08x\n", got)
+ }
+ }
+ }
+
+ return true
+}
+
+func (d *Decoder) nextBlockSync() (ok bool) {
+ if d.current.d == nil {
+ d.current.d = <-d.decoders
+ }
+ for len(d.current.b) == 0 {
+ if !d.syncStream.inFrame {
+ d.frame.history.reset()
+ d.current.err = d.frame.reset(&d.syncStream.br)
+ if d.current.err == nil {
+ d.current.err = d.setDict(d.frame)
+ }
+ if d.current.err != nil {
+ return false
+ }
+ if d.frame.WindowSize > d.o.maxDecodedSize || d.frame.WindowSize > d.o.maxWindowSize {
+ d.current.err = ErrDecoderSizeExceeded
+ return false
+ }
+
+ d.syncStream.decodedFrame = 0
+ d.syncStream.inFrame = true
+ }
+ d.current.err = d.frame.next(d.current.d)
+ if d.current.err != nil {
+ return false
+ }
+ d.frame.history.ensureBlock()
+ if debugDecoder {
+ println("History trimmed:", len(d.frame.history.b), "decoded already:", d.syncStream.decodedFrame)
+ }
+ histBefore := len(d.frame.history.b)
+ d.current.err = d.current.d.decodeBuf(&d.frame.history)
+
+ if d.current.err != nil {
+ println("error after:", d.current.err)
+ return false
+ }
+ d.current.b = d.frame.history.b[histBefore:]
+ if debugDecoder {
+ println("history after:", len(d.frame.history.b))
+ }
+
+ // Check frame size (before CRC)
+ d.syncStream.decodedFrame += uint64(len(d.current.b))
+ if d.syncStream.decodedFrame > d.frame.FrameContentSize {
+ if debugDecoder {
+ printf("DecodedFrame (%d) > FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize)
+ }
+ d.current.err = ErrFrameSizeExceeded
+ return false
+ }
+
+ // Check FCS
+ if d.current.d.Last && d.frame.FrameContentSize != fcsUnknown && d.syncStream.decodedFrame != d.frame.FrameContentSize {
+ if debugDecoder {
+ printf("DecodedFrame (%d) != FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize)
+ }
+ d.current.err = ErrFrameSizeMismatch
+ return false
+ }
+
+ // Update/Check CRC
+ if d.frame.HasCheckSum {
+ if !d.o.ignoreChecksum {
+ d.frame.crc.Write(d.current.b)
+ }
+ if d.current.d.Last {
+ if !d.o.ignoreChecksum {
+ d.current.err = d.frame.checkCRC()
+ } else {
+ d.current.err = d.frame.consumeCRC()
+ }
+ if d.current.err != nil {
+ println("CRC error:", d.current.err)
+ return false
+ }
+ }
+ }
+ d.syncStream.inFrame = !d.current.d.Last
+ }
+ return true
+}
+
+func (d *Decoder) stashDecoder() {
+ if d.current.d != nil {
+ if debugDecoder {
+ printf("re-adding current decoder %p", d.current.d)
+ }
+ d.decoders <- d.current.d
+ d.current.d = nil
+ }
+}
+
+// Close will release all resources.
+// It is NOT possible to reuse the decoder after this.
+func (d *Decoder) Close() {
+ if d.current.err == ErrDecoderClosed {
+ return
+ }
+ d.drainOutput()
+ if d.current.cancel != nil {
+ d.current.cancel()
+ d.streamWg.Wait()
+ d.current.cancel = nil
+ }
+ if d.decoders != nil {
+ close(d.decoders)
+ for dec := range d.decoders {
+ dec.Close()
+ }
+ d.decoders = nil
+ }
+ if d.current.d != nil {
+ d.current.d.Close()
+ d.current.d = nil
+ }
+ d.current.err = ErrDecoderClosed
+}
+
+// IOReadCloser returns the decoder as an io.ReadCloser for convenience.
+// Any changes to the decoder will be reflected, so the returned ReadCloser
+// can be reused along with the decoder.
+// io.WriterTo is also supported by the returned ReadCloser.
+func (d *Decoder) IOReadCloser() io.ReadCloser {
+ return closeWrapper{d: d}
+}
+
+// closeWrapper wraps a function call as a closer.
+type closeWrapper struct {
+ d *Decoder
+}
+
+// WriteTo forwards WriteTo calls to the decoder.
+func (c closeWrapper) WriteTo(w io.Writer) (n int64, err error) {
+ return c.d.WriteTo(w)
+}
+
+// Read forwards read calls to the decoder.
+func (c closeWrapper) Read(p []byte) (n int, err error) {
+ return c.d.Read(p)
+}
+
+// Close closes the decoder.
+func (c closeWrapper) Close() error {
+ c.d.Close()
+ return nil
+}
+
+type decodeOutput struct {
+ d *blockDec
+ b []byte
+ err error
+}
+
+func (d *Decoder) startSyncDecoder(r io.Reader) error {
+ d.frame.history.reset()
+ d.syncStream.br = readerWrapper{r: r}
+ d.syncStream.inFrame = false
+ d.syncStream.enabled = true
+ d.syncStream.decodedFrame = 0
+ return nil
+}
+
+// Create Decoder:
+// ASYNC:
+// Spawn 3 go routines.
+// 0: Read frames and decode block literals.
+// 1: Decode sequences.
+// 2: Execute sequences, send to output.
+func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output chan decodeOutput) {
+ defer d.streamWg.Done()
+ br := readerWrapper{r: r}
+
+ var seqDecode = make(chan *blockDec, d.o.concurrent)
+ var seqExecute = make(chan *blockDec, d.o.concurrent)
+
+ // Async 1: Decode sequences...
+ go func() {
+ var hist history
+ var hasErr bool
+
+ for block := range seqDecode {
+ if hasErr {
+ if block != nil {
+ seqExecute <- block
+ }
+ continue
+ }
+ if block.async.newHist != nil {
+ if debugDecoder {
+ println("Async 1: new history, recent:", block.async.newHist.recentOffsets)
+ }
+ hist.reset()
+ hist.decoders = block.async.newHist.decoders
+ hist.recentOffsets = block.async.newHist.recentOffsets
+ hist.windowSize = block.async.newHist.windowSize
+ if block.async.newHist.dict != nil {
+ hist.setDict(block.async.newHist.dict)
+ }
+ }
+ if block.err != nil || block.Type != blockTypeCompressed {
+ hasErr = block.err != nil
+ seqExecute <- block
+ continue
+ }
+
+ hist.decoders.literals = block.async.literals
+ block.err = block.prepareSequences(block.async.seqData, &hist)
+ if debugDecoder && block.err != nil {
+ println("prepareSequences returned:", block.err)
+ }
+ hasErr = block.err != nil
+ if block.err == nil {
+ block.err = block.decodeSequences(&hist)
+ if debugDecoder && block.err != nil {
+ println("decodeSequences returned:", block.err)
+ }
+ hasErr = block.err != nil
+ // block.async.sequence = hist.decoders.seq[:hist.decoders.nSeqs]
+ block.async.seqSize = hist.decoders.seqSize
+ }
+ seqExecute <- block
+ }
+ close(seqExecute)
+ hist.reset()
+ }()
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ // Async 3: Execute sequences...
+ frameHistCache := d.frame.history.b
+ go func() {
+ var hist history
+ var decodedFrame uint64
+ var fcs uint64
+ var hasErr bool
+ for block := range seqExecute {
+ out := decodeOutput{err: block.err, d: block}
+ if block.err != nil || hasErr {
+ hasErr = true
+ output <- out
+ continue
+ }
+ if block.async.newHist != nil {
+ if debugDecoder {
+ println("Async 2: new history")
+ }
+ hist.reset()
+ hist.windowSize = block.async.newHist.windowSize
+ hist.allocFrameBuffer = block.async.newHist.allocFrameBuffer
+ if block.async.newHist.dict != nil {
+ hist.setDict(block.async.newHist.dict)
+ }
+
+ if cap(hist.b) < hist.allocFrameBuffer {
+ if cap(frameHistCache) >= hist.allocFrameBuffer {
+ hist.b = frameHistCache
+ } else {
+ hist.b = make([]byte, 0, hist.allocFrameBuffer)
+ println("Alloc history sized", hist.allocFrameBuffer)
+ }
+ }
+ hist.b = hist.b[:0]
+ fcs = block.async.fcs
+ decodedFrame = 0
+ }
+ do := decodeOutput{err: block.err, d: block}
+ switch block.Type {
+ case blockTypeRLE:
+ if debugDecoder {
+ println("add rle block length:", block.RLESize)
+ }
+
+ if cap(block.dst) < int(block.RLESize) {
+ if block.lowMem {
+ block.dst = make([]byte, block.RLESize)
+ } else {
+ block.dst = make([]byte, maxCompressedBlockSize)
+ }
+ }
+ block.dst = block.dst[:block.RLESize]
+ v := block.data[0]
+ for i := range block.dst {
+ block.dst[i] = v
+ }
+ hist.append(block.dst)
+ do.b = block.dst
+ case blockTypeRaw:
+ if debugDecoder {
+ println("add raw block length:", len(block.data))
+ }
+ hist.append(block.data)
+ do.b = block.data
+ case blockTypeCompressed:
+ if debugDecoder {
+ println("execute with history length:", len(hist.b), "window:", hist.windowSize)
+ }
+ hist.decoders.seqSize = block.async.seqSize
+ hist.decoders.literals = block.async.literals
+ do.err = block.executeSequences(&hist)
+ hasErr = do.err != nil
+ if debugDecoder && hasErr {
+ println("executeSequences returned:", do.err)
+ }
+ do.b = block.dst
+ }
+ if !hasErr {
+ decodedFrame += uint64(len(do.b))
+ if decodedFrame > fcs {
+ println("fcs exceeded", block.Last, fcs, decodedFrame)
+ do.err = ErrFrameSizeExceeded
+ hasErr = true
+ } else if block.Last && fcs != fcsUnknown && decodedFrame != fcs {
+ do.err = ErrFrameSizeMismatch
+ hasErr = true
+ } else {
+ if debugDecoder {
+ println("fcs ok", block.Last, fcs, decodedFrame)
+ }
+ }
+ }
+ output <- do
+ }
+ close(output)
+ frameHistCache = hist.b
+ wg.Done()
+ if debugDecoder {
+ println("decoder goroutines finished")
+ }
+ hist.reset()
+ }()
+
+ var hist history
+decodeStream:
+ for {
+ var hasErr bool
+ hist.reset()
+ decodeBlock := func(block *blockDec) {
+ if hasErr {
+ if block != nil {
+ seqDecode <- block
+ }
+ return
+ }
+ if block.err != nil || block.Type != blockTypeCompressed {
+ hasErr = block.err != nil
+ seqDecode <- block
+ return
+ }
+
+ remain, err := block.decodeLiterals(block.data, &hist)
+ block.err = err
+ hasErr = block.err != nil
+ if err == nil {
+ block.async.literals = hist.decoders.literals
+ block.async.seqData = remain
+ } else if debugDecoder {
+ println("decodeLiterals error:", err)
+ }
+ seqDecode <- block
+ }
+ frame := d.frame
+ if debugDecoder {
+ println("New frame...")
+ }
+ var historySent bool
+ frame.history.reset()
+ err := frame.reset(&br)
+ if debugDecoder && err != nil {
+ println("Frame decoder returned", err)
+ }
+ if err == nil {
+ err = d.setDict(frame)
+ }
+ if err == nil && d.frame.WindowSize > d.o.maxWindowSize {
+ if debugDecoder {
+ println("decoder size exceeded, fws:", d.frame.WindowSize, "> mws:", d.o.maxWindowSize)
+ }
+
+ err = ErrDecoderSizeExceeded
+ }
+ if err != nil {
+ select {
+ case <-ctx.Done():
+ case dec := <-d.decoders:
+ dec.sendErr(err)
+ decodeBlock(dec)
+ }
+ break decodeStream
+ }
+
+ // Go through all blocks of the frame.
+ for {
+ var dec *blockDec
+ select {
+ case <-ctx.Done():
+ break decodeStream
+ case dec = <-d.decoders:
+ // Once we have a decoder, we MUST return it.
+ }
+ err := frame.next(dec)
+ if !historySent {
+ h := frame.history
+ if debugDecoder {
+ println("Alloc History:", h.allocFrameBuffer)
+ }
+ hist.reset()
+ if h.dict != nil {
+ hist.setDict(h.dict)
+ }
+ dec.async.newHist = &h
+ dec.async.fcs = frame.FrameContentSize
+ historySent = true
+ } else {
+ dec.async.newHist = nil
+ }
+ if debugDecoder && err != nil {
+ println("next block returned error:", err)
+ }
+ dec.err = err
+ dec.hasCRC = false
+ if dec.Last && frame.HasCheckSum && err == nil {
+ crc, err := frame.rawInput.readSmall(4)
+ if len(crc) < 4 {
+ if err == nil {
+ err = io.ErrUnexpectedEOF
+
+ }
+ println("CRC missing?", err)
+ dec.err = err
+ } else {
+ dec.checkCRC = binary.LittleEndian.Uint32(crc)
+ dec.hasCRC = true
+ if debugDecoder {
+ printf("found crc to check: %08x\n", dec.checkCRC)
+ }
+ }
+ }
+ err = dec.err
+ last := dec.Last
+ decodeBlock(dec)
+ if err != nil {
+ break decodeStream
+ }
+ if last {
+ break
+ }
+ }
+ }
+ close(seqDecode)
+ wg.Wait()
+ hist.reset()
+ d.frame.history.b = frameHistCache
+}
+
+func (d *Decoder) setDict(frame *frameDec) (err error) {
+ dict, ok := d.o.dicts[frame.DictionaryID]
+ if ok {
+ if debugDecoder {
+ println("setting dict", frame.DictionaryID)
+ }
+ frame.history.setDict(dict)
+ } else if frame.DictionaryID != 0 {
+ // A zero or missing dictionary id is ambiguous:
+ // either dictionary zero, or no dictionary. In particular,
+ // zstd --patch-from uses this id for the source file,
+ // so only return an error if the dictionary id is not zero.
+ err = ErrUnknownDictionary
+ }
+ return err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder_options.go b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
new file mode 100644
index 00000000..537627a0
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/decoder_options.go
@@ -0,0 +1,213 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math/bits"
+ "runtime"
+)
+
+// DOption is an option for creating a decoder.
+type DOption func(*decoderOptions) error
+
+// options retains accumulated state of multiple options.
+type decoderOptions struct {
+ lowMem bool
+ concurrent int
+ maxDecodedSize uint64
+ maxWindowSize uint64
+ dicts map[uint32]*dict
+ ignoreChecksum bool
+ limitToCap bool
+ decodeBufsBelow int
+ resetOpt bool
+}
+
+func (o *decoderOptions) setDefault() {
+ *o = decoderOptions{
+ // use less ram: true for now, but may change.
+ lowMem: true,
+ concurrent: runtime.GOMAXPROCS(0),
+ maxWindowSize: MaxWindowSize,
+ decodeBufsBelow: 128 << 10,
+ }
+ if o.concurrent > 4 {
+ o.concurrent = 4
+ }
+ o.maxDecodedSize = 64 << 30
+}
+
+// WithDecoderLowmem will set whether to use a lower amount of memory,
+// but possibly have to allocate more while running.
+// Cannot be changed with ResetWithOptions.
+func WithDecoderLowmem(b bool) DOption {
+ return func(o *decoderOptions) error {
+ if o.resetOpt && b != o.lowMem {
+ return errors.New("WithDecoderLowmem cannot be changed on Reset")
+ }
+ o.lowMem = b
+ return nil
+ }
+}
+
+// WithDecoderConcurrency sets the number of created decoders.
+// When decoding block with DecodeAll, this will limit the number
+// of possible concurrently running decodes.
+// When decoding streams, this will limit the number of
+// inflight blocks.
+// When decoding streams and setting maximum to 1,
+// no async decoding will be done.
+// The value supplied must be at least 0.
+// When a value of 0 is provided GOMAXPROCS will be used.
+// By default this will be set to 4 or GOMAXPROCS, whatever is lower.
+// Cannot be changed with ResetWithOptions.
+func WithDecoderConcurrency(n int) DOption {
+ return func(o *decoderOptions) error {
+ if n < 0 {
+ return errors.New("concurrency must be at least 0")
+ }
+ newVal := n
+ if n == 0 {
+ newVal = runtime.GOMAXPROCS(0)
+ }
+ if o.resetOpt && newVal != o.concurrent {
+ return errors.New("WithDecoderConcurrency cannot be changed on Reset")
+ }
+ o.concurrent = newVal
+ return nil
+ }
+}
+
+// WithDecoderMaxMemory allows to set a maximum decoded size for in-memory
+// non-streaming operations or maximum window size for streaming operations.
+// This can be used to control memory usage of potentially hostile content.
+// Maximum is 1 << 63 bytes. Default is 64GiB.
+// Can be changed with ResetWithOptions.
+func WithDecoderMaxMemory(n uint64) DOption {
+ return func(o *decoderOptions) error {
+ if n == 0 {
+ return errors.New("WithDecoderMaxMemory must be at least 1")
+ }
+ if n > 1<<63 {
+ return errors.New("WithDecoderMaxmemory must be less than 1 << 63")
+ }
+ o.maxDecodedSize = n
+ return nil
+ }
+}
+
+// WithDecoderDicts allows to register one or more dictionaries for the decoder.
+//
+// Each slice in dict must be in the [dictionary format] produced by
+// "zstd --train" from the Zstandard reference implementation.
+//
+// If several dictionaries with the same ID are provided, the last one will be used.
+// Can be changed with ResetWithOptions.
+//
+// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
+func WithDecoderDicts(dicts ...[]byte) DOption {
+ return func(o *decoderOptions) error {
+ if o.dicts == nil {
+ o.dicts = make(map[uint32]*dict)
+ }
+ for _, b := range dicts {
+ d, err := loadDict(b)
+ if err != nil {
+ return err
+ }
+ o.dicts[d.id] = d
+ }
+ return nil
+ }
+}
+
+// WithDecoderDictRaw registers a dictionary that may be used by the decoder.
+// The slice content can be arbitrary data.
+// Can be changed with ResetWithOptions.
+func WithDecoderDictRaw(id uint32, content []byte) DOption {
+ return func(o *decoderOptions) error {
+ if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
+ return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
+ }
+ if o.dicts == nil {
+ o.dicts = make(map[uint32]*dict)
+ }
+ o.dicts[id] = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}}
+ return nil
+ }
+}
+
+// WithDecoderMaxWindow allows to set a maximum window size for decodes.
+// This allows rejecting packets that will cause big memory usage.
+// The Decoder will likely allocate more memory based on the WithDecoderLowmem setting.
+// If WithDecoderMaxMemory is set to a lower value, that will be used.
+// Default is 512MB, Maximum is ~3.75 TB as per zstandard spec.
+// Can be changed with ResetWithOptions.
+func WithDecoderMaxWindow(size uint64) DOption {
+ return func(o *decoderOptions) error {
+ if size < MinWindowSize {
+ return errors.New("WithMaxWindowSize must be at least 1KB, 1024 bytes")
+ }
+ if size > (1<<41)+7*(1<<38) {
+ return errors.New("WithMaxWindowSize must be less than (1<<41) + 7*(1<<38) ~ 3.75TB")
+ }
+ o.maxWindowSize = size
+ return nil
+ }
+}
+
+// WithDecodeAllCapLimit will limit DecodeAll to decoding cap(dst)-len(dst) bytes,
+// or any size set in WithDecoderMaxMemory.
+// This can be used to limit decoding to a specific maximum output size.
+// Disabled by default.
+// Can be changed with ResetWithOptions.
+func WithDecodeAllCapLimit(b bool) DOption {
+ return func(o *decoderOptions) error {
+ o.limitToCap = b
+ return nil
+ }
+}
+
+// WithDecodeBuffersBelow will fully decode readers that have a
+// `Bytes() []byte` and `Len() int` interface similar to bytes.Buffer.
+// This typically uses less allocations but will have the full decompressed object in memory.
+// Note that DecodeAllCapLimit will disable this, as well as giving a size of 0 or less.
+// Default is 128KiB.
+// Cannot be changed with ResetWithOptions.
+func WithDecodeBuffersBelow(size int) DOption {
+ return func(o *decoderOptions) error {
+ if o.resetOpt && size != o.decodeBufsBelow {
+ return errors.New("WithDecodeBuffersBelow cannot be changed on Reset")
+ }
+ o.decodeBufsBelow = size
+ return nil
+ }
+}
+
+// IgnoreChecksum allows to forcibly ignore checksum checking.
+// Can be changed with ResetWithOptions.
+func IgnoreChecksum(b bool) DOption {
+ return func(o *decoderOptions) error {
+ o.ignoreChecksum = b
+ return nil
+ }
+}
+
+// WithDecoderDictDelete removes dictionaries by ID.
+// If no ids are passed, all dictionaries are deleted.
+// Should be used with ResetWithOptions.
+func WithDecoderDictDelete(ids ...uint32) DOption {
+ return func(o *decoderOptions) error {
+ if len(ids) == 0 {
+ clear(o.dicts)
+ }
+ for _, id := range ids {
+ delete(o.dicts, id)
+ }
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go
new file mode 100644
index 00000000..2ffbfdf3
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/dict.go
@@ -0,0 +1,559 @@
+package zstd
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "sort"
+
+ "github.com/klauspost/compress/huff0"
+)
+
+type dict struct {
+ id uint32
+
+ litEnc *huff0.Scratch
+ llDec, ofDec, mlDec sequenceDec
+ offsets [3]int
+ content []byte
+}
+
+const dictMagic = "\x37\xa4\x30\xec"
+
+// Maximum dictionary size for the reference implementation (1.5.3) is 2 GiB.
+const dictMaxLength = 1 << 31
+
+// ID returns the dictionary id or 0 if d is nil.
+func (d *dict) ID() uint32 {
+ if d == nil {
+ return 0
+ }
+ return d.id
+}
+
+// ContentSize returns the dictionary content size or 0 if d is nil.
+func (d *dict) ContentSize() int {
+ if d == nil {
+ return 0
+ }
+ return len(d.content)
+}
+
+// Content returns the dictionary content.
+func (d *dict) Content() []byte {
+ if d == nil {
+ return nil
+ }
+ return d.content
+}
+
+// Offsets returns the initial offsets.
+func (d *dict) Offsets() [3]int {
+ if d == nil {
+ return [3]int{}
+ }
+ return d.offsets
+}
+
+// LitEncoder returns the literal encoder.
+func (d *dict) LitEncoder() *huff0.Scratch {
+ if d == nil {
+ return nil
+ }
+ return d.litEnc
+}
+
+// Load a dictionary as described in
+// https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
+func loadDict(b []byte) (*dict, error) {
+ // Check static field size.
+ if len(b) <= 8+(3*4) {
+ return nil, io.ErrUnexpectedEOF
+ }
+ d := dict{
+ llDec: sequenceDec{fse: &fseDecoder{}},
+ ofDec: sequenceDec{fse: &fseDecoder{}},
+ mlDec: sequenceDec{fse: &fseDecoder{}},
+ }
+ if string(b[:4]) != dictMagic {
+ return nil, ErrMagicMismatch
+ }
+ d.id = binary.LittleEndian.Uint32(b[4:8])
+ if d.id == 0 {
+ return nil, errors.New("dictionaries cannot have ID 0")
+ }
+
+ // Read literal table
+ var err error
+ d.litEnc, b, err = huff0.ReadTable(b[8:], nil)
+ if err != nil {
+ return nil, fmt.Errorf("loading literal table: %w", err)
+ }
+ d.litEnc.Reuse = huff0.ReusePolicyMust
+
+ br := byteReader{
+ b: b,
+ off: 0,
+ }
+ readDec := func(i tableIndex, dec *fseDecoder) error {
+ if err := dec.readNCount(&br, uint16(maxTableSymbol[i])); err != nil {
+ return err
+ }
+ if br.overread() {
+ return io.ErrUnexpectedEOF
+ }
+ err = dec.transform(symbolTableX[i])
+ if err != nil {
+ println("Transform table error:", err)
+ return err
+ }
+ if debugDecoder || debugEncoder {
+ println("Read table ok", "symbolLen:", dec.symbolLen)
+ }
+ // Set decoders as predefined so they aren't reused.
+ dec.preDefined = true
+ return nil
+ }
+
+ if err := readDec(tableOffsets, d.ofDec.fse); err != nil {
+ return nil, err
+ }
+ if err := readDec(tableMatchLengths, d.mlDec.fse); err != nil {
+ return nil, err
+ }
+ if err := readDec(tableLiteralLengths, d.llDec.fse); err != nil {
+ return nil, err
+ }
+ if br.remain() < 12 {
+ return nil, io.ErrUnexpectedEOF
+ }
+
+ d.offsets[0] = int(br.Uint32())
+ br.advance(4)
+ d.offsets[1] = int(br.Uint32())
+ br.advance(4)
+ d.offsets[2] = int(br.Uint32())
+ br.advance(4)
+ if d.offsets[0] <= 0 || d.offsets[1] <= 0 || d.offsets[2] <= 0 {
+ return nil, errors.New("invalid offset in dictionary")
+ }
+ d.content = make([]byte, br.remain())
+ copy(d.content, br.unread())
+ if d.offsets[0] > len(d.content) || d.offsets[1] > len(d.content) || d.offsets[2] > len(d.content) {
+ return nil, fmt.Errorf("initial offset bigger than dictionary content size %d, offsets: %v", len(d.content), d.offsets)
+ }
+
+ return &d, nil
+}
+
+// InspectDictionary loads a zstd dictionary and provides functions to inspect the content.
+func InspectDictionary(b []byte) (interface {
+ ID() uint32
+ ContentSize() int
+ Content() []byte
+ Offsets() [3]int
+ LitEncoder() *huff0.Scratch
+}, error) {
+ initPredefined()
+ d, err := loadDict(b)
+ return d, err
+}
+
+type BuildDictOptions struct {
+ // Dictionary ID.
+ ID uint32
+
+ // Content to use to create dictionary tables.
+ Contents [][]byte
+
+ // History to use for all blocks.
+ History []byte
+
+ // Offsets to use.
+ Offsets [3]int
+
+ // CompatV155 will make the dictionary compatible with Zstd v1.5.5 and earlier.
+ // See https://github.com/facebook/zstd/issues/3724
+ CompatV155 bool
+
+ // Use the specified encoder level.
+ // The dictionary will be built using the specified encoder level,
+ // which will reflect speed and make the dictionary tailored for that level.
+ // If not set SpeedBestCompression will be used.
+ Level EncoderLevel
+
+ // DebugOut will write stats and other details here if set.
+ DebugOut io.Writer
+}
+
+func BuildDict(o BuildDictOptions) ([]byte, error) {
+ initPredefined()
+ hist := o.History
+ contents := o.Contents
+ debug := o.DebugOut != nil
+ println := func(args ...any) {
+ if o.DebugOut != nil {
+ fmt.Fprintln(o.DebugOut, args...)
+ }
+ }
+ printf := func(s string, args ...any) {
+ if o.DebugOut != nil {
+ fmt.Fprintf(o.DebugOut, s, args...)
+ }
+ }
+ print := func(args ...any) {
+ if o.DebugOut != nil {
+ fmt.Fprint(o.DebugOut, args...)
+ }
+ }
+
+ if int64(len(hist)) > dictMaxLength {
+ return nil, fmt.Errorf("dictionary of size %d > %d", len(hist), int64(dictMaxLength))
+ }
+ if len(hist) < 8 {
+ return nil, fmt.Errorf("dictionary of size %d < %d", len(hist), 8)
+ }
+ if len(contents) == 0 {
+ return nil, errors.New("no content provided")
+ }
+ d := dict{
+ id: o.ID,
+ litEnc: nil,
+ llDec: sequenceDec{},
+ ofDec: sequenceDec{},
+ mlDec: sequenceDec{},
+ offsets: o.Offsets,
+ content: hist,
+ }
+ block := blockEnc{lowMem: false}
+ block.init()
+ enc := encoder(&bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(maxMatchLen), bufferReset: math.MaxInt32 - int32(maxMatchLen*2), lowMem: false}})
+ if o.Level != 0 {
+ eOpts := encoderOptions{
+ level: o.Level,
+ blockSize: maxMatchLen,
+ windowSize: maxMatchLen,
+ dict: &d,
+ lowMem: false,
+ }
+ enc = eOpts.encoder()
+ } else {
+ o.Level = SpeedBestCompression
+ }
+ var (
+ remain [256]int
+ ll [256]int
+ ml [256]int
+ of [256]int
+ )
+ addValues := func(dst *[256]int, src []byte) {
+ for _, v := range src {
+ dst[v]++
+ }
+ }
+ addHist := func(dst *[256]int, src *[256]uint32) {
+ for i, v := range src {
+ dst[i] += int(v)
+ }
+ }
+ seqs := 0
+ nUsed := 0
+ litTotal := 0
+ newOffsets := make(map[uint32]int, 1000)
+ for _, b := range contents {
+ block.reset(nil)
+ if len(b) < 8 {
+ continue
+ }
+ nUsed++
+ enc.Reset(&d, true)
+ enc.Encode(&block, b)
+ addValues(&remain, block.literals)
+ litTotal += len(block.literals)
+ if len(block.sequences) == 0 {
+ continue
+ }
+ seqs += len(block.sequences)
+ block.genCodes()
+ addHist(&ll, block.coders.llEnc.Histogram())
+ addHist(&ml, block.coders.mlEnc.Histogram())
+ addHist(&of, block.coders.ofEnc.Histogram())
+ for i, seq := range block.sequences {
+ if i > 3 {
+ break
+ }
+ offset := seq.offset
+ if offset == 0 {
+ continue
+ }
+ if int(offset) >= len(o.History) {
+ continue
+ }
+ if offset > 3 {
+ newOffsets[offset-3]++
+ } else {
+ newOffsets[uint32(o.Offsets[offset-1])]++
+ }
+ }
+ }
+ // Find most used offsets.
+ var sortedOffsets []uint32
+ for k := range newOffsets {
+ sortedOffsets = append(sortedOffsets, k)
+ }
+ sort.Slice(sortedOffsets, func(i, j int) bool {
+ a, b := sortedOffsets[i], sortedOffsets[j]
+ if a == b {
+ // Prefer the longer offset
+ return sortedOffsets[i] > sortedOffsets[j]
+ }
+ return newOffsets[sortedOffsets[i]] > newOffsets[sortedOffsets[j]]
+ })
+ if len(sortedOffsets) > 3 {
+ if debug {
+ print("Offsets:")
+ for i, v := range sortedOffsets {
+ if i > 20 {
+ break
+ }
+ printf("[%d: %d],", v, newOffsets[v])
+ }
+ println("")
+ }
+
+ sortedOffsets = sortedOffsets[:3]
+ }
+ for i, v := range sortedOffsets {
+ o.Offsets[i] = int(v)
+ }
+ if debug {
+ println("New repeat offsets", o.Offsets)
+ }
+
+ if nUsed == 0 || seqs == 0 {
+ return nil, fmt.Errorf("%d blocks, %d sequences found", nUsed, seqs)
+ }
+ if debug {
+ println("Sequences:", seqs, "Blocks:", nUsed, "Literals:", litTotal)
+ }
+ if seqs/nUsed < 512 {
+ // Use 512 as minimum.
+ nUsed = seqs / 512
+ if nUsed == 0 {
+ nUsed = 1
+ }
+ }
+ copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) {
+ hist := dst.Histogram()
+ var maxSym uint8
+ var maxCount int
+ var fakeLength int
+ for i, v := range src {
+ if v > 0 {
+ v = v / nUsed
+ if v == 0 {
+ v = 1
+ }
+ }
+ if v > maxCount {
+ maxCount = v
+ }
+ if v != 0 {
+ maxSym = uint8(i)
+ }
+ fakeLength += v
+ hist[i] = uint32(v)
+ }
+
+ // Ensure we aren't trying to represent RLE.
+ if maxCount == fakeLength {
+ for i := range hist {
+ if uint8(i) == maxSym {
+ fakeLength++
+ maxSym++
+ hist[i+1] = 1
+ if maxSym > 1 {
+ break
+ }
+ }
+ if hist[0] == 0 {
+ fakeLength++
+ hist[i] = 1
+ if maxSym > 1 {
+ break
+ }
+ }
+ }
+ }
+
+ dst.HistogramFinished(maxSym, maxCount)
+ dst.reUsed = false
+ dst.useRLE = false
+ err := dst.normalizeCount(fakeLength)
+ if err != nil {
+ return nil, err
+ }
+ if debug {
+ println("RAW:", dst.count[:maxSym+1], "NORM:", dst.norm[:maxSym+1], "LEN:", fakeLength)
+ }
+ return dst.writeCount(nil)
+ }
+ if debug {
+ print("Literal lengths: ")
+ }
+ llTable, err := copyHist(block.coders.llEnc, &ll)
+ if err != nil {
+ return nil, err
+ }
+ if debug {
+ print("Match lengths: ")
+ }
+ mlTable, err := copyHist(block.coders.mlEnc, &ml)
+ if err != nil {
+ return nil, err
+ }
+ if debug {
+ print("Offsets: ")
+ }
+ ofTable, err := copyHist(block.coders.ofEnc, &of)
+ if err != nil {
+ return nil, err
+ }
+
+ // Literal table
+ avgSize := min(litTotal, huff0.BlockSizeMax/2)
+ huffBuff := make([]byte, 0, avgSize)
+ // Target size
+ div := max(litTotal/avgSize, 1)
+ if debug {
+ println("Huffman weights:")
+ }
+ for i, n := range remain[:] {
+ if n > 0 {
+ n = n / div
+ // Allow all entries to be represented.
+ if n == 0 {
+ n = 1
+ }
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
+ if debug {
+ printf("[%d: %d], ", i, n)
+ }
+ }
+ }
+ if o.CompatV155 && remain[255]/div == 0 {
+ huffBuff = append(huffBuff, 255)
+ }
+ scratch := &huff0.Scratch{TableLog: 11}
+ for tries := range 255 {
+ scratch = &huff0.Scratch{TableLog: 11}
+ _, _, err = huff0.Compress1X(huffBuff, scratch)
+ if err == nil {
+ break
+ }
+ if debug {
+ printf("Try %d: Huffman error: %v\n", tries+1, err)
+ }
+ huffBuff = huffBuff[:0]
+ if tries == 250 {
+ if debug {
+ println("Huffman: Bailing out with predefined table")
+ }
+
+ // Bail out.... Just generate something
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{255}, 10000)...)
+ for i := range 128 {
+ huffBuff = append(huffBuff, byte(i))
+ }
+ continue
+ }
+ if errors.Is(err, huff0.ErrIncompressible) {
+ // Try truncating least common.
+ for i, n := range remain[:] {
+ if n > 0 {
+ n = n / (div * (i + 1))
+ if n > 0 {
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
+ }
+ }
+ }
+ if o.CompatV155 && len(huffBuff) > 0 && huffBuff[len(huffBuff)-1] != 255 {
+ huffBuff = append(huffBuff, 255)
+ }
+ if len(huffBuff) == 0 {
+ huffBuff = append(huffBuff, 0, 255)
+ }
+ }
+ if errors.Is(err, huff0.ErrUseRLE) {
+ for i, n := range remain[:] {
+ n = n / (div * (i + 1))
+ // Allow all entries to be represented.
+ if n == 0 {
+ n = 1
+ }
+ huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...)
+ }
+ }
+ }
+
+ var out bytes.Buffer
+ out.Write([]byte(dictMagic))
+ out.Write(binary.LittleEndian.AppendUint32(nil, o.ID))
+ out.Write(scratch.OutTable)
+ if debug {
+ println("huff table:", len(scratch.OutTable), "bytes")
+ println("of table:", len(ofTable), "bytes")
+ println("ml table:", len(mlTable), "bytes")
+ println("ll table:", len(llTable), "bytes")
+ }
+ out.Write(ofTable)
+ out.Write(mlTable)
+ out.Write(llTable)
+ out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[0])))
+ out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[1])))
+ out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[2])))
+ out.Write(hist)
+ if debug {
+ _, err := loadDict(out.Bytes())
+ if err != nil {
+ panic(err)
+ }
+ i, err := InspectDictionary(out.Bytes())
+ if err != nil {
+ panic(err)
+ }
+ println("ID:", i.ID())
+ println("Content size:", i.ContentSize())
+ println("Encoder:", i.LitEncoder() != nil)
+ println("Offsets:", i.Offsets())
+ var totalSize int
+ for _, b := range contents {
+ totalSize += len(b)
+ }
+
+ encWith := func(opts ...EOption) int {
+ enc, err := NewWriter(nil, opts...)
+ if err != nil {
+ panic(err)
+ }
+ defer enc.Close()
+ var dst []byte
+ var totalSize int
+ for _, b := range contents {
+ dst = enc.EncodeAll(b, dst[:0])
+ totalSize += len(dst)
+ }
+ return totalSize
+ }
+ plain := encWith(WithEncoderLevel(o.Level))
+ withDict := encWith(WithEncoderLevel(o.Level), WithEncoderDict(out.Bytes()))
+ println("Input size:", totalSize)
+ println("Plain Compressed:", plain)
+ println("Dict Compressed:", withDict)
+ println("Saved:", plain-withDict, (plain-withDict)/len(contents), "bytes per input (rounded down)")
+ }
+ return out.Bytes(), nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_base.go b/vendor/github.com/klauspost/compress/zstd/enc_base.go
new file mode 100644
index 00000000..c4de134a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_base.go
@@ -0,0 +1,171 @@
+package zstd
+
+import (
+ "fmt"
+ "math/bits"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+const (
+ dictShardBits = 7
+)
+
+type fastBase struct {
+ // cur is the offset at the start of hist
+ cur int32
+ // maximum offset. Should be at least 2x block size.
+ maxMatchOff int32
+ bufferReset int32
+ hist []byte
+ crc *xxhash.Digest
+ tmp [8]byte
+ blk *blockEnc
+ lastDict *dict
+ lowMem bool
+}
+
+// CRC returns the underlying CRC writer.
+func (e *fastBase) CRC() *xxhash.Digest {
+ return e.crc
+}
+
+// AppendCRC will append the CRC to the destination slice and return it.
+func (e *fastBase) AppendCRC(dst []byte) []byte {
+ crc := e.crc.Sum(e.tmp[:0])
+ dst = append(dst, crc[7], crc[6], crc[5], crc[4])
+ return dst
+}
+
+// WindowSize returns the window size of the encoder,
+// or a window size small enough to contain the input size, if > 0.
+func (e *fastBase) WindowSize(size int64) int32 {
+ if size > 0 && size < int64(e.maxMatchOff) {
+ b := max(
+ // Keep minimum window.
+ int32(1)< e.bufferReset {
+ panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, e.bufferReset))
+ }
+ // check if we have space already
+ if len(e.hist)+len(src) > cap(e.hist) {
+ if cap(e.hist) == 0 {
+ e.ensureHist(len(src))
+ } else {
+ if cap(e.hist) < int(e.maxMatchOff+maxCompressedBlockSize) {
+ panic(fmt.Errorf("unexpected buffer cap %d, want at least %d with window %d", cap(e.hist), e.maxMatchOff+maxCompressedBlockSize, e.maxMatchOff))
+ }
+ // Move down
+ offset := int32(len(e.hist)) - e.maxMatchOff
+ copy(e.hist[0:e.maxMatchOff], e.hist[offset:])
+ e.cur += offset
+ e.hist = e.hist[:e.maxMatchOff]
+ }
+ }
+ s := int32(len(e.hist))
+ e.hist = append(e.hist, src...)
+ return s
+}
+
+// ensureHist will ensure that history can keep at least this many bytes.
+func (e *fastBase) ensureHist(n int) {
+ if cap(e.hist) >= n {
+ return
+ }
+ l := e.maxMatchOff
+ if (e.lowMem && e.maxMatchOff > maxCompressedBlockSize) || e.maxMatchOff <= maxCompressedBlockSize {
+ l += maxCompressedBlockSize
+ } else {
+ l += e.maxMatchOff
+ }
+ // Make it at least 1MB.
+ if l < 1<<20 && !e.lowMem {
+ l = 1 << 20
+ }
+ // Make it at least the requested size.
+ if l < int32(n) {
+ l = int32(n)
+ }
+ e.hist = make([]byte, 0, l)
+}
+
+// useBlock will replace the block with the provided one,
+// but transfer recent offsets from the previous.
+func (e *fastBase) UseBlock(enc *blockEnc) {
+ enc.reset(e.blk)
+ e.blk = enc
+}
+
+func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
+ if debugAsserts {
+ if s < 0 {
+ err := fmt.Sprintf("s (%d) < 0", s)
+ panic(err)
+ }
+ if t < 0 {
+ err := fmt.Sprintf("t (%d) < 0", t)
+ panic(err)
+ }
+ if s-t > e.maxMatchOff {
+ err := fmt.Sprintf("s (%d) - t (%d) > maxMatchOff (%d)", s, t, e.maxMatchOff)
+ panic(err)
+ }
+ if len(src)-int(s) > maxCompressedBlockSize {
+ panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize))
+ }
+ }
+ return int32(matchLen(src[s:], src[t:]))
+}
+
+// Reset the encoding table.
+func (e *fastBase) resetBase(d *dict, singleBlock bool) {
+ if e.blk == nil {
+ e.blk = &blockEnc{lowMem: e.lowMem}
+ e.blk.init()
+ } else {
+ e.blk.reset(nil)
+ }
+ e.blk.initNewEncode()
+ if e.crc == nil {
+ e.crc = xxhash.New()
+ } else {
+ e.crc.Reset()
+ }
+ e.blk.dictLitEnc = nil
+ if d != nil {
+ low := e.lowMem
+ if singleBlock {
+ e.lowMem = true
+ }
+ e.ensureHist(d.ContentSize() + maxCompressedBlockSize)
+ e.lowMem = low
+ }
+
+ // We offset current position so everything will be out of reach.
+ // If above reset line, history will be purged.
+ if e.cur < e.bufferReset {
+ e.cur += e.maxMatchOff + int32(len(e.hist))
+ }
+ e.hist = e.hist[:0]
+ if d != nil {
+ // Set offsets (currently not used)
+ for i, off := range d.offsets {
+ e.blk.recentOffsets[i] = uint32(off)
+ e.blk.prevRecentOffsets[i] = e.blk.recentOffsets[i]
+ }
+ // Transfer litenc.
+ e.blk.dictLitEnc = d.litEnc
+ e.hist = append(e.hist, d.content...)
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go
new file mode 100644
index 00000000..85179932
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go
@@ -0,0 +1,553 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/klauspost/compress"
+)
+
+const (
+ bestLongTableBits = 22 // Bits used in the long match table
+ bestLongTableSize = 1 << bestLongTableBits // Size of the table
+ bestLongLen = 8 // Bytes used for table hash
+
+ // Note: Increasing the short table bits or making the hash shorter
+ // can actually lead to compression degradation since it will 'steal' more from the
+ // long match table and match offsets are quite big.
+ // This greatly depends on the type of input.
+ bestShortTableBits = 18 // Bits used in the short match table
+ bestShortTableSize = 1 << bestShortTableBits // Size of the table
+ bestShortLen = 4 // Bytes used for table hash
+
+)
+
+type match struct {
+ offset int32
+ s int32
+ length int32
+ rep int32
+ est int32
+}
+
+const highScore = maxMatchLen * 8
+
+// estBits will estimate output bits from predefined tables.
+func (m *match) estBits(bitsPerByte int32) {
+ mlc := mlCode(uint32(m.length - zstdMinMatch))
+ var ofc uint8
+ if m.rep < 0 {
+ ofc = ofCode(uint32(m.s-m.offset) + 3)
+ } else {
+ ofc = ofCode(uint32(m.rep) & 3)
+ }
+ // Cost, excluding
+ ofTT, mlTT := fsePredefEnc[tableOffsets].ct.symbolTT[ofc], fsePredefEnc[tableMatchLengths].ct.symbolTT[mlc]
+
+ // Add cost of match encoding...
+ m.est = int32(ofTT.outBits + mlTT.outBits)
+ m.est += int32(ofTT.deltaNbBits>>16 + mlTT.deltaNbBits>>16)
+ // Subtract savings compared to literal encoding...
+ m.est -= (m.length * bitsPerByte) >> 10
+ if m.est > 0 {
+ // Unlikely gain..
+ m.length = 0
+ m.est = highScore
+ }
+}
+
+// bestFastEncoder uses 2 tables, one for short matches (5 bytes) and one for long matches.
+// The long match table contains the previous entry with the same hash,
+// effectively making it a "chain" of length 2.
+// When we find a long match we choose between the two values and select the longest.
+// When we find a short match, after checking the long, we check if we can find a long at n+1
+// and that it is longer (lazy matching).
+type bestFastEncoder struct {
+ fastBase
+ table [bestShortTableSize]prevEntry
+ longTable [bestLongTableSize]prevEntry
+ dictTable []prevEntry
+ dictLongTable []prevEntry
+}
+
+// Encode improves compression...
+func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 4
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [bestShortTableSize]prevEntry{}
+ e.longTable = [bestLongTableSize]prevEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ v2 := e.table[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.table[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ v2 := e.longTable[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.longTable[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ // Add block to history
+ s := e.addBlock(src)
+ blk.size = len(src)
+
+ // Check RLE first
+ if len(src) > zstdMinMatch {
+ ml := matchLen(src[1:], src)
+ if ml == len(src)-1 {
+ blk.literals = append(blk.literals, src[0])
+ blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3})
+ return
+ }
+ }
+
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Use this to estimate literal cost.
+ // Scaled by 10 bits.
+ bitsPerByte := max(
+ // Huffman can never go < 1 bit/byte
+ int32((compress.ShannonEntropyBits(src)*1024)/len(src)), 1024)
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ const kSearchStrength = 10
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+ offset3 := int32(blk.recentOffsets[2])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ const goodEnough = 250
+
+ cv := load6432(src, s)
+
+ nextHashL := hashLen(cv, bestLongTableBits, bestLongLen)
+ nextHashS := hashLen(cv, bestShortTableBits, bestShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ // Set m to a match at offset if it looks like that will improve compression.
+ improve := func(m *match, offset int32, s int32, first uint32, rep int32) {
+ delta := s - offset
+ if delta >= e.maxMatchOff || delta <= 0 || load3232(src, offset) != first {
+ return
+ }
+ // Try to quick reject if we already have a long match.
+ if m.length > 16 {
+ left := len(src) - int(m.s+m.length)
+ // If we are too close to the end, keep as is.
+ if left <= 0 {
+ return
+ }
+ checkLen := m.length - (s - m.s) - 8
+ if left > 2 && checkLen > 4 {
+ // Check 4 bytes, 4 bytes from the end of the current match.
+ a := load3232(src, offset+checkLen)
+ b := load3232(src, s+checkLen)
+ if a != b {
+ return
+ }
+ }
+ }
+ l := 4 + e.matchlen(s+4, offset+4, src)
+ if m.rep <= 0 {
+ // Extend candidate match backwards as far as possible.
+ // Do not extend repeats as we can assume they are optimal
+ // and offsets change if s == nextEmit.
+ tMin := max(s-e.maxMatchOff, 0)
+ for offset > tMin && s > nextEmit && src[offset-1] == src[s-1] && l < maxMatchLength {
+ s--
+ offset--
+ l++
+ }
+ }
+ if debugAsserts {
+ if offset >= s {
+ panic(fmt.Sprintf("offset: %d - s:%d - rep: %d - cur :%d - max: %d", offset, s, rep, e.cur, e.maxMatchOff))
+ }
+ if !bytes.Equal(src[s:s+l], src[offset:offset+l]) {
+ panic(fmt.Sprintf("second match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first))
+ }
+ }
+ cand := match{offset: offset, s: s, length: l, rep: rep}
+ cand.estBits(bitsPerByte)
+ if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 {
+ *m = cand
+ }
+ }
+
+ best := match{s: s, est: highScore}
+ improve(&best, candidateL.offset-e.cur, s, uint32(cv), -1)
+ improve(&best, candidateL.prev-e.cur, s, uint32(cv), -1)
+ improve(&best, candidateS.offset-e.cur, s, uint32(cv), -1)
+ improve(&best, candidateS.prev-e.cur, s, uint32(cv), -1)
+
+ if canRepeat && best.length < goodEnough {
+ if s == nextEmit {
+ // Check repeats straight after a match.
+ improve(&best, s-offset2, s, uint32(cv), 1|4)
+ improve(&best, s-offset3, s, uint32(cv), 2|4)
+ if offset1 > 1 {
+ improve(&best, s-(offset1-1), s, uint32(cv), 3|4)
+ }
+ }
+
+ // If either no match or a non-repeat match, check at + 1
+ if best.rep <= 0 {
+ cv32 := uint32(cv >> 8)
+ spp := s + 1
+ improve(&best, spp-offset1, spp, cv32, 1)
+ improve(&best, spp-offset2, spp, cv32, 2)
+ improve(&best, spp-offset3, spp, cv32, 3)
+ if best.rep < 0 {
+ cv32 = uint32(cv >> 24)
+ spp += 2
+ improve(&best, spp-offset1, spp, cv32, 1)
+ improve(&best, spp-offset2, spp, cv32, 2)
+ improve(&best, spp-offset3, spp, cv32, 3)
+ }
+ }
+ }
+ // Load next and check...
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: candidateL.offset}
+ e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: candidateS.offset}
+ index0 := s + 1
+
+ // Look far ahead, unless we have a really long match already...
+ if best.length < goodEnough {
+ // No match found, move forward on input, no need to check forward...
+ if best.length < 4 {
+ s += 1 + (s-nextEmit)>>(kSearchStrength-1)
+ if s >= sLimit {
+ break encodeLoop
+ }
+ continue
+ }
+
+ candidateS = e.table[hashLen(cv>>8, bestShortTableBits, bestShortLen)]
+ cv = load6432(src, s+1)
+ cv2 := load6432(src, s+2)
+ candidateL = e.longTable[hashLen(cv, bestLongTableBits, bestLongLen)]
+ candidateL2 := e.longTable[hashLen(cv2, bestLongTableBits, bestLongLen)]
+
+ // Short at s+1
+ improve(&best, candidateS.offset-e.cur, s+1, uint32(cv), -1)
+ // Long at s+1, s+2
+ improve(&best, candidateL.offset-e.cur, s+1, uint32(cv), -1)
+ improve(&best, candidateL.prev-e.cur, s+1, uint32(cv), -1)
+ improve(&best, candidateL2.offset-e.cur, s+2, uint32(cv2), -1)
+ improve(&best, candidateL2.prev-e.cur, s+2, uint32(cv2), -1)
+ if false {
+ // Short at s+3.
+ // Too often worse...
+ improve(&best, e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+3, uint32(cv2>>8), -1)
+ }
+
+ // Start check at a fixed offset to allow for a few mismatches.
+ // For this compression level 2 yields the best results.
+ // We cannot do this if we have already indexed this position.
+ const skipBeginning = 2
+ if best.s > s-skipBeginning {
+ // See if we can find a better match by checking where the current best ends.
+ // Use that offset to see if we can find a better full match.
+ if sAt := best.s + best.length; sAt < sLimit {
+ nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen)
+ candidateEnd := e.longTable[nextHashL]
+
+ if off := candidateEnd.offset - e.cur - best.length + skipBeginning; off >= 0 {
+ improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
+ if off := candidateEnd.prev - e.cur - best.length + skipBeginning; off >= 0 {
+ improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1)
+ }
+ }
+ }
+ }
+ }
+
+ if debugAsserts {
+ if best.offset >= best.s {
+ panic(fmt.Sprintf("best.offset > s: %d >= %d", best.offset, best.s))
+ }
+ if best.s < nextEmit {
+ panic(fmt.Sprintf("s %d < nextEmit %d", best.s, nextEmit))
+ }
+ if best.offset < s-e.maxMatchOff {
+ panic(fmt.Sprintf("best.offset < s-e.maxMatchOff: %d < %d", best.offset, s-e.maxMatchOff))
+ }
+ if !bytes.Equal(src[best.s:best.s+best.length], src[best.offset:best.offset+best.length]) {
+ panic(fmt.Sprintf("match mismatch: %v != %v", src[best.s:best.s+best.length], src[best.offset:best.offset+best.length]))
+ }
+ }
+
+ // We have a match, we can store the forward value
+ s = best.s
+ if best.rep > 0 {
+ var seq seq
+ seq.matchLen = uint32(best.length - zstdMinMatch)
+ addLiterals(&seq, best.s)
+
+ // Repeat. If bit 4 is set, this is a non-lit repeat.
+ seq.offset = uint32(best.rep & 3)
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", best.s, "off:", best.s-best.offset)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Index old s + 1 -> s - 1
+ s = best.s + best.length
+ nextEmit = s
+
+ // Index skipped...
+ end := min(s, sLimit+4)
+ off := index0 + e.cur
+ for index0 < end {
+ cv0 := load6432(src, index0)
+ h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
+ h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
+ off++
+ index0++
+ }
+
+ switch best.rep {
+ case 2, 4 | 1:
+ offset1, offset2 = offset2, offset1
+ case 3, 4 | 2:
+ offset1, offset2, offset3 = offset3, offset1, offset2
+ case 4 | 3:
+ offset1, offset2, offset3 = offset1-1, offset1, offset2
+ }
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, best.length)
+ }
+ break encodeLoop
+ }
+ continue
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ t := best.offset
+ offset1, offset2, offset3 = s-t, offset1, offset2
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Write our sequence
+ var seq seq
+ l := best.length
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+
+ // Index old s + 1 -> s - 1 or sLimit
+ end := min(s, sLimit-4)
+
+ off := index0 + e.cur
+ for index0 < end {
+ cv0 := load6432(src, index0)
+ h0 := hashLen(cv0, bestLongTableBits, bestLongLen)
+ h1 := hashLen(cv0, bestShortTableBits, bestShortLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset}
+ index0++
+ off++
+ }
+ if s >= sLimit {
+ break encodeLoop
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ blk.recentOffsets[2] = uint32(offset3)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *bestFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ e.ensureHist(len(src))
+ e.Encode(blk, src)
+}
+
+// Reset will reset and set a dictionary if not nil
+func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+ dictChanged := d != e.lastDict
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || dictChanged {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]prevEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff; i < end; i += 4 {
+ const hashLog = bestShortTableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hashLen(cv, hashLog, bestShortLen) // 0 -> 4
+ nextHash1 := hashLen(cv>>8, hashLog, bestShortLen) // 1 -> 5
+ nextHash2 := hashLen(cv>>16, hashLog, bestShortLen) // 2 -> 6
+ nextHash3 := hashLen(cv>>24, hashLog, bestShortLen) // 3 -> 7
+ e.dictTable[nextHash] = prevEntry{
+ prev: e.dictTable[nextHash].offset,
+ offset: i,
+ }
+ e.dictTable[nextHash1] = prevEntry{
+ prev: e.dictTable[nextHash1].offset,
+ offset: i + 1,
+ }
+ e.dictTable[nextHash2] = prevEntry{
+ prev: e.dictTable[nextHash2].offset,
+ offset: i + 2,
+ }
+ e.dictTable[nextHash3] = prevEntry{
+ prev: e.dictTable[nextHash3].offset,
+ offset: i + 3,
+ }
+ }
+ }
+
+ // Init or copy dict long table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]prevEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ h := hashLen(cv, bestLongTableBits, bestLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: e.maxMatchOff,
+ prev: e.dictLongTable[h].offset,
+ }
+
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ off := 8 // First to read
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[off]) << 56)
+ h := hashLen(cv, bestLongTableBits, bestLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: i,
+ prev: e.dictLongTable[h].offset,
+ }
+ off++
+ }
+ }
+ }
+ e.lastDict = d
+ // Reset table to initial state
+ copy(e.longTable[:], e.dictLongTable)
+
+ e.cur = e.maxMatchOff
+ // Reset table to initial state
+ copy(e.table[:], e.dictTable)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go
new file mode 100644
index 00000000..3305f092
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go
@@ -0,0 +1,1238 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import "fmt"
+
+const (
+ betterLongTableBits = 19 // Bits used in the long match table
+ betterLongTableSize = 1 << betterLongTableBits // Size of the table
+ betterLongLen = 8 // Bytes used for table hash
+
+ // Note: Increasing the short table bits or making the hash shorter
+ // can actually lead to compression degradation since it will 'steal' more from the
+ // long match table and match offsets are quite big.
+ // This greatly depends on the type of input.
+ betterShortTableBits = 13 // Bits used in the short match table
+ betterShortTableSize = 1 << betterShortTableBits // Size of the table
+ betterShortLen = 5 // Bytes used for table hash
+
+ betterLongTableShardCnt = 1 << (betterLongTableBits - dictShardBits) // Number of shards in the table
+ betterLongTableShardSize = betterLongTableSize / betterLongTableShardCnt // Size of an individual shard
+
+ betterShortTableShardCnt = 1 << (betterShortTableBits - dictShardBits) // Number of shards in the table
+ betterShortTableShardSize = betterShortTableSize / betterShortTableShardCnt // Size of an individual shard
+)
+
+type prevEntry struct {
+ offset int32
+ prev int32
+}
+
+// betterFastEncoder uses 2 tables, one for short matches (5 bytes) and one for long matches.
+// The long match table contains the previous entry with the same hash,
+// effectively making it a "chain" of length 2.
+// When we find a long match we choose between the two values and select the longest.
+// When we find a short match, after checking the long, we check if we can find a long at n+1
+// and that it is longer (lazy matching).
+type betterFastEncoder struct {
+ fastBase
+ table [betterShortTableSize]tableEntry
+ longTable [betterLongTableSize]prevEntry
+}
+
+type betterFastEncoderDict struct {
+ betterFastEncoder
+ dictTable []tableEntry
+ dictLongTable []prevEntry
+ shortTableShardDirty [betterShortTableShardCnt]bool
+ longTableShardDirty [betterLongTableShardCnt]bool
+ allDirty bool
+}
+
+// Encode improves compression...
+func (e *betterFastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [betterShortTableSize]tableEntry{}
+ e.longTable = [betterLongTableSize]prevEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ v2 := e.longTable[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.longTable[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Add block to history
+ s := e.addBlock(src)
+ blk.size = len(src)
+
+ // Check RLE first
+ if len(src) > zstdMinMatch {
+ ml := matchLen(src[1:], src)
+ if ml == len(src)-1 {
+ blk.literals = append(blk.literals, src[0])
+ blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3})
+ return
+ }
+ }
+
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 9
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+ var matched, index0 int32
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ off := s + e.cur
+ e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset}
+ e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)}
+ index0 = s + 1
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Index match start+1 (long) -> s - 1
+ index0 := s + repOff
+ s += length + repOff
+
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ const repOff2 = 1
+
+ // We deviate from the reference encoder and also check offset 2.
+ // Still slower and not much better, so disabled.
+ // repIndex = s - offset2 + repOff2
+ if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
+ // Consider history as well.
+ var seq seq
+ length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 2
+ seq.offset = 2
+ if debugSequences {
+ println("repeat sequence 2", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ s += length + repOff2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ // Swap offsets
+ offset1, offset2 = offset2, offset1
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := candidateL.offset - e.cur
+ coffsetLP := candidateL.prev - e.cur
+
+ // Check if we have a long match.
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetL+8, src) + 8
+ t = coffsetL
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ prevMatch := e.matchlen(s+8, coffsetLP+8, src) + 8
+ if prevMatch > matched {
+ matched = prevMatch
+ t = coffsetLP
+ }
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ }
+ break
+ }
+
+ // Check if we have a long match on prev.
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetLP+8, src) + 8
+ t = coffsetLP
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ coffsetS := candidateS.offset - e.cur
+
+ // Check if we have a short match.
+ if s-coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ matched = e.matchlen(s+4, coffsetS+4, src) + 4
+
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, betterLongTableBits, betterLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = candidateL.offset - e.cur
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = prevEntry{offset: s + checkAt + e.cur, prev: candidateL.offset}
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+ }
+
+ // Check prev long...
+ coffsetL = candidateL.prev - e.cur
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match (after short)")
+ }
+ break
+ }
+ }
+ t = coffsetS
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // Try to find a better match by searching for a long match at the end of the current best match
+ if s+matched < sLimit {
+ // Allow some bytes at the beginning to mismatch.
+ // Sweet spot is around 3 bytes, but depends on input.
+ // The skipped bytes are tested in Extend backwards,
+ // and still picked up as part of the match if they do.
+ const skipBeginning = 3
+
+ nextHashL := hashLen(load6432(src, s+matched), betterLongTableBits, betterLongLen)
+ s2 := s + skipBeginning
+ cv := load3232(src, s2)
+ candidateL := e.longTable[nextHashL]
+ coffsetL := candidateL.offset - e.cur - matched + skipBeginning
+ if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ s = s2
+ matched = matchedNext
+ if debugMatches {
+ println("long match at end-of-match")
+ }
+ }
+ }
+
+ // Check prev long...
+ if true {
+ coffsetL = candidateL.prev - e.cur - matched + skipBeginning
+ if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ s = s2
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match at end-of-match")
+ }
+ }
+ }
+ }
+ }
+ // A match has been found. Update recent offsets.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the n-byte match as long as possible.
+ l := matched
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) -> s - 1
+ off := index0 + e.cur
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ index0 += 2
+ off += 2
+ }
+
+ cv = load6432(src, s)
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset}
+ e.table[nextHashS] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *betterFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ e.ensureHist(len(src))
+ e.Encode(blk, src)
+}
+
+// Encode improves compression...
+func (e *betterFastEncoderDict) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = prevEntry{}
+ }
+ e.cur = e.maxMatchOff
+ e.allDirty = true
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ v2 := e.longTable[i].prev
+ if v < minOff {
+ v = 0
+ v2 = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ if v2 < minOff {
+ v2 = 0
+ } else {
+ v2 = v2 - e.cur + e.maxMatchOff
+ }
+ }
+ e.longTable[i] = prevEntry{
+ offset: v,
+ prev: v2,
+ }
+ }
+ e.allDirty = true
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 9
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+ var matched, index0 int32
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ off := s + e.cur
+ e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset}
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)}
+ e.markShortShardDirty(nextHashS)
+ index0 = s + 1
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Index match start+1 (long) -> s - 1
+ s += length + repOff
+
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.markLongShardDirty(h0)
+ h1 := hashLen(cv1, betterShortTableBits, betterShortLen)
+ e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ e.markShortShardDirty(h1)
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ const repOff2 = 1
+
+ // We deviate from the reference encoder and also check offset 2.
+ // Still slower and not much better, so disabled.
+ // repIndex = s - offset2 + repOff2
+ if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) {
+ // Consider history as well.
+ var seq seq
+ length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 2
+ seq.offset = 2
+ if debugSequences {
+ println("repeat sequence 2", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ s += length + repOff2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+
+ // Index skipped...
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ off := index0 + e.cur
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.markLongShardDirty(h0)
+ h1 := hashLen(cv1, betterShortTableBits, betterShortLen)
+ e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ e.markShortShardDirty(h1)
+ index0 += 2
+ }
+ cv = load6432(src, s)
+ // Swap offsets
+ offset1, offset2 = offset2, offset1
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := candidateL.offset - e.cur
+ coffsetLP := candidateL.prev - e.cur
+
+ // Check if we have a long match.
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetL+8, src) + 8
+ t = coffsetL
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ prevMatch := e.matchlen(s+8, coffsetLP+8, src) + 8
+ if prevMatch > matched {
+ matched = prevMatch
+ t = coffsetLP
+ }
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ }
+ break
+ }
+
+ // Check if we have a long match on prev.
+ if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) {
+ // Found a long match, at least 8 bytes.
+ matched = e.matchlen(s+8, coffsetLP+8, src) + 8
+ t = coffsetLP
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ coffsetS := candidateS.offset - e.cur
+
+ // Check if we have a short match.
+ if s-coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ matched = e.matchlen(s+4, coffsetS+4, src) + 4
+
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, betterLongTableBits, betterLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = candidateL.offset - e.cur
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = prevEntry{offset: s + checkAt + e.cur, prev: candidateL.offset}
+ e.markLongShardDirty(nextHashL)
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+ }
+
+ // Check prev long...
+ coffsetL = candidateL.prev - e.cur
+ if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) {
+ // Found a long match, at least 8 bytes.
+ matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8
+ if matchedNext > matched {
+ t = coffsetL
+ s += checkAt
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match (after short)")
+ }
+ break
+ }
+ }
+ t = coffsetS
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // Try to find a better match by searching for a long match at the end of the current best match
+ if s+matched < sLimit {
+ nextHashL := hashLen(load6432(src, s+matched), betterLongTableBits, betterLongLen)
+ cv := load3232(src, s)
+ candidateL := e.longTable[nextHashL]
+ coffsetL := candidateL.offset - e.cur - matched
+ if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ matched = matchedNext
+ if debugMatches {
+ println("long match at end-of-match")
+ }
+ }
+ }
+
+ // Check prev long...
+ if true {
+ coffsetL = candidateL.prev - e.cur - matched
+ if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) {
+ // Found a long match, at least 4 bytes.
+ matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4
+ if matchedNext > matched {
+ t = coffsetL
+ matched = matchedNext
+ if debugMatches {
+ println("prev long match at end-of-match")
+ }
+ }
+ }
+ }
+ }
+ // A match has been found. Update recent offsets.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the n-byte match as long as possible.
+ l := matched
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) -> s - 1
+ off := index0 + e.cur
+ for index0 < s-1 {
+ cv0 := load6432(src, index0)
+ cv1 := cv0 >> 8
+ h0 := hashLen(cv0, betterLongTableBits, betterLongLen)
+ e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset}
+ e.markLongShardDirty(h0)
+ h1 := hashLen(cv1, betterShortTableBits, betterShortLen)
+ e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)}
+ e.markShortShardDirty(h1)
+ index0 += 2
+ off += 2
+ }
+
+ cv = load6432(src, s)
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashL := hashLen(cv, betterLongTableBits, betterLongLen)
+ nextHashS := hashLen(cv, betterShortTableBits, betterShortLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset}
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.markShortShardDirty(nextHashS)
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *betterFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d != nil {
+ panic("betterFastEncoder: Reset with dict")
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+ dictChanged := d != e.lastDict
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || dictChanged {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]tableEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff; i < end; i += 4 {
+ const hashLog = betterShortTableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hashLen(cv, hashLog, betterShortLen) // 0 -> 4
+ nextHash1 := hashLen(cv>>8, hashLog, betterShortLen) // 1 -> 5
+ nextHash2 := hashLen(cv>>16, hashLog, betterShortLen) // 2 -> 6
+ nextHash3 := hashLen(cv>>24, hashLog, betterShortLen) // 3 -> 7
+ e.dictTable[nextHash] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ e.dictTable[nextHash1] = tableEntry{
+ val: uint32(cv >> 8),
+ offset: i + 1,
+ }
+ e.dictTable[nextHash2] = tableEntry{
+ val: uint32(cv >> 16),
+ offset: i + 2,
+ }
+ e.dictTable[nextHash3] = tableEntry{
+ val: uint32(cv >> 24),
+ offset: i + 3,
+ }
+ }
+ e.allDirty = true
+ }
+
+ // Init or copy dict long table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]prevEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ h := hashLen(cv, betterLongTableBits, betterLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: e.maxMatchOff,
+ prev: e.dictLongTable[h].offset,
+ }
+
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ off := 8 // First to read
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[off]) << 56)
+ h := hashLen(cv, betterLongTableBits, betterLongLen)
+ e.dictLongTable[h] = prevEntry{
+ offset: i,
+ prev: e.dictLongTable[h].offset,
+ }
+ off++
+ }
+ }
+ e.allDirty = true
+ }
+ e.lastDict = d
+
+ // Reset table to initial state
+ {
+ dirtyShardCnt := 0
+ if !e.allDirty {
+ for i := range e.shortTableShardDirty {
+ if e.shortTableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+ const shardCnt = betterShortTableShardCnt
+ const shardSize = betterShortTableShardSize
+ if e.allDirty || dirtyShardCnt > shardCnt*4/6 {
+ copy(e.table[:], e.dictTable)
+ for i := range e.shortTableShardDirty {
+ e.shortTableShardDirty[i] = false
+ }
+ } else {
+ for i := range e.shortTableShardDirty {
+ if !e.shortTableShardDirty[i] {
+ continue
+ }
+
+ copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize])
+ e.shortTableShardDirty[i] = false
+ }
+ }
+ }
+ {
+ dirtyShardCnt := 0
+ if !e.allDirty {
+ for i := range e.shortTableShardDirty {
+ if e.shortTableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+ const shardCnt = betterLongTableShardCnt
+ const shardSize = betterLongTableShardSize
+ if e.allDirty || dirtyShardCnt > shardCnt*4/6 {
+ copy(e.longTable[:], e.dictLongTable)
+ for i := range e.longTableShardDirty {
+ e.longTableShardDirty[i] = false
+ }
+ } else {
+ for i := range e.longTableShardDirty {
+ if !e.longTableShardDirty[i] {
+ continue
+ }
+
+ copy(e.longTable[i*shardSize:(i+1)*shardSize], e.dictLongTable[i*shardSize:(i+1)*shardSize])
+ e.longTableShardDirty[i] = false
+ }
+ }
+ }
+ e.cur = e.maxMatchOff
+ e.allDirty = false
+}
+
+func (e *betterFastEncoderDict) markLongShardDirty(entryNum uint32) {
+ e.longTableShardDirty[entryNum/betterLongTableShardSize] = true
+}
+
+func (e *betterFastEncoderDict) markShortShardDirty(entryNum uint32) {
+ e.shortTableShardDirty[entryNum/betterShortTableShardSize] = true
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
new file mode 100644
index 00000000..2fb6da11
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
@@ -0,0 +1,1107 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import "fmt"
+
+const (
+ dFastLongTableBits = 17 // Bits used in the long match table
+ dFastLongTableSize = 1 << dFastLongTableBits // Size of the table
+ dFastLongTableMask = dFastLongTableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
+ dFastLongLen = 8 // Bytes used for table hash
+
+ dLongTableShardCnt = 1 << (dFastLongTableBits - dictShardBits) // Number of shards in the table
+ dLongTableShardSize = dFastLongTableSize / dLongTableShardCnt // Size of an individual shard
+
+ dFastShortTableBits = tableBits // Bits used in the short match table
+ dFastShortTableSize = 1 << dFastShortTableBits // Size of the table
+ dFastShortTableMask = dFastShortTableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
+ dFastShortLen = 5 // Bytes used for table hash
+
+)
+
+type doubleFastEncoder struct {
+ fastEncoder
+ longTable [dFastLongTableSize]tableEntry
+}
+
+type doubleFastEncoderDict struct {
+ fastEncoderDict
+ longTable [dFastLongTableSize]tableEntry
+ dictLongTable []tableEntry
+ longTableShardDirty [dLongTableShardCnt]bool
+}
+
+// Encode mimmics functionality in zstd_dfast.c
+func (e *doubleFastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [dFastShortTableSize]tableEntry{}
+ e.longTable = [dFastLongTableSize]tableEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.longTable[i].offset = v
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + repOff
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := s - (candidateL.offset - e.cur)
+ coffsetS := s - (candidateS.offset - e.cur)
+
+ // Check if we have a long match.
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ // Check if we have a short match.
+ if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - e.cur) + checkAt
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ s += checkAt
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+
+ t = candidateS.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) and start+2 (short)
+ index0 := s - l + 1
+ // Index match end-2 (long) and end-1 (short)
+ index1 := s - 2
+
+ cv0 := load6432(src, index0)
+ cv1 := load6432(src, index1)
+ te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
+ e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0
+ e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0
+ e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1
+
+ cv = load6432(src, s)
+
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *doubleFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ if e.cur >= e.bufferReset {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ }
+
+ s := int32(0)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ for {
+
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+
+ if len(blk.sequences) > 2 {
+ if load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ //length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+ length := 4 + int32(matchLen(src[s+4+repOff:], src[repIndex+4:]))
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + repOff
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := s - (candidateL.offset - e.cur)
+ coffsetS := s - (candidateS.offset - e.cur)
+
+ // Check if we have a long match.
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d). cur: %d", s, t, e.cur))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ // Check if we have a short match.
+ if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - e.cur) + checkAt
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ s += checkAt
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+
+ t = candidateS.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ // Extend the 4-byte match as long as possible.
+ //l := e.matchlen(s+4, t+4, src) + 4
+ l := int32(matchLen(src[s+4:], src[t+4:])) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) and start+2 (short)
+ index0 := s - l + 1
+ // Index match end-2 (long) and end-1 (short)
+ index1 := s - 2
+
+ cv0 := load6432(src, index0)
+ cv1 := load6432(src, index1)
+ te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
+ e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0
+ e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0
+ e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1
+
+ cv = load6432(src, s)
+
+ if len(blk.sequences) <= 2 {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashS := hashLen(cv1>>8, dFastShortTableBits, dFastShortLen)
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ //l := 4 + e.matchlen(s+4, o2+4, src)
+ l := 4 + int32(matchLen(src[s+4:], src[o2+4:]))
+
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+
+ // We do not store history, so we must offset e.cur to avoid false matches for next user.
+ if e.cur < e.bufferReset {
+ e.cur += int32(len(src))
+ }
+}
+
+// Encode will encode the content, with a dictionary if initialized for it.
+func (e *doubleFastEncoderDict) Encode(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = tableEntry{}
+ }
+ e.markAllShardsDirty()
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ for i := range e.longTable[:] {
+ v := e.longTable[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.longTable[i].offset = v
+ }
+ e.markAllShardsDirty()
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ const stepSize = 1
+
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ // We allow the encoder to optionally turn off repeat offsets across blocks
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = entry
+ e.markShardDirty(nextHashS)
+
+ if canRepeat {
+ if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := max(s-e.maxMatchOff, 0)
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + repOff
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := s - (candidateL.offset - e.cur)
+ coffsetS := s - (candidateS.offset - e.cur)
+
+ // Check if we have a long match.
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ // Check if we have a short match.
+ if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - e.cur) + checkAt
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
+ e.markLongShardDirty(nextHashL)
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ s += checkAt
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+
+ t = candidateS.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) and start+2 (short)
+ index0 := s - l + 1
+ // Index match end-2 (long) and end-1 (short)
+ index1 := s - 2
+
+ cv0 := load6432(src, index0)
+ cv1 := load6432(src, index1)
+ te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
+ longHash1 := hashLen(cv0, dFastLongTableBits, dFastLongLen)
+ longHash2 := hashLen(cv1, dFastLongTableBits, dFastLongLen)
+ e.longTable[longHash1] = te0
+ e.longTable[longHash2] = te1
+ e.markLongShardDirty(longHash1)
+ e.markLongShardDirty(longHash2)
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ hashVal1 := hashLen(cv0, dFastShortTableBits, dFastShortLen)
+ hashVal2 := hashLen(cv1, dFastShortTableBits, dFastShortLen)
+ e.table[hashVal1] = te0
+ e.markShardDirty(hashVal1)
+ e.table[hashVal2] = te1
+ e.markShardDirty(hashVal2)
+
+ cv = load6432(src, s)
+
+ if !canRepeat {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen)
+ nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.markLongShardDirty(nextHashL)
+ e.table[nextHashS] = entry
+ e.markShardDirty(nextHashS)
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+ // If we encoded more than 64K mark all dirty.
+ if len(src) > 64<<10 {
+ e.markAllShardsDirty()
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *doubleFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.fastEncoder.Reset(d, singleBlock)
+ if d != nil {
+ panic("doubleFastEncoder: Reset with dict not supported")
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) {
+ allDirty := e.allDirty
+ dictChanged := d != e.lastDict
+ e.fastEncoderDict.Reset(d, singleBlock)
+ if d == nil {
+ return
+ }
+
+ // Init or copy dict table
+ if len(e.dictLongTable) != len(e.longTable) || dictChanged {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]tableEntry, len(e.longTable))
+ } else {
+ clear(e.dictLongTable)
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{
+ val: uint32(cv),
+ offset: e.maxMatchOff,
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[i-e.maxMatchOff+7]) << 56)
+ e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ }
+ }
+ allDirty = true
+ }
+ // Reset table to initial state
+ e.cur = e.maxMatchOff
+
+ dirtyShardCnt := 0
+ if !allDirty {
+ for i := range e.longTableShardDirty {
+ if e.longTableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+
+ if allDirty || dirtyShardCnt > dLongTableShardCnt/2 {
+ //copy(e.longTable[:], e.dictLongTable)
+ e.longTable = *(*[dFastLongTableSize]tableEntry)(e.dictLongTable)
+ for i := range e.longTableShardDirty {
+ e.longTableShardDirty[i] = false
+ }
+ return
+ }
+ for i := range e.longTableShardDirty {
+ if !e.longTableShardDirty[i] {
+ continue
+ }
+
+ // copy(e.longTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize], e.dictLongTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize])
+ *(*[dLongTableShardSize]tableEntry)(e.longTable[i*dLongTableShardSize:]) = *(*[dLongTableShardSize]tableEntry)(e.dictLongTable[i*dLongTableShardSize:])
+
+ e.longTableShardDirty[i] = false
+ }
+}
+
+func (e *doubleFastEncoderDict) markLongShardDirty(entryNum uint32) {
+ e.longTableShardDirty[entryNum/dLongTableShardSize] = true
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
new file mode 100644
index 00000000..5e104f1a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
@@ -0,0 +1,875 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "fmt"
+)
+
+const (
+ tableBits = 15 // Bits used in the table
+ tableSize = 1 << tableBits // Size of the table
+ tableShardCnt = 1 << (tableBits - dictShardBits) // Number of shards in the table
+ tableShardSize = tableSize / tableShardCnt // Size of an individual shard
+ tableFastHashLen = 6
+ tableMask = tableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks.
+ maxMatchLength = 131074
+)
+
+type tableEntry struct {
+ val uint32
+ offset int32
+}
+
+type fastEncoder struct {
+ fastBase
+ table [tableSize]tableEntry
+}
+
+type fastEncoderDict struct {
+ fastEncoder
+ dictTable []tableEntry
+ tableShardDirty [tableShardCnt]bool
+ allDirty bool
+}
+
+// Encode mimmics functionality in zstd_fast.c
+func (e *fastEncoder) Encode(blk *blockEnc, src []byte) {
+ const (
+ inputMargin = 8
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 2.
+ const stepSize = 2
+
+ // TEMPLATE
+ const hashLog = tableBits
+ // seems global, but would be nice to tweak.
+ const kSearchStrength = 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When existing the search loop, we have already checked 4 bytes.
+ var t int32
+
+ // We will not use repeat offsets across blocks.
+ // By not using them for the first 3 matches
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
+ candidate := e.table[nextHash]
+ candidate2 := e.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
+
+ if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+6, repIndex+4, src)
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + 2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ sMin := max(s-e.maxMatchOff, 0)
+ for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + 2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ coffset0 := s - (candidate.offset - e.cur)
+ coffset1 := s - (candidate2.offset - e.cur) + 1
+ if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
+ // found a regular match
+ t = candidate.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ break
+ }
+
+ if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
+ // found a regular match
+ t = candidate2.offset - e.cur
+ s++
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ break
+ }
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // A 4-byte match has been found. We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence.
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ // Don't use repeat offsets
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+
+ // Check offset 2
+ if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) {
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ // Store this, since we have it.
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break encodeLoop
+ }
+ // Prepare next loop.
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ const (
+ inputMargin = 8
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+ if debugEncoder {
+ if len(src) > maxCompressedBlockSize {
+ panic("src too big")
+ }
+ }
+
+ // Protect against e.cur wraparound.
+ if e.cur >= e.bufferReset {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ }
+
+ s := int32(0)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 2.
+ const stepSize = 2
+
+ // TEMPLATE
+ const hashLog = tableBits
+ // seems global, but would be nice to tweak.
+ const kSearchStrength = 6
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When existing the search loop, we have already checked 4 bytes.
+ var t int32
+
+ // We will not use repeat offsets across blocks.
+ // By not using them for the first 3 matches
+
+ for {
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
+ candidate := e.table[nextHash]
+ candidate2 := e.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
+
+ if len(blk.sequences) > 2 && load3232(src, repIndex) == uint32(cv>>16) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+6, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + 2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ sMin := max(s-e.maxMatchOff, 0)
+ for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + 2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ coffset0 := s - (candidate.offset - e.cur)
+ coffset1 := s - (candidate2.offset - e.cur) + 1
+ if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
+ // found a regular match
+ t = candidate.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic(fmt.Sprintf("t (%d) < 0, candidate.offset: %d, e.cur: %d, coffset0: %d, e.maxMatchOff: %d", t, candidate.offset, e.cur, coffset0, e.maxMatchOff))
+ }
+ break
+ }
+
+ if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
+ // found a regular match
+ t = candidate2.offset - e.cur
+ s++
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ break
+ }
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // A 4-byte match has been found. We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && t < 0 {
+ panic(fmt.Sprintf("t (%d) < 0 ", t))
+ }
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence.
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ // Don't use repeat offsets
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+
+ // Check offset 2
+ if o2 := s - offset2; len(blk.sequences) > 2 && load3232(src, o2) == uint32(cv) {
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ // Store this, since we have it.
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break encodeLoop
+ }
+ // Prepare next loop.
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+ // We do not store history, so we must offset e.cur to avoid false matches for next user.
+ if e.cur < e.bufferReset {
+ e.cur += int32(len(src))
+ }
+}
+
+// Encode will encode the content, with a dictionary if initialized for it.
+func (e *fastEncoderDict) Encode(blk *blockEnc, src []byte) {
+ const (
+ inputMargin = 8
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+ if e.allDirty || len(src) > 32<<10 {
+ e.fastEncoder.Encode(blk, src)
+ e.allDirty = true
+ return
+ }
+ // Protect against e.cur wraparound.
+ for e.cur >= e.bufferReset-int32(len(e.hist)) {
+ if len(e.hist) == 0 {
+ e.table = [tableSize]tableEntry{}
+ e.cur = e.maxMatchOff
+ break
+ }
+ // Shift down everything in the table that isn't already too far away.
+ minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff
+ for i := range e.table[:] {
+ v := e.table[i].offset
+ if v < minOff {
+ v = 0
+ } else {
+ v = v - e.cur + e.maxMatchOff
+ }
+ e.table[i].offset = v
+ }
+ e.cur = e.maxMatchOff
+ break
+ }
+
+ s := e.addBlock(src)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ src = e.hist
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 2.
+ const stepSize = 2
+
+ // TEMPLATE
+ const hashLog = tableBits
+ // seems global, but would be nice to tweak.
+ const kSearchStrength = 7
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debugEncoder {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When existing the search loop, we have already checked 4 bytes.
+ var t int32
+
+ // We will not use repeat offsets across blocks.
+ // By not using them for the first 3 matches
+ canRepeat := len(blk.sequences) > 2
+
+ for {
+ if debugAsserts && canRepeat && offset1 == 0 {
+ panic("offset0 was 0")
+ }
+
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen)
+ candidate := e.table[nextHash]
+ candidate2 := e.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.markShardDirty(nextHash)
+ e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
+ e.markShardDirty(nextHash2)
+
+ if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) {
+ // Consider history as well.
+ var seq seq
+ length := 4 + e.matchlen(s+6, repIndex+4, src)
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + 2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ sMin := max(s-e.maxMatchOff, 0)
+ for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + 2
+ nextEmit = s
+ if s >= sLimit {
+ if debugEncoder {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ coffset0 := s - (candidate.offset - e.cur)
+ coffset1 := s - (candidate2.offset - e.cur) + 1
+ if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
+ // found a regular match
+ t = candidate.offset - e.cur
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ break
+ }
+
+ if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
+ // found a regular match
+ t = candidate2.offset - e.cur
+ s++
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+ if debugAsserts && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugAsserts && t < 0 {
+ panic("t<0")
+ }
+ break
+ }
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // A 4-byte match has been found. We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debugAsserts && s <= t {
+ panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ }
+
+ if debugAsserts && canRepeat && int(offset1) > len(src) {
+ panic("invalid offset")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ l := e.matchlen(s+4, t+4, src) + 4
+
+ // Extend backwards
+ tMin := max(s-e.maxMatchOff, 0)
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence.
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ // Don't use repeat offsets
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+
+ // Check offset 2
+ if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) {
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ l := 4 + e.matchlen(s+4, o2+4, src)
+
+ // Store this, since we have it.
+ nextHash := hashLen(cv, hashLog, tableFastHashLen)
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.markShardDirty(nextHash)
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break encodeLoop
+ }
+ // Prepare next loop.
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ blk.recentOffsets[0] = uint32(offset1)
+ blk.recentOffsets[1] = uint32(offset2)
+ if debugEncoder {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *fastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d != nil {
+ panic("fastEncoder: Reset with dict")
+ }
+}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || d != e.lastDict {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]tableEntry, len(e.table))
+ } else {
+ clear(e.dictTable)
+ }
+ if true {
+ end := e.maxMatchOff + int32(len(d.content)) - 8
+ for i := e.maxMatchOff; i < end; i += 2 {
+ const hashLog = tableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hashLen(cv, hashLog, tableFastHashLen) // 0 -> 6
+ nextHash1 := hashLen(cv>>8, hashLog, tableFastHashLen) // 1 -> 7
+ e.dictTable[nextHash] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ e.dictTable[nextHash1] = tableEntry{
+ val: uint32(cv >> 8),
+ offset: i + 1,
+ }
+ }
+ }
+ e.lastDict = d
+ e.allDirty = true
+ }
+
+ e.cur = e.maxMatchOff
+ dirtyShardCnt := 0
+ if !e.allDirty {
+ for i := range e.tableShardDirty {
+ if e.tableShardDirty[i] {
+ dirtyShardCnt++
+ }
+ }
+ }
+
+ const shardCnt = tableShardCnt
+ const shardSize = tableShardSize
+ if e.allDirty || dirtyShardCnt > shardCnt*4/6 {
+ //copy(e.table[:], e.dictTable)
+ e.table = *(*[tableSize]tableEntry)(e.dictTable)
+ for i := range e.tableShardDirty {
+ e.tableShardDirty[i] = false
+ }
+ e.allDirty = false
+ return
+ }
+ for i := range e.tableShardDirty {
+ if !e.tableShardDirty[i] {
+ continue
+ }
+
+ //copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize])
+ *(*[shardSize]tableEntry)(e.table[i*shardSize:]) = *(*[shardSize]tableEntry)(e.dictTable[i*shardSize:])
+ e.tableShardDirty[i] = false
+ }
+ e.allDirty = false
+}
+
+func (e *fastEncoderDict) markAllShardsDirty() {
+ e.allDirty = true
+}
+
+func (e *fastEncoderDict) markShardDirty(entryNum uint32) {
+ e.tableShardDirty[entryNum/tableShardSize] = true
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
new file mode 100644
index 00000000..0f2a00a0
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -0,0 +1,671 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ rdebug "runtime/debug"
+ "sync"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+// Encoder provides encoding to Zstandard.
+// An Encoder can be used for either compressing a stream via the
+// io.WriteCloser interface supported by the Encoder or as multiple independent
+// tasks via the EncodeAll function.
+// Smaller encodes are encouraged to use the EncodeAll function.
+// Use NewWriter to create a new instance.
+type Encoder struct {
+ o encoderOptions
+ encoders chan encoder
+ state encoderState
+ init sync.Once
+}
+
+type encoder interface {
+ Encode(blk *blockEnc, src []byte)
+ EncodeNoHist(blk *blockEnc, src []byte)
+ Block() *blockEnc
+ CRC() *xxhash.Digest
+ AppendCRC([]byte) []byte
+ WindowSize(size int64) int32
+ UseBlock(*blockEnc)
+ Reset(d *dict, singleBlock bool)
+}
+
+type encoderState struct {
+ w io.Writer
+ filling []byte
+ current []byte
+ previous []byte
+ encoder encoder
+ writing *blockEnc
+ err error
+ writeErr error
+ nWritten int64
+ nInput int64
+ frameContentSize int64
+ headerWritten bool
+ eofWritten bool
+ fullFrameWritten bool
+
+ // This waitgroup indicates an encode is running.
+ wg sync.WaitGroup
+ // This waitgroup indicates we have a block encoding/writing.
+ wWg sync.WaitGroup
+}
+
+// NewWriter will create a new Zstandard encoder.
+// If the encoder will be used for encoding blocks a nil writer can be used.
+func NewWriter(w io.Writer, opts ...EOption) (*Encoder, error) {
+ initPredefined()
+ var e Encoder
+ e.o.setDefault()
+ for _, o := range opts {
+ err := o(&e.o)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if w != nil {
+ e.Reset(w)
+ }
+ return &e, nil
+}
+
+func (e *Encoder) initialize() {
+ if e.o.concurrent == 0 {
+ e.o.setDefault()
+ }
+ e.encoders = make(chan encoder, e.o.concurrent)
+ for i := 0; i < e.o.concurrent; i++ {
+ enc := e.o.encoder()
+ e.encoders <- enc
+ }
+}
+
+// Reset will re-initialize the writer and new writes will encode to the supplied writer
+// as a new, independent stream.
+func (e *Encoder) Reset(w io.Writer) {
+ s := &e.state
+ s.wg.Wait()
+ s.wWg.Wait()
+ if cap(s.filling) == 0 {
+ s.filling = make([]byte, 0, e.o.blockSize)
+ }
+ if e.o.concurrent > 1 {
+ if cap(s.current) == 0 {
+ s.current = make([]byte, 0, e.o.blockSize)
+ }
+ if cap(s.previous) == 0 {
+ s.previous = make([]byte, 0, e.o.blockSize)
+ }
+ s.current = s.current[:0]
+ s.previous = s.previous[:0]
+ if s.writing == nil {
+ s.writing = &blockEnc{lowMem: e.o.lowMem}
+ s.writing.init()
+ }
+ s.writing.initNewEncode()
+ }
+ if s.encoder == nil {
+ s.encoder = e.o.encoder()
+ }
+ s.filling = s.filling[:0]
+ s.encoder.Reset(e.o.dict, false)
+ s.headerWritten = false
+ s.eofWritten = false
+ s.fullFrameWritten = false
+ s.w = w
+ s.err = nil
+ s.nWritten = 0
+ s.nInput = 0
+ s.writeErr = nil
+ s.frameContentSize = 0
+}
+
+// ResetWithOptions will re-initialize the writer and apply the given options
+// as a new, independent stream.
+// Options are applied on top of the existing options.
+// Some options cannot be changed on reset and will return an error.
+func (e *Encoder) ResetWithOptions(w io.Writer, opts ...EOption) error {
+ e.o.resetOpt = true
+ defer func() { e.o.resetOpt = false }()
+ hadDict := e.o.dict != nil
+ for _, o := range opts {
+ if err := o(&e.o); err != nil {
+ return err
+ }
+ }
+ hasDict := e.o.dict != nil
+ if hadDict != hasDict {
+ // Dict presence changed — encoder type must be recreated.
+ e.state.encoder = nil
+ e.init = sync.Once{}
+ }
+ e.Reset(w)
+ return nil
+}
+
+// ResetContentSize will reset and set a content size for the next stream.
+// If the bytes written does not match the size given an error will be returned
+// when calling Close().
+// This is removed when Reset is called.
+// Sizes <= 0 results in no content size set.
+func (e *Encoder) ResetContentSize(w io.Writer, size int64) {
+ e.Reset(w)
+ if size >= 0 {
+ e.state.frameContentSize = size
+ }
+}
+
+// Write data to the encoder.
+// Input data will be buffered and as the buffer fills up
+// content will be compressed and written to the output.
+// When done writing, use Close to flush the remaining output
+// and write CRC if requested.
+func (e *Encoder) Write(p []byte) (n int, err error) {
+ s := &e.state
+ if s.eofWritten {
+ return 0, ErrEncoderClosed
+ }
+ for len(p) > 0 {
+ if len(p)+len(s.filling) < e.o.blockSize {
+ if e.o.crc {
+ _, _ = s.encoder.CRC().Write(p)
+ }
+ s.filling = append(s.filling, p...)
+ return n + len(p), nil
+ }
+ add := p
+ if len(p)+len(s.filling) > e.o.blockSize {
+ add = add[:e.o.blockSize-len(s.filling)]
+ }
+ if e.o.crc {
+ _, _ = s.encoder.CRC().Write(add)
+ }
+ s.filling = append(s.filling, add...)
+ p = p[len(add):]
+ n += len(add)
+ if len(s.filling) < e.o.blockSize {
+ return n, nil
+ }
+ err := e.nextBlock(false)
+ if err != nil {
+ return n, err
+ }
+ if debugAsserts && len(s.filling) > 0 {
+ panic(len(s.filling))
+ }
+ }
+ return n, nil
+}
+
+// nextBlock will synchronize and start compressing input in e.state.filling.
+// If an error has occurred during encoding it will be returned.
+func (e *Encoder) nextBlock(final bool) error {
+ s := &e.state
+ // Wait for current block.
+ s.wg.Wait()
+ if s.err != nil {
+ return s.err
+ }
+ if len(s.filling) > e.o.blockSize {
+ return fmt.Errorf("block > maxStoreBlockSize")
+ }
+ if !s.headerWritten {
+ // If we have a single block encode, do a sync compression.
+ if final && len(s.filling) == 0 && !e.o.fullZero {
+ s.headerWritten = true
+ s.fullFrameWritten = true
+ s.eofWritten = true
+ return nil
+ }
+ if final && len(s.filling) > 0 {
+ s.current = e.encodeAll(s.encoder, s.filling, s.current[:0])
+ var n2 int
+ n2, s.err = s.w.Write(s.current)
+ if s.err != nil {
+ return s.err
+ }
+ s.nWritten += int64(n2)
+ s.nInput += int64(len(s.filling))
+ s.current = s.current[:0]
+ s.filling = s.filling[:0]
+ s.headerWritten = true
+ s.fullFrameWritten = true
+ s.eofWritten = true
+ return nil
+ }
+
+ var tmp [maxHeaderSize]byte
+ fh := frameHeader{
+ ContentSize: uint64(s.frameContentSize),
+ WindowSize: uint32(s.encoder.WindowSize(s.frameContentSize)),
+ SingleSegment: false,
+ Checksum: e.o.crc,
+ DictID: e.o.dict.ID(),
+ }
+
+ dst := fh.appendTo(tmp[:0])
+ s.headerWritten = true
+ s.wWg.Wait()
+ var n2 int
+ n2, s.err = s.w.Write(dst)
+ if s.err != nil {
+ return s.err
+ }
+ s.nWritten += int64(n2)
+ }
+ if s.eofWritten {
+ // Ensure we only write it once.
+ final = false
+ }
+
+ if len(s.filling) == 0 {
+ // Final block, but no data.
+ if final {
+ enc := s.encoder
+ blk := enc.Block()
+ blk.reset(nil)
+ blk.last = true
+ blk.encodeRaw(nil)
+ s.wWg.Wait()
+ _, s.err = s.w.Write(blk.output)
+ s.nWritten += int64(len(blk.output))
+ s.eofWritten = true
+ }
+ return s.err
+ }
+
+ // SYNC:
+ if e.o.concurrent == 1 {
+ src := s.filling
+ s.nInput += int64(len(s.filling))
+ if debugEncoder {
+ println("Adding sync block,", len(src), "bytes, final:", final)
+ }
+ enc := s.encoder
+ blk := enc.Block()
+ blk.reset(nil)
+ enc.Encode(blk, src)
+ blk.last = final
+ if final {
+ s.eofWritten = true
+ }
+
+ s.err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
+ if s.err != nil {
+ return s.err
+ }
+ _, s.err = s.w.Write(blk.output)
+ s.nWritten += int64(len(blk.output))
+ s.filling = s.filling[:0]
+ return s.err
+ }
+
+ // Move blocks forward.
+ s.filling, s.current, s.previous = s.previous[:0], s.filling, s.current
+ s.nInput += int64(len(s.current))
+ s.wg.Add(1)
+ if final {
+ s.eofWritten = true
+ }
+ go func(src []byte) {
+ if debugEncoder {
+ println("Adding block,", len(src), "bytes, final:", final)
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ s.err = fmt.Errorf("panic while encoding: %v", r)
+ rdebug.PrintStack()
+ }
+ s.wg.Done()
+ }()
+ enc := s.encoder
+ blk := enc.Block()
+ enc.Encode(blk, src)
+ blk.last = final
+ // Wait for pending writes.
+ s.wWg.Wait()
+ if s.writeErr != nil {
+ s.err = s.writeErr
+ return
+ }
+ // Transfer encoders from previous write block.
+ blk.swapEncoders(s.writing)
+ // Transfer recent offsets to next.
+ enc.UseBlock(s.writing)
+ s.writing = blk
+ s.wWg.Add(1)
+ go func() {
+ defer func() {
+ if r := recover(); r != nil {
+ s.writeErr = fmt.Errorf("panic while encoding/writing: %v", r)
+ rdebug.PrintStack()
+ }
+ s.wWg.Done()
+ }()
+ s.writeErr = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
+ if s.writeErr != nil {
+ return
+ }
+ _, s.writeErr = s.w.Write(blk.output)
+ s.nWritten += int64(len(blk.output))
+ }()
+ }(s.current)
+ return nil
+}
+
+// ReadFrom reads data from r until EOF or error.
+// The return value n is the number of bytes read.
+// Any error except io.EOF encountered during the read is also returned.
+//
+// The Copy function uses ReaderFrom if available.
+func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) {
+ if debugEncoder {
+ println("Using ReadFrom")
+ }
+
+ // Flush any current writes.
+ if len(e.state.filling) > 0 {
+ if err := e.nextBlock(false); err != nil {
+ return 0, err
+ }
+ }
+ e.state.filling = e.state.filling[:e.o.blockSize]
+ src := e.state.filling
+ for {
+ n2, err := r.Read(src)
+ if e.o.crc {
+ _, _ = e.state.encoder.CRC().Write(src[:n2])
+ }
+ // src is now the unfilled part...
+ src = src[n2:]
+ n += int64(n2)
+ switch err {
+ case io.EOF:
+ e.state.filling = e.state.filling[:len(e.state.filling)-len(src)]
+ if debugEncoder {
+ println("ReadFrom: got EOF final block:", len(e.state.filling))
+ }
+ return n, nil
+ case nil:
+ default:
+ if debugEncoder {
+ println("ReadFrom: got error:", err)
+ }
+ e.state.err = err
+ return n, err
+ }
+ if len(src) > 0 {
+ if debugEncoder {
+ println("ReadFrom: got space left in source:", len(src))
+ }
+ continue
+ }
+ err = e.nextBlock(false)
+ if err != nil {
+ return n, err
+ }
+ e.state.filling = e.state.filling[:e.o.blockSize]
+ src = e.state.filling
+ }
+}
+
+// Flush will send the currently written data to output
+// and block until everything has been written.
+// This should only be used on rare occasions where pushing the currently queued data is critical.
+func (e *Encoder) Flush() error {
+ s := &e.state
+ if len(s.filling) > 0 {
+ err := e.nextBlock(false)
+ if err != nil {
+ // Ignore Flush after Close.
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+ return err
+ }
+ }
+ s.wg.Wait()
+ s.wWg.Wait()
+ if s.err != nil {
+ // Ignore Flush after Close.
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+ return s.err
+ }
+ return s.writeErr
+}
+
+// Close will flush the final output and close the stream.
+// The function will block until everything has been written.
+// The Encoder can still be re-used after calling this.
+func (e *Encoder) Close() error {
+ s := &e.state
+ if s.encoder == nil {
+ return nil
+ }
+ if s.w == nil {
+ if len(s.filling) == 0 && !s.headerWritten && !s.eofWritten && s.nInput == 0 {
+ return nil
+ }
+ return errors.New("zstd: encoder has no writer")
+ }
+ err := e.nextBlock(true)
+ if err != nil {
+ if errors.Is(s.err, ErrEncoderClosed) {
+ return nil
+ }
+ return err
+ }
+ if s.frameContentSize > 0 {
+ if s.nInput != s.frameContentSize {
+ return fmt.Errorf("frame content size %d given, but %d bytes was written", s.frameContentSize, s.nInput)
+ }
+ }
+ if e.state.fullFrameWritten {
+ return s.err
+ }
+ s.wg.Wait()
+ s.wWg.Wait()
+
+ if s.err != nil {
+ return s.err
+ }
+ if s.writeErr != nil {
+ return s.writeErr
+ }
+
+ // Write CRC
+ if e.o.crc && s.err == nil {
+ // heap alloc.
+ var tmp [4]byte
+ _, s.err = s.w.Write(s.encoder.AppendCRC(tmp[:0]))
+ s.nWritten += 4
+ }
+
+ // Add padding with content from crypto/rand.Reader
+ if s.err == nil && e.o.pad > 0 {
+ add := calcSkippableFrame(s.nWritten, int64(e.o.pad))
+ frame, err := skippableFrame(s.filling[:0], add, rand.Reader)
+ if err != nil {
+ return err
+ }
+ _, s.err = s.w.Write(frame)
+ }
+ if s.err == nil {
+ s.err = ErrEncoderClosed
+ return nil
+ }
+
+ return s.err
+}
+
+// EncodeAll will encode all input in src and append it to dst.
+// This function can be called concurrently, but each call will only run on a single goroutine.
+// If empty input is given, nothing is returned, unless WithZeroFrames is specified.
+// Encoded blocks can be concatenated and the result will be the combined input stream.
+// Data compressed with EncodeAll can be decoded with the Decoder,
+// using either a stream or DecodeAll.
+func (e *Encoder) EncodeAll(src, dst []byte) []byte {
+ e.init.Do(e.initialize)
+ enc := <-e.encoders
+ defer func() {
+ e.encoders <- enc
+ }()
+ return e.encodeAll(enc, src, dst)
+}
+
+func (e *Encoder) encodeAll(enc encoder, src, dst []byte) []byte {
+ if len(src) == 0 {
+ if e.o.fullZero {
+ // Add frame header.
+ fh := frameHeader{
+ ContentSize: 0,
+ WindowSize: MinWindowSize,
+ SingleSegment: true,
+ // Adding a checksum would be a waste of space.
+ Checksum: false,
+ DictID: 0,
+ }
+ dst = fh.appendTo(dst)
+
+ // Write raw block as last one only.
+ var blk blockHeader
+ blk.setSize(0)
+ blk.setType(blockTypeRaw)
+ blk.setLast(true)
+ dst = blk.appendTo(dst)
+ }
+ return dst
+ }
+
+ // Use single segments when above minimum window and below window size.
+ single := len(src) <= e.o.windowSize && len(src) > MinWindowSize
+ if e.o.single != nil {
+ single = *e.o.single
+ }
+ fh := frameHeader{
+ ContentSize: uint64(len(src)),
+ WindowSize: uint32(enc.WindowSize(int64(len(src)))),
+ SingleSegment: single,
+ Checksum: e.o.crc,
+ DictID: e.o.dict.ID(),
+ }
+
+ // If less than 1MB, allocate a buffer up front.
+ if len(dst) == 0 && cap(dst) == 0 && len(src) < 1<<20 && !e.o.lowMem {
+ dst = make([]byte, 0, len(src))
+ }
+ dst = fh.appendTo(dst)
+
+ // If we can do everything in one block, prefer that.
+ if len(src) <= e.o.blockSize {
+ enc.Reset(e.o.dict, true)
+ // Slightly faster with no history and everything in one block.
+ if e.o.crc {
+ _, _ = enc.CRC().Write(src)
+ }
+ blk := enc.Block()
+ blk.last = true
+ if e.o.dict == nil {
+ enc.EncodeNoHist(blk, src)
+ } else {
+ enc.Encode(blk, src)
+ }
+
+ // If we got the exact same number of literals as input,
+ // assume the literals cannot be compressed.
+ oldout := blk.output
+ // Output directly to dst
+ blk.output = dst
+
+ err := blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
+ if err != nil {
+ panic(err)
+ }
+ dst = blk.output
+ blk.output = oldout
+ } else {
+ enc.Reset(e.o.dict, false)
+ blk := enc.Block()
+ for len(src) > 0 {
+ todo := src
+ if len(todo) > e.o.blockSize {
+ todo = todo[:e.o.blockSize]
+ }
+ src = src[len(todo):]
+ if e.o.crc {
+ _, _ = enc.CRC().Write(todo)
+ }
+ blk.pushOffsets()
+ enc.Encode(blk, todo)
+ if len(src) == 0 {
+ blk.last = true
+ }
+ err := blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy)
+ if err != nil {
+ panic(err)
+ }
+ dst = append(dst, blk.output...)
+ blk.reset(nil)
+ }
+ }
+ if e.o.crc {
+ dst = enc.AppendCRC(dst)
+ }
+ // Add padding with content from crypto/rand.Reader
+ if e.o.pad > 0 {
+ add := calcSkippableFrame(int64(len(dst)), int64(e.o.pad))
+ var err error
+ dst, err = skippableFrame(dst, add, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+ }
+ return dst
+}
+
+// MaxEncodedSize returns the expected maximum
+// size of an encoded block or stream.
+func (e *Encoder) MaxEncodedSize(size int) int {
+ frameHeader := 4 + 2 // magic + frame header & window descriptor
+ if e.o.dict != nil {
+ frameHeader += 4
+ }
+ // Frame content size:
+ if size < 256 {
+ frameHeader++
+ } else if size < 65536+256 {
+ frameHeader += 2
+ } else if size < math.MaxInt32 {
+ frameHeader += 4
+ } else {
+ frameHeader += 8
+ }
+ // Final crc
+ if e.o.crc {
+ frameHeader += 4
+ }
+
+ // Max overhead is 3 bytes/block.
+ // There cannot be 0 blocks.
+ blocks := (size + e.o.blockSize) / e.o.blockSize
+
+ // Combine, add padding.
+ maxSz := frameHeader + 3*blocks + size
+ if e.o.pad > 1 {
+ maxSz += calcSkippableFrame(int64(maxSz), int64(e.o.pad))
+ }
+ return maxSz
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
new file mode 100644
index 00000000..e217be0a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
@@ -0,0 +1,378 @@
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "math/bits"
+ "runtime"
+ "strings"
+)
+
+// EOption is an option for creating a encoder.
+type EOption func(*encoderOptions) error
+
+// options retains accumulated state of multiple options.
+type encoderOptions struct {
+ resetOpt bool
+ concurrent int
+ level EncoderLevel
+ single *bool
+ pad int
+ blockSize int
+ windowSize int
+ crc bool
+ fullZero bool
+ noEntropy bool
+ allLitEntropy bool
+ customWindow bool
+ customALEntropy bool
+ customBlockSize bool
+ lowMem bool
+ dict *dict
+}
+
+func (o *encoderOptions) setDefault() {
+ *o = encoderOptions{
+ concurrent: runtime.GOMAXPROCS(0),
+ crc: true,
+ single: nil,
+ blockSize: maxCompressedBlockSize,
+ windowSize: 8 << 20,
+ level: SpeedDefault,
+ allLitEntropy: false,
+ lowMem: false,
+ fullZero: true,
+ }
+}
+
+// encoder returns an encoder with the selected options.
+func (o encoderOptions) encoder() encoder {
+ switch o.level {
+ case SpeedFastest:
+ if o.dict != nil {
+ return &fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
+ }
+ return &fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
+
+ case SpeedDefault:
+ if o.dict != nil {
+ return &doubleFastEncoderDict{fastEncoderDict: fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}}
+ }
+ return &doubleFastEncoder{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
+ case SpeedBetterCompression:
+ if o.dict != nil {
+ return &betterFastEncoderDict{betterFastEncoder: betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}
+ }
+ return &betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
+ case SpeedBestCompression:
+ return &bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}
+ }
+ panic("unknown compression level")
+}
+
+// WithEncoderCRC will add CRC value to output.
+// Output will be 4 bytes larger.
+// Can be changed with ResetWithOptions.
+func WithEncoderCRC(b bool) EOption {
+ return func(o *encoderOptions) error { o.crc = b; return nil }
+}
+
+// WithEncoderConcurrency will set the concurrency,
+// meaning the maximum number of encoders to run concurrently.
+// The value supplied must be at least 0.
+// When a value of 0 is provided GOMAXPROCS will be used.
+// For streams, setting a value of 1 will disable async compression.
+// By default this will be set to GOMAXPROCS.
+// Cannot be changed with ResetWithOptions.
+func WithEncoderConcurrency(n int) EOption {
+ return func(o *encoderOptions) error {
+ if n < 0 {
+ return errors.New("concurrency must at least 0")
+ }
+ if n == 0 {
+ n = runtime.GOMAXPROCS(0)
+ }
+ if o.resetOpt && n != o.concurrent {
+ return errors.New("WithEncoderConcurrency cannot be changed on Reset")
+ }
+ o.concurrent = n
+ return nil
+ }
+}
+
+// WithWindowSize will set the maximum allowed back-reference distance.
+// The value must be a power of two between MinWindowSize and MaxWindowSize.
+// A larger value will enable better compression but allocate more memory and,
+// for above-default values, take considerably longer.
+// The default value is determined by the compression level and max 8MB.
+// Cannot be changed with ResetWithOptions.
+func WithWindowSize(n int) EOption {
+ return func(o *encoderOptions) error {
+ switch {
+ case n < MinWindowSize:
+ return fmt.Errorf("window size must be at least %d", MinWindowSize)
+ case n > MaxWindowSize:
+ return fmt.Errorf("window size must be at most %d", MaxWindowSize)
+ case (n & (n - 1)) != 0:
+ return errors.New("window size must be a power of 2")
+ }
+ if o.resetOpt && n != o.windowSize {
+ return errors.New("WithWindowSize cannot be changed on Reset")
+ }
+
+ o.windowSize = n
+ o.customWindow = true
+ if o.blockSize > o.windowSize {
+ o.blockSize = o.windowSize
+ o.customBlockSize = true
+ }
+ return nil
+ }
+}
+
+// WithEncoderPadding will add padding to all output so the size will be a multiple of n.
+// This can be used to obfuscate the exact output size or make blocks of a certain size.
+// The contents will be a skippable frame, so it will be invisible by the decoder.
+// n must be > 0 and <= 1GB, 1<<30 bytes.
+// The padded area will be filled with data from crypto/rand.Reader.
+// If `EncodeAll` is used with data already in the destination, the total size will be multiple of this.
+// Can be changed with ResetWithOptions.
+func WithEncoderPadding(n int) EOption {
+ return func(o *encoderOptions) error {
+ if n <= 0 {
+ return fmt.Errorf("padding must be at least 1")
+ }
+ // No need to waste our time.
+ if n == 1 {
+ n = 0
+ }
+ if n > 1<<30 {
+ return fmt.Errorf("padding must less than 1GB (1<<30 bytes) ")
+ }
+ o.pad = n
+ return nil
+ }
+}
+
+// EncoderLevel predefines encoder compression levels.
+// Only use the constants made available, since the actual mapping
+// of these values are very likely to change and your compression could change
+// unpredictably when upgrading the library.
+type EncoderLevel int
+
+const (
+ speedNotSet EncoderLevel = iota
+
+ // SpeedFastest will choose the fastest reasonable compression.
+ // This is roughly equivalent to the fastest Zstandard mode.
+ SpeedFastest
+
+ // SpeedDefault is the default "pretty fast" compression option.
+ // This is roughly equivalent to the default Zstandard mode (level 3).
+ SpeedDefault
+
+ // SpeedBetterCompression will yield better compression than the default.
+ // Currently it is about zstd level 7-8 with ~ 2x-3x the default CPU usage.
+ // By using this, notice that CPU usage may go up in the future.
+ SpeedBetterCompression
+
+ // SpeedBestCompression will choose the best available compression option.
+ // This will offer the best compression no matter the CPU cost.
+ SpeedBestCompression
+
+ // speedLast should be kept as the last actual compression option.
+ // The is not for external usage, but is used to keep track of the valid options.
+ speedLast
+)
+
+// EncoderLevelFromString will convert a string representation of an encoding level back
+// to a compression level. The compare is not case sensitive.
+// If the string wasn't recognized, (false, SpeedDefault) will be returned.
+func EncoderLevelFromString(s string) (bool, EncoderLevel) {
+ for l := speedNotSet + 1; l < speedLast; l++ {
+ if strings.EqualFold(s, l.String()) {
+ return true, l
+ }
+ }
+ return false, SpeedDefault
+}
+
+// EncoderLevelFromZstd will return an encoder level that closest matches the compression
+// ratio of a specific zstd compression level.
+// Many input values will provide the same compression level.
+func EncoderLevelFromZstd(level int) EncoderLevel {
+ switch {
+ case level < 3:
+ return SpeedFastest
+ case level >= 3 && level < 6:
+ return SpeedDefault
+ case level >= 6 && level < 10:
+ return SpeedBetterCompression
+ default:
+ return SpeedBestCompression
+ }
+}
+
+// String provides a string representation of the compression level.
+func (e EncoderLevel) String() string {
+ switch e {
+ case SpeedFastest:
+ return "fastest"
+ case SpeedDefault:
+ return "default"
+ case SpeedBetterCompression:
+ return "better"
+ case SpeedBestCompression:
+ return "best"
+ default:
+ return "invalid"
+ }
+}
+
+// WithEncoderLevel specifies a predefined compression level.
+// Cannot be changed with ResetWithOptions.
+func WithEncoderLevel(l EncoderLevel) EOption {
+ return func(o *encoderOptions) error {
+ switch {
+ case l <= speedNotSet || l >= speedLast:
+ return fmt.Errorf("unknown encoder level")
+ }
+ if o.resetOpt && l != o.level {
+ return errors.New("WithEncoderLevel cannot be changed on Reset")
+ }
+ o.level = l
+ if !o.customWindow {
+ switch o.level {
+ case SpeedFastest:
+ o.windowSize = 4 << 20
+ if !o.customBlockSize {
+ o.blockSize = 1 << 16
+ }
+ case SpeedDefault:
+ o.windowSize = 8 << 20
+ case SpeedBetterCompression:
+ o.windowSize = 8 << 20
+ case SpeedBestCompression:
+ o.windowSize = 8 << 20
+ }
+ }
+ if !o.customALEntropy {
+ o.allLitEntropy = l > SpeedDefault
+ }
+
+ return nil
+ }
+}
+
+// WithZeroFrames will encode 0 length input as full frames.
+// This can be needed for compatibility with zstandard usage,
+// but is not needed for this package.
+// Can be changed with ResetWithOptions.
+func WithZeroFrames(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.fullZero = b
+ return nil
+ }
+}
+
+// WithAllLitEntropyCompression will apply entropy compression if no matches are found.
+// Disabling this will skip incompressible data faster, but in cases with no matches but
+// skewed character distribution compression is lost.
+// Default value depends on the compression level selected.
+// Can be changed with ResetWithOptions.
+func WithAllLitEntropyCompression(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.customALEntropy = true
+ o.allLitEntropy = b
+ return nil
+ }
+}
+
+// WithNoEntropyCompression will always skip entropy compression of literals.
+// This can be useful if content has matches, but unlikely to benefit from entropy
+// compression. Usually the slight speed improvement is not worth enabling this.
+// Can be changed with ResetWithOptions.
+func WithNoEntropyCompression(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.noEntropy = b
+ return nil
+ }
+}
+
+// WithSingleSegment will set the "single segment" flag when EncodeAll is used.
+// If this flag is set, data must be regenerated within a single continuous memory segment.
+// In this case, Window_Descriptor byte is skipped, but Frame_Content_Size is necessarily present.
+// As a consequence, the decoder must allocate a memory segment of size equal or larger than size of your content.
+// In order to preserve the decoder from unreasonable memory requirements,
+// a decoder is allowed to reject a compressed frame which requests a memory size beyond decoder's authorized range.
+// For broader compatibility, decoders are recommended to support memory sizes of at least 8 MB.
+// This is only a recommendation, each decoder is free to support higher or lower limits, depending on local limitations.
+// If this is not specified, block encodes will automatically choose this based on the input size and the window size.
+// This setting has no effect on streamed encodes.
+// Can be changed with ResetWithOptions.
+func WithSingleSegment(b bool) EOption {
+ return func(o *encoderOptions) error {
+ o.single = &b
+ return nil
+ }
+}
+
+// WithLowerEncoderMem will trade in some memory cases trade less memory usage for
+// slower encoding speed.
+// This will not change the window size which is the primary function for reducing
+// memory usage. See WithWindowSize.
+// Cannot be changed with ResetWithOptions.
+func WithLowerEncoderMem(b bool) EOption {
+ return func(o *encoderOptions) error {
+ if o.resetOpt && b != o.lowMem {
+ return errors.New("WithLowerEncoderMem cannot be changed on Reset")
+ }
+ o.lowMem = b
+ return nil
+ }
+}
+
+// WithEncoderDict allows to register a dictionary that will be used for the encode.
+//
+// The slice dict must be in the [dictionary format] produced by
+// "zstd --train" from the Zstandard reference implementation.
+//
+// The encoder *may* choose to use no dictionary instead for certain payloads.
+// Can be changed with ResetWithOptions.
+//
+// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
+func WithEncoderDict(dict []byte) EOption {
+ return func(o *encoderOptions) error {
+ d, err := loadDict(dict)
+ if err != nil {
+ return err
+ }
+ o.dict = d
+ return nil
+ }
+}
+
+// WithEncoderDictRaw registers a dictionary that may be used by the encoder.
+//
+// The slice content may contain arbitrary data. It will be used as an initial
+// history.
+// Can be changed with ResetWithOptions.
+func WithEncoderDictRaw(id uint32, content []byte) EOption {
+ return func(o *encoderOptions) error {
+ if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
+ return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
+ }
+ o.dict = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}}
+ return nil
+ }
+}
+
+// WithEncoderDictDelete clears the dictionary, so no dictionary will be used.
+// Should be used with ResetWithOptions.
+func WithEncoderDictDelete() EOption {
+ return func(o *encoderOptions) error {
+ o.dict = nil
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go
new file mode 100644
index 00000000..d88f067e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/framedec.go
@@ -0,0 +1,412 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "io"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+type frameDec struct {
+ o decoderOptions
+ crc *xxhash.Digest
+
+ WindowSize uint64
+
+ // Frame history passed between blocks
+ history history
+
+ rawInput byteBuffer
+
+ // Byte buffer that can be reused for small input blocks.
+ bBuf byteBuf
+
+ FrameContentSize uint64
+
+ DictionaryID uint32
+ HasCheckSum bool
+ SingleSegment bool
+}
+
+const (
+ // MinWindowSize is the minimum Window Size, which is 1 KB.
+ MinWindowSize = 1 << 10
+
+ // MaxWindowSize is the maximum encoder window size
+ // and the default decoder maximum window size.
+ MaxWindowSize = 1 << 29
+)
+
+const (
+ frameMagic = "\x28\xb5\x2f\xfd"
+ skippableFrameMagic = "\x2a\x4d\x18"
+)
+
+func newFrameDec(o decoderOptions) *frameDec {
+ if o.maxWindowSize > o.maxDecodedSize {
+ o.maxWindowSize = o.maxDecodedSize
+ }
+ d := frameDec{
+ o: o,
+ }
+ return &d
+}
+
+// reset will read the frame header and prepare for block decoding.
+// If nothing can be read from the input, io.EOF will be returned.
+// Any other error indicated that the stream contained data, but
+// there was a problem.
+func (d *frameDec) reset(br byteBuffer) error {
+ d.HasCheckSum = false
+ d.WindowSize = 0
+ var signature [4]byte
+ for {
+ var err error
+ // Check if we can read more...
+ b, err := br.readSmall(1)
+ switch err {
+ case io.EOF, io.ErrUnexpectedEOF:
+ return io.EOF
+ case nil:
+ signature[0] = b[0]
+ default:
+ return err
+ }
+ // Read the rest, don't allow io.ErrUnexpectedEOF
+ b, err = br.readSmall(3)
+ switch err {
+ case io.EOF:
+ return io.EOF
+ case nil:
+ copy(signature[1:], b)
+ default:
+ return err
+ }
+
+ if string(signature[1:4]) != skippableFrameMagic || signature[0]&0xf0 != 0x50 {
+ if debugDecoder {
+ println("Not skippable", hex.EncodeToString(signature[:]), hex.EncodeToString([]byte(skippableFrameMagic)))
+ }
+ // Break if not skippable frame.
+ break
+ }
+ // Read size to skip
+ b, err = br.readSmall(4)
+ if err != nil {
+ if debugDecoder {
+ println("Reading Frame Size", err)
+ }
+ return err
+ }
+ n := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ println("Skipping frame with", n, "bytes.")
+ err = br.skipN(int64(n))
+ if err != nil {
+ if debugDecoder {
+ println("Reading discarded frame", err)
+ }
+ return err
+ }
+ }
+ if string(signature[:]) != frameMagic {
+ if debugDecoder {
+ println("Got magic numbers: ", signature, "want:", []byte(frameMagic))
+ }
+ return ErrMagicMismatch
+ }
+
+ // Read Frame_Header_Descriptor
+ fhd, err := br.readByte()
+ if err != nil {
+ if debugDecoder {
+ println("Reading Frame_Header_Descriptor", err)
+ }
+ return err
+ }
+ d.SingleSegment = fhd&(1<<5) != 0
+
+ if fhd&(1<<3) != 0 {
+ return errors.New("reserved bit set on frame header")
+ }
+
+ // Read Window_Descriptor
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor
+ d.WindowSize = 0
+ if !d.SingleSegment {
+ wd, err := br.readByte()
+ if err != nil {
+ if debugDecoder {
+ println("Reading Window_Descriptor", err)
+ }
+ return err
+ }
+ if debugDecoder {
+ printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3)
+ }
+ windowLog := 10 + (wd >> 3)
+ windowBase := uint64(1) << windowLog
+ windowAdd := (windowBase / 8) * uint64(wd&0x7)
+ d.WindowSize = windowBase + windowAdd
+ }
+
+ // Read Dictionary_ID
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
+ d.DictionaryID = 0
+ if size := fhd & 3; size != 0 {
+ if size == 3 {
+ size = 4
+ }
+
+ b, err := br.readSmall(int(size))
+ if err != nil {
+ println("Reading Dictionary_ID", err)
+ return err
+ }
+ var id uint32
+ switch len(b) {
+ case 1:
+ id = uint32(b[0])
+ case 2:
+ id = uint32(b[0]) | (uint32(b[1]) << 8)
+ case 4:
+ id = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ }
+ if debugDecoder {
+ println("Dict size", size, "ID:", id)
+ }
+ d.DictionaryID = id
+ }
+
+ // Read Frame_Content_Size
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size
+ var fcsSize int
+ v := fhd >> 6
+ switch v {
+ case 0:
+ if d.SingleSegment {
+ fcsSize = 1
+ }
+ default:
+ fcsSize = 1 << v
+ }
+ d.FrameContentSize = fcsUnknown
+ if fcsSize > 0 {
+ b, err := br.readSmall(fcsSize)
+ if err != nil {
+ println("Reading Frame content", err)
+ return err
+ }
+ switch len(b) {
+ case 1:
+ d.FrameContentSize = uint64(b[0])
+ case 2:
+ // When FCS_Field_Size is 2, the offset of 256 is added.
+ d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256
+ case 4:
+ d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24)
+ case 8:
+ d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
+ d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24)
+ d.FrameContentSize = uint64(d1) | (uint64(d2) << 32)
+ }
+ if debugDecoder {
+ println("Read FCS:", d.FrameContentSize)
+ }
+ }
+
+ // Move this to shared.
+ d.HasCheckSum = fhd&(1<<2) != 0
+ if d.HasCheckSum {
+ if d.crc == nil {
+ d.crc = xxhash.New()
+ }
+ d.crc.Reset()
+ }
+
+ if d.WindowSize > d.o.maxWindowSize {
+ if debugDecoder {
+ printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize)
+ }
+ return ErrWindowSizeExceeded
+ }
+
+ if d.WindowSize == 0 && d.SingleSegment {
+ // We may not need window in this case.
+ d.WindowSize = max(d.FrameContentSize, MinWindowSize)
+ if d.WindowSize > d.o.maxDecodedSize {
+ if debugDecoder {
+ printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize)
+ }
+ return ErrDecoderSizeExceeded
+ }
+ }
+
+ // The minimum Window_Size is 1 KB.
+ if d.WindowSize < MinWindowSize {
+ if debugDecoder {
+ println("got window size: ", d.WindowSize)
+ }
+ return ErrWindowSizeTooSmall
+ }
+ d.history.windowSize = int(d.WindowSize)
+ if !d.o.lowMem || d.history.windowSize < maxBlockSize {
+ // Alloc 2x window size if not low-mem, or window size below 2MB.
+ d.history.allocFrameBuffer = d.history.windowSize * 2
+ } else {
+ if d.o.lowMem {
+ // Alloc with 1MB extra.
+ d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize/2
+ } else {
+ // Alloc with 2MB extra.
+ d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize
+ }
+ }
+
+ if debugDecoder {
+ println("Frame: Dict:", d.DictionaryID, "FrameContentSize:", d.FrameContentSize, "singleseg:", d.SingleSegment, "window:", d.WindowSize, "crc:", d.HasCheckSum)
+ }
+
+ // history contains input - maybe we do something
+ d.rawInput = br
+ return nil
+}
+
+// next will start decoding the next block from stream.
+func (d *frameDec) next(block *blockDec) error {
+ if debugDecoder {
+ println("decoding new block")
+ }
+ err := block.reset(d.rawInput, d.WindowSize)
+ if err != nil {
+ println("block error:", err)
+ // Signal the frame decoder we have a problem.
+ block.sendErr(err)
+ return err
+ }
+ return nil
+}
+
+// checkCRC will check the checksum, assuming the frame has one.
+// Will return ErrCRCMismatch if crc check failed, otherwise nil.
+func (d *frameDec) checkCRC() error {
+ // We can overwrite upper tmp now
+ buf, err := d.rawInput.readSmall(4)
+ if err != nil {
+ println("CRC missing?", err)
+ return err
+ }
+
+ want := binary.LittleEndian.Uint32(buf[:4])
+ got := uint32(d.crc.Sum64())
+
+ if got != want {
+ if debugDecoder {
+ printf("CRC check failed: got %08x, want %08x\n", got, want)
+ }
+ return ErrCRCMismatch
+ }
+ if debugDecoder {
+ printf("CRC ok %08x\n", got)
+ }
+ return nil
+}
+
+// consumeCRC skips over the checksum, assuming the frame has one.
+func (d *frameDec) consumeCRC() error {
+ _, err := d.rawInput.readSmall(4)
+ if err != nil {
+ println("CRC missing?", err)
+ }
+ return err
+}
+
+// runDecoder will run the decoder for the remainder of the frame.
+func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) {
+ saved := d.history.b
+
+ // We use the history for output to avoid copying it.
+ d.history.b = dst
+ d.history.ignoreBuffer = len(dst)
+ // Store input length, so we only check new data.
+ crcStart := len(dst)
+ d.history.decoders.maxSyncLen = 0
+ if d.o.limitToCap {
+ d.history.decoders.maxSyncLen = uint64(cap(dst) - len(dst))
+ }
+ if d.FrameContentSize != fcsUnknown {
+ if !d.o.limitToCap || d.FrameContentSize+uint64(len(dst)) < d.history.decoders.maxSyncLen {
+ d.history.decoders.maxSyncLen = d.FrameContentSize + uint64(len(dst))
+ }
+ if d.history.decoders.maxSyncLen > d.o.maxDecodedSize {
+ if debugDecoder {
+ println("maxSyncLen:", d.history.decoders.maxSyncLen, "> maxDecodedSize:", d.o.maxDecodedSize)
+ }
+ return dst, ErrDecoderSizeExceeded
+ }
+ if debugDecoder {
+ println("maxSyncLen:", d.history.decoders.maxSyncLen)
+ }
+ if !d.o.limitToCap && uint64(cap(dst)) < d.history.decoders.maxSyncLen {
+ // Alloc for output
+ dst2 := make([]byte, len(dst), d.history.decoders.maxSyncLen+compressedBlockOverAlloc)
+ copy(dst2, dst)
+ dst = dst2
+ }
+ }
+ var err error
+ for {
+ err = dec.reset(d.rawInput, d.WindowSize)
+ if err != nil {
+ break
+ }
+ if debugDecoder {
+ println("next block:", dec)
+ }
+ err = dec.decodeBuf(&d.history)
+ if err != nil {
+ break
+ }
+ if uint64(len(d.history.b)-crcStart) > d.o.maxDecodedSize {
+ println("runDecoder: maxDecodedSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.o.maxDecodedSize)
+ err = ErrDecoderSizeExceeded
+ break
+ }
+ if d.o.limitToCap && len(d.history.b) > cap(dst) {
+ println("runDecoder: cap exceeded", uint64(len(d.history.b)), ">", cap(dst))
+ err = ErrDecoderSizeExceeded
+ break
+ }
+ if uint64(len(d.history.b)-crcStart) > d.FrameContentSize {
+ println("runDecoder: FrameContentSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.FrameContentSize)
+ err = ErrFrameSizeExceeded
+ break
+ }
+ if dec.Last {
+ break
+ }
+ if debugDecoder {
+ println("runDecoder: FrameContentSize", uint64(len(d.history.b)-crcStart), "<=", d.FrameContentSize)
+ }
+ }
+ dst = d.history.b
+ if err == nil {
+ if d.FrameContentSize != fcsUnknown && uint64(len(d.history.b)-crcStart) != d.FrameContentSize {
+ err = ErrFrameSizeMismatch
+ } else if d.HasCheckSum {
+ if d.o.ignoreChecksum {
+ err = d.consumeCRC()
+ } else {
+ d.crc.Write(dst[crcStart:])
+ err = d.checkCRC()
+ }
+ }
+ }
+ d.history.b = saved
+ return dst, err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/frameenc.go b/vendor/github.com/klauspost/compress/zstd/frameenc.go
new file mode 100644
index 00000000..667ca067
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/frameenc.go
@@ -0,0 +1,137 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "math"
+ "math/bits"
+)
+
+type frameHeader struct {
+ ContentSize uint64
+ WindowSize uint32
+ SingleSegment bool
+ Checksum bool
+ DictID uint32
+}
+
+const maxHeaderSize = 14
+
+func (f frameHeader) appendTo(dst []byte) []byte {
+ dst = append(dst, frameMagic...)
+ var fhd uint8
+ if f.Checksum {
+ fhd |= 1 << 2
+ }
+ if f.SingleSegment {
+ fhd |= 1 << 5
+ }
+
+ var dictIDContent []byte
+ if f.DictID > 0 {
+ var tmp [4]byte
+ if f.DictID < 256 {
+ fhd |= 1
+ tmp[0] = uint8(f.DictID)
+ dictIDContent = tmp[:1]
+ } else if f.DictID < 1<<16 {
+ fhd |= 2
+ binary.LittleEndian.PutUint16(tmp[:2], uint16(f.DictID))
+ dictIDContent = tmp[:2]
+ } else {
+ fhd |= 3
+ binary.LittleEndian.PutUint32(tmp[:4], f.DictID)
+ dictIDContent = tmp[:4]
+ }
+ }
+ var fcs uint8
+ if f.ContentSize >= 256 {
+ fcs++
+ }
+ if f.ContentSize >= 65536+256 {
+ fcs++
+ }
+ if f.ContentSize >= 0xffffffff {
+ fcs++
+ }
+
+ fhd |= fcs << 6
+
+ dst = append(dst, fhd)
+ if !f.SingleSegment {
+ const winLogMin = 10
+ windowLog := (bits.Len32(f.WindowSize-1) - winLogMin) << 3
+ dst = append(dst, uint8(windowLog))
+ }
+ if f.DictID > 0 {
+ dst = append(dst, dictIDContent...)
+ }
+ switch fcs {
+ case 0:
+ if f.SingleSegment {
+ dst = append(dst, uint8(f.ContentSize))
+ }
+ // Unless SingleSegment is set, framessizes < 256 are not stored.
+ case 1:
+ f.ContentSize -= 256
+ dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8))
+ case 2:
+ dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24))
+ case 3:
+ dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24),
+ uint8(f.ContentSize>>32), uint8(f.ContentSize>>40), uint8(f.ContentSize>>48), uint8(f.ContentSize>>56))
+ default:
+ panic("invalid fcs")
+ }
+ return dst
+}
+
+const skippableFrameHeader = 4 + 4
+
+// calcSkippableFrame will return a total size to be added for written
+// to be divisible by multiple.
+// The value will always be > skippableFrameHeader.
+// The function will panic if written < 0 or wantMultiple <= 0.
+func calcSkippableFrame(written, wantMultiple int64) int {
+ if wantMultiple <= 0 {
+ panic("wantMultiple <= 0")
+ }
+ if written < 0 {
+ panic("written < 0")
+ }
+ leftOver := written % wantMultiple
+ if leftOver == 0 {
+ return 0
+ }
+ toAdd := wantMultiple - leftOver
+ for toAdd < skippableFrameHeader {
+ toAdd += wantMultiple
+ }
+ return int(toAdd)
+}
+
+// skippableFrame will add a skippable frame with a total size of bytes.
+// total should be >= skippableFrameHeader and < math.MaxUint32.
+func skippableFrame(dst []byte, total int, r io.Reader) ([]byte, error) {
+ if total == 0 {
+ return dst, nil
+ }
+ if total < skippableFrameHeader {
+ return dst, fmt.Errorf("requested skippable frame (%d) < 8", total)
+ }
+ if int64(total) > math.MaxUint32 {
+ return dst, fmt.Errorf("requested skippable frame (%d) > max uint32", total)
+ }
+ dst = append(dst, 0x50, 0x2a, 0x4d, 0x18)
+ f := uint32(total - skippableFrameHeader)
+ dst = append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24))
+ start := len(dst)
+ dst = append(dst, make([]byte, f)...)
+ _, err := io.ReadFull(r, dst[start:])
+ return dst, err
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
new file mode 100644
index 00000000..2f8860a7
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go
@@ -0,0 +1,307 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+)
+
+const (
+ tablelogAbsoluteMax = 9
+)
+
+const (
+ /*!MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
+ maxMemoryUsage = tablelogAbsoluteMax + 2
+
+ maxTableLog = maxMemoryUsage - 2
+ maxTablesize = 1 << maxTableLog
+ maxTableMask = (1 << maxTableLog) - 1
+ minTablelog = 5
+ maxSymbolValue = 255
+)
+
+// fseDecoder provides temporary storage for compression and decompression.
+type fseDecoder struct {
+ dt [maxTablesize]decSymbol // Decompression table.
+ symbolLen uint16 // Length of active part of the symbol table.
+ actualTableLog uint8 // Selected tablelog.
+ maxBits uint8 // Maximum number of additional bits
+
+ // used for table creation to avoid allocations.
+ stateTable [256]uint16
+ norm [maxSymbolValue + 1]int16
+ preDefined bool
+}
+
+// tableStep returns the next table index.
+func tableStep(tableSize uint32) uint32 {
+ return (tableSize >> 1) + (tableSize >> 3) + 3
+}
+
+// readNCount will read the symbol distribution so decoding tables can be constructed.
+func (s *fseDecoder) readNCount(b *byteReader, maxSymbol uint16) error {
+ var (
+ charnum uint16
+ previous0 bool
+ )
+ if b.remain() < 4 {
+ return errors.New("input too small")
+ }
+ bitStream := b.Uint32NC()
+ nbBits := uint((bitStream & 0xF) + minTablelog) // extract tableLog
+ if nbBits > tablelogAbsoluteMax {
+ println("Invalid tablelog:", nbBits)
+ return errors.New("tableLog too large")
+ }
+ bitStream >>= 4
+ bitCount := uint(4)
+
+ s.actualTableLog = uint8(nbBits)
+ remaining := int32((1 << nbBits) + 1)
+ threshold := int32(1 << nbBits)
+ gotTotal := int32(0)
+ nbBits++
+
+ for remaining > 1 && charnum <= maxSymbol {
+ if previous0 {
+ //println("prev0")
+ n0 := charnum
+ for (bitStream & 0xFFFF) == 0xFFFF {
+ //println("24 x 0")
+ n0 += 24
+ if r := b.remain(); r > 5 {
+ b.advance(2)
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> bitCount
+ } else {
+ // end of bit stream
+ bitStream >>= 16
+ bitCount += 16
+ }
+ }
+ //printf("bitstream: %d, 0b%b", bitStream&3, bitStream)
+ for (bitStream & 3) == 3 {
+ n0 += 3
+ bitStream >>= 2
+ bitCount += 2
+ }
+ n0 += uint16(bitStream & 3)
+ bitCount += 2
+
+ if n0 > maxSymbolValue {
+ return errors.New("maxSymbolValue too small")
+ }
+ //println("inserting ", n0-charnum, "zeroes from idx", charnum, "ending before", n0)
+ for charnum < n0 {
+ s.norm[uint8(charnum)] = 0
+ charnum++
+ }
+
+ if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> bitCount
+ } else {
+ bitStream >>= 2
+ }
+ }
+
+ max := (2*threshold - 1) - remaining
+ var count int32
+
+ if int32(bitStream)&(threshold-1) < max {
+ count = int32(bitStream) & (threshold - 1)
+ if debugAsserts && nbBits < 1 {
+ panic("nbBits underflow")
+ }
+ bitCount += nbBits - 1
+ } else {
+ count = int32(bitStream) & (2*threshold - 1)
+ if count >= threshold {
+ count -= max
+ }
+ bitCount += nbBits
+ }
+
+ // extra accuracy
+ count--
+ if count < 0 {
+ // -1 means +1
+ remaining += count
+ gotTotal -= count
+ } else {
+ remaining -= count
+ gotTotal += count
+ }
+ s.norm[charnum&0xff] = int16(count)
+ charnum++
+ previous0 = count == 0
+ for remaining < threshold {
+ nbBits--
+ threshold >>= 1
+ }
+
+ if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 {
+ b.advance(bitCount >> 3)
+ bitCount &= 7
+ // The check above should make sure we can read 32 bits
+ bitStream = b.Uint32NC() >> (bitCount & 31)
+ } else {
+ bitCount -= (uint)(8 * (len(b.b) - 4 - b.off))
+ b.off = len(b.b) - 4
+ bitStream = b.Uint32() >> (bitCount & 31)
+ }
+ }
+ s.symbolLen = charnum
+ if s.symbolLen <= 1 {
+ return fmt.Errorf("symbolLen (%d) too small", s.symbolLen)
+ }
+ if s.symbolLen > maxSymbolValue+1 {
+ return fmt.Errorf("symbolLen (%d) too big", s.symbolLen)
+ }
+ if remaining != 1 {
+ return fmt.Errorf("corruption detected (remaining %d != 1)", remaining)
+ }
+ if bitCount > 32 {
+ return fmt.Errorf("corruption detected (bitCount %d > 32)", bitCount)
+ }
+ if gotTotal != 1<> 3)
+ return s.buildDtable()
+}
+
+func (s *fseDecoder) mustReadFrom(r io.Reader) {
+ fatalErr := func(err error) {
+ if err != nil {
+ panic(err)
+ }
+ }
+ // dt [maxTablesize]decSymbol // Decompression table.
+ // symbolLen uint16 // Length of active part of the symbol table.
+ // actualTableLog uint8 // Selected tablelog.
+ // maxBits uint8 // Maximum number of additional bits
+ // // used for table creation to avoid allocations.
+ // stateTable [256]uint16
+ // norm [maxSymbolValue + 1]int16
+ // preDefined bool
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.dt))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.symbolLen))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.actualTableLog))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.maxBits))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.stateTable))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.norm))
+ fatalErr(binary.Read(r, binary.LittleEndian, &s.preDefined))
+}
+
+// decSymbol contains information about a state entry,
+// Including the state offset base, the output symbol and
+// the number of bits to read for the low part of the destination state.
+// Using a composite uint64 is faster than a struct with separate members.
+type decSymbol uint64
+
+func newDecSymbol(nbits, addBits uint8, newState uint16, baseline uint32) decSymbol {
+ return decSymbol(nbits) | (decSymbol(addBits) << 8) | (decSymbol(newState) << 16) | (decSymbol(baseline) << 32)
+}
+
+func (d decSymbol) nbBits() uint8 {
+ return uint8(d)
+}
+
+func (d decSymbol) addBits() uint8 {
+ return uint8(d >> 8)
+}
+
+func (d decSymbol) newState() uint16 {
+ return uint16(d >> 16)
+}
+
+func (d decSymbol) baselineInt() int {
+ return int(d >> 32)
+}
+
+func (d *decSymbol) setNBits(nBits uint8) {
+ const mask = 0xffffffffffffff00
+ *d = (*d & mask) | decSymbol(nBits)
+}
+
+func (d *decSymbol) setAddBits(addBits uint8) {
+ const mask = 0xffffffffffff00ff
+ *d = (*d & mask) | (decSymbol(addBits) << 8)
+}
+
+func (d *decSymbol) setNewState(state uint16) {
+ const mask = 0xffffffff0000ffff
+ *d = (*d & mask) | decSymbol(state)<<16
+}
+
+func (d *decSymbol) setExt(addBits uint8, baseline uint32) {
+ const mask = 0xffff00ff
+ *d = (*d & mask) | (decSymbol(addBits) << 8) | (decSymbol(baseline) << 32)
+}
+
+// decSymbolValue returns the transformed decSymbol for the given symbol.
+func decSymbolValue(symb uint8, t []baseOffset) (decSymbol, error) {
+ if int(symb) >= len(t) {
+ return 0, fmt.Errorf("rle symbol %d >= max %d", symb, len(t))
+ }
+ lu := t[symb]
+ return newDecSymbol(0, lu.addBits, 0, lu.baseLine), nil
+}
+
+// setRLE will set the decoder til RLE mode.
+func (s *fseDecoder) setRLE(symbol decSymbol) {
+ s.actualTableLog = 0
+ s.maxBits = symbol.addBits()
+ s.dt[0] = symbol
+}
+
+// transform will transform the decoder table into a table usable for
+// decoding without having to apply the transformation while decoding.
+// The state will contain the base value and the number of bits to read.
+func (s *fseDecoder) transform(t []baseOffset) error {
+ tableSize := uint16(1 << s.actualTableLog)
+ s.maxBits = 0
+ for i, v := range s.dt[:tableSize] {
+ add := v.addBits()
+ if int(add) >= len(t) {
+ return fmt.Errorf("invalid decoding table entry %d, symbol %d >= max (%d)", i, v.addBits(), len(t))
+ }
+ lu := t[add]
+ if lu.addBits > s.maxBits {
+ s.maxBits = lu.addBits
+ }
+ v.setExt(lu.addBits, lu.baseLine)
+ s.dt[i] = v
+ }
+ return nil
+}
+
+type fseState struct {
+ dt []decSymbol
+ state decSymbol
+}
+
+// Initialize and decodeAsync first state and symbol.
+func (s *fseState) init(br *bitReader, tableLog uint8, dt []decSymbol) {
+ s.dt = dt
+ br.fill()
+ s.state = dt[br.getBits(tableLog)]
+}
+
+// final returns the current state symbol without decoding the next.
+func (s decSymbol) final() (int, uint8) {
+ return s.baselineInt(), s.addBits()
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go
new file mode 100644
index 00000000..b8c8607b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.go
@@ -0,0 +1,64 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+package zstd
+
+import (
+ "fmt"
+)
+
+type buildDtableAsmContext struct {
+ // inputs
+ stateTable *uint16
+ norm *int16
+ dt *uint64
+
+ // outputs --- set by the procedure in the case of error;
+ // for interpretation please see the error handling part below
+ errParam1 uint64
+ errParam2 uint64
+}
+
+// buildDtable_asm is an x86 assembly implementation of fseDecoder.buildDtable.
+// Function returns non-zero exit code on error.
+//
+//go:noescape
+func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int
+
+// please keep in sync with _generate/gen_fse.go
+const (
+ errorCorruptedNormalizedCounter = 1
+ errorNewStateTooBig = 2
+ errorNewStateNoBits = 3
+)
+
+// buildDtable will build the decoding table.
+func (s *fseDecoder) buildDtable() error {
+ ctx := buildDtableAsmContext{
+ stateTable: &s.stateTable[0],
+ norm: &s.norm[0],
+ dt: (*uint64)(&s.dt[0]),
+ }
+ code := buildDtable_asm(s, &ctx)
+
+ if code != 0 {
+ switch code {
+ case errorCorruptedNormalizedCounter:
+ position := ctx.errParam1
+ return fmt.Errorf("corrupted input (position=%d, expected 0)", position)
+
+ case errorNewStateTooBig:
+ newState := decSymbol(ctx.errParam1)
+ size := ctx.errParam2
+ return fmt.Errorf("newState (%d) outside table size (%d)", newState, size)
+
+ case errorNewStateNoBits:
+ newState := decSymbol(ctx.errParam1)
+ oldState := decSymbol(ctx.errParam2)
+ return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, oldState)
+
+ default:
+ return fmt.Errorf("buildDtable_asm returned unhandled nonzero code = %d", code)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
new file mode 100644
index 00000000..bcde3986
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s
@@ -0,0 +1,126 @@
+// Code generated by command: go run gen_fse.go -out ../fse_decoder_amd64.s -pkg=zstd. DO NOT EDIT.
+
+//go:build !appengine && !noasm && gc && !noasm
+
+// func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int
+TEXT ·buildDtable_asm(SB), $0-24
+ MOVQ ctx+8(FP), CX
+ MOVQ s+0(FP), DI
+
+ // Load values
+ MOVBQZX 4098(DI), DX
+ XORQ AX, AX
+ BTSQ DX, AX
+ MOVQ (CX), BX
+ MOVQ 16(CX), SI
+ LEAQ -1(AX), R8
+ MOVQ 8(CX), CX
+ MOVWQZX 4096(DI), DI
+
+ // End load values
+ // Init, lay down lowprob symbols
+ XORQ R9, R9
+ JMP init_main_loop_condition
+
+init_main_loop:
+ MOVWQSX (CX)(R9*2), R10
+ CMPW R10, $-1
+ JNE do_not_update_high_threshold
+ MOVB R9, 1(SI)(R8*8)
+ DECQ R8
+ MOVQ $0x0000000000000001, R10
+
+do_not_update_high_threshold:
+ MOVW R10, (BX)(R9*2)
+ INCQ R9
+
+init_main_loop_condition:
+ CMPQ R9, DI
+ JL init_main_loop
+
+ // Spread symbols
+ // Calculate table step
+ MOVQ AX, R9
+ SHRQ $0x01, R9
+ MOVQ AX, R10
+ SHRQ $0x03, R10
+ LEAQ 3(R9)(R10*1), R9
+
+ // Fill add bits values
+ LEAQ -1(AX), R10
+ XORQ R11, R11
+ XORQ R12, R12
+ JMP spread_main_loop_condition
+
+spread_main_loop:
+ XORQ R13, R13
+ MOVWQSX (CX)(R12*2), R14
+ JMP spread_inner_loop_condition
+
+spread_inner_loop:
+ MOVB R12, 1(SI)(R11*8)
+
+adjust_position:
+ ADDQ R9, R11
+ ANDQ R10, R11
+ CMPQ R11, R8
+ JG adjust_position
+ INCQ R13
+
+spread_inner_loop_condition:
+ CMPQ R13, R14
+ JL spread_inner_loop
+ INCQ R12
+
+spread_main_loop_condition:
+ CMPQ R12, DI
+ JL spread_main_loop
+ TESTQ R11, R11
+ JZ spread_check_ok
+ MOVQ ctx+8(FP), AX
+ MOVQ R11, 24(AX)
+ MOVQ $+1, ret+16(FP)
+ RET
+
+spread_check_ok:
+ // Build Decoding table
+ XORQ DI, DI
+
+build_table_main_table:
+ MOVBQZX 1(SI)(DI*8), CX
+ MOVWQZX (BX)(CX*2), R8
+ LEAQ 1(R8), R9
+ MOVW R9, (BX)(CX*2)
+ MOVQ R8, R9
+ BSRQ R9, R9
+ MOVQ DX, CX
+ SUBQ R9, CX
+ SHLQ CL, R8
+ SUBQ AX, R8
+ MOVB CL, (SI)(DI*8)
+ MOVW R8, 2(SI)(DI*8)
+ CMPQ R8, AX
+ JLE build_table_check1_ok
+ MOVQ ctx+8(FP), CX
+ MOVQ R8, 24(CX)
+ MOVQ AX, 32(CX)
+ MOVQ $+2, ret+16(FP)
+ RET
+
+build_table_check1_ok:
+ TESTB CL, CL
+ JNZ build_table_check2_ok
+ CMPW R8, DI
+ JNE build_table_check2_ok
+ MOVQ ctx+8(FP), AX
+ MOVQ R8, 24(AX)
+ MOVQ DI, 32(AX)
+ MOVQ $+3, ret+16(FP)
+ RET
+
+build_table_check2_ok:
+ INCQ DI
+ CMPQ DI, AX
+ JL build_table_main_table
+ MOVQ $+0, ret+16(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
new file mode 100644
index 00000000..2138f809
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go
@@ -0,0 +1,72 @@
+//go:build !amd64 || appengine || !gc || noasm
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+)
+
+// buildDtable will build the decoding table.
+func (s *fseDecoder) buildDtable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ symbolNext := s.stateTable[:256]
+
+ // Init, lay down lowprob symbols
+ {
+ for i, v := range s.norm[:s.symbolLen] {
+ if v == -1 {
+ s.dt[highThreshold].setAddBits(uint8(i))
+ highThreshold--
+ v = 1
+ }
+ symbolNext[i] = uint16(v)
+ }
+ }
+
+ // Spread symbols
+ {
+ tableMask := tableSize - 1
+ step := tableStep(tableSize)
+ position := uint32(0)
+ for ss, v := range s.norm[:s.symbolLen] {
+ for i := 0; i < int(v); i++ {
+ s.dt[position].setAddBits(uint8(ss))
+ for {
+ // lowprob area
+ position = (position + step) & tableMask
+ if position <= highThreshold {
+ break
+ }
+ }
+ }
+ }
+ if position != 0 {
+ // position must reach all cells once, otherwise normalizedCounter is incorrect
+ return errors.New("corrupted input (position != 0)")
+ }
+ }
+
+ // Build Decoding table
+ {
+ tableSize := uint16(1 << s.actualTableLog)
+ for u, v := range s.dt[:tableSize] {
+ symbol := v.addBits()
+ nextState := symbolNext[symbol]
+ symbolNext[symbol] = nextState + 1
+ nBits := s.actualTableLog - byte(highBits(uint32(nextState)))
+ s.dt[u&maxTableMask].setNBits(nBits)
+ newState := (nextState << nBits) - tableSize
+ if newState > tableSize {
+ return fmt.Errorf("newState (%d) outside table size (%d)", newState, tableSize)
+ }
+ if newState == uint16(u) && nBits == 0 {
+ // Seems weird that this is possible with nbits > 0.
+ return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, u)
+ }
+ s.dt[u&maxTableMask].setNewState(newState)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_encoder.go b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go
new file mode 100644
index 00000000..3a0f4e7f
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go
@@ -0,0 +1,701 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "math"
+)
+
+const (
+ // For encoding we only support up to
+ maxEncTableLog = 8
+ maxEncTablesize = 1 << maxTableLog
+ maxEncTableMask = (1 << maxTableLog) - 1
+ minEncTablelog = 5
+ maxEncSymbolValue = maxMatchLengthSymbol
+)
+
+// Scratch provides temporary storage for compression and decompression.
+type fseEncoder struct {
+ symbolLen uint16 // Length of active part of the symbol table.
+ actualTableLog uint8 // Selected tablelog.
+ ct cTable // Compression tables.
+ maxCount int // count of the most probable symbol
+ zeroBits bool // no bits has prob > 50%.
+ clearCount bool // clear count
+ useRLE bool // This encoder is for RLE
+ preDefined bool // This encoder is predefined.
+ reUsed bool // Set to know when the encoder has been reused.
+ rleVal uint8 // RLE Symbol
+ maxBits uint8 // Maximum output bits after transform.
+
+ // TODO: Technically zstd should be fine with 64 bytes.
+ count [256]uint32
+ norm [256]int16
+}
+
+// cTable contains tables used for compression.
+type cTable struct {
+ tableSymbol []byte
+ stateTable []uint16
+ symbolTT []symbolTransform
+}
+
+// symbolTransform contains the state transform for a symbol.
+type symbolTransform struct {
+ deltaNbBits uint32
+ deltaFindState int16
+ outBits uint8
+}
+
+// String prints values as a human readable string.
+func (s symbolTransform) String() string {
+ return fmt.Sprintf("{deltabits: %08x, findstate:%d outbits:%d}", s.deltaNbBits, s.deltaFindState, s.outBits)
+}
+
+// Histogram allows to populate the histogram and skip that step in the compression,
+// It otherwise allows to inspect the histogram when compression is done.
+// To indicate that you have populated the histogram call HistogramFinished
+// with the value of the highest populated symbol, as well as the number of entries
+// in the most populated entry. These are accepted at face value.
+func (s *fseEncoder) Histogram() *[256]uint32 {
+ return &s.count
+}
+
+// HistogramFinished can be called to indicate that the histogram has been populated.
+// maxSymbol is the index of the highest set symbol of the next data segment.
+// maxCount is the number of entries in the most populated entry.
+// These are accepted at face value.
+func (s *fseEncoder) HistogramFinished(maxSymbol uint8, maxCount int) {
+ s.maxCount = maxCount
+ s.symbolLen = uint16(maxSymbol) + 1
+ s.clearCount = maxCount != 0
+}
+
+// allocCtable will allocate tables needed for compression.
+// If existing tables a re big enough, they are simply re-used.
+func (s *fseEncoder) allocCtable() {
+ tableSize := 1 << s.actualTableLog
+ // get tableSymbol that is big enough.
+ if cap(s.ct.tableSymbol) < tableSize {
+ s.ct.tableSymbol = make([]byte, tableSize)
+ }
+ s.ct.tableSymbol = s.ct.tableSymbol[:tableSize]
+
+ ctSize := tableSize
+ if cap(s.ct.stateTable) < ctSize {
+ s.ct.stateTable = make([]uint16, ctSize)
+ }
+ s.ct.stateTable = s.ct.stateTable[:ctSize]
+
+ if cap(s.ct.symbolTT) < 256 {
+ s.ct.symbolTT = make([]symbolTransform, 256)
+ }
+ s.ct.symbolTT = s.ct.symbolTT[:256]
+}
+
+// buildCTable will populate the compression table so it is ready to be used.
+func (s *fseEncoder) buildCTable() error {
+ tableSize := uint32(1 << s.actualTableLog)
+ highThreshold := tableSize - 1
+ var cumul [256]int16
+
+ s.allocCtable()
+ tableSymbol := s.ct.tableSymbol[:tableSize]
+ // symbol start positions
+ {
+ cumul[0] = 0
+ for ui, v := range s.norm[:s.symbolLen-1] {
+ u := byte(ui) // one less than reference
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = u
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ }
+ // Encode last symbol separately to avoid overflowing u
+ u := int(s.symbolLen - 1)
+ v := s.norm[s.symbolLen-1]
+ if v == -1 {
+ // Low proba symbol
+ cumul[u+1] = cumul[u] + 1
+ tableSymbol[highThreshold] = byte(u)
+ highThreshold--
+ } else {
+ cumul[u+1] = cumul[u] + v
+ }
+ if uint32(cumul[s.symbolLen]) != tableSize {
+ return fmt.Errorf("internal error: expected cumul[s.symbolLen] (%d) == tableSize (%d)", cumul[s.symbolLen], tableSize)
+ }
+ cumul[s.symbolLen] = int16(tableSize) + 1
+ }
+ // Spread symbols
+ s.zeroBits = false
+ {
+ step := tableStep(tableSize)
+ tableMask := tableSize - 1
+ var position uint32
+ // if any symbol > largeLimit, we may have 0 bits output.
+ largeLimit := int16(1 << (s.actualTableLog - 1))
+ for ui, v := range s.norm[:s.symbolLen] {
+ symbol := byte(ui)
+ if v > largeLimit {
+ s.zeroBits = true
+ }
+ for range v {
+ tableSymbol[position] = symbol
+ position = (position + step) & tableMask
+ for position > highThreshold {
+ position = (position + step) & tableMask
+ } /* Low proba area */
+ }
+ }
+
+ // Check if we have gone through all positions
+ if position != 0 {
+ return errors.New("position!=0")
+ }
+ }
+
+ // Build table
+ table := s.ct.stateTable
+ {
+ tsi := int(tableSize)
+ for u, v := range tableSymbol {
+ // TableU16 : sorted by symbol order; gives next state value
+ table[cumul[v]] = uint16(tsi + u)
+ cumul[v]++
+ }
+ }
+
+ // Build Symbol Transformation Table
+ {
+ total := int16(0)
+ symbolTT := s.ct.symbolTT[:s.symbolLen]
+ tableLog := s.actualTableLog
+ tl := (uint32(tableLog) << 16) - (1 << tableLog)
+ for i, v := range s.norm[:s.symbolLen] {
+ switch v {
+ case 0:
+ case -1, 1:
+ symbolTT[i].deltaNbBits = tl
+ symbolTT[i].deltaFindState = total - 1
+ total++
+ default:
+ maxBitsOut := uint32(tableLog) - highBit(uint32(v-1))
+ minStatePlus := uint32(v) << maxBitsOut
+ symbolTT[i].deltaNbBits = (maxBitsOut << 16) - minStatePlus
+ symbolTT[i].deltaFindState = total - v
+ total += v
+ }
+ }
+ if total != int16(tableSize) {
+ return fmt.Errorf("total mismatch %d (got) != %d (want)", total, tableSize)
+ }
+ }
+ return nil
+}
+
+var rtbTable = [...]uint32{0, 473195, 504333, 520860, 550000, 700000, 750000, 830000}
+
+func (s *fseEncoder) setRLE(val byte) {
+ s.allocCtable()
+ s.actualTableLog = 0
+ s.ct.stateTable = s.ct.stateTable[:1]
+ s.ct.symbolTT[val] = symbolTransform{
+ deltaFindState: 0,
+ deltaNbBits: 0,
+ }
+ if debugEncoder {
+ println("setRLE: val", val, "symbolTT", s.ct.symbolTT[val])
+ }
+ s.rleVal = val
+ s.useRLE = true
+}
+
+// setBits will set output bits for the transform.
+// if nil is provided, the number of bits is equal to the index.
+func (s *fseEncoder) setBits(transform []byte) {
+ if s.reUsed || s.preDefined {
+ return
+ }
+ if s.useRLE {
+ if transform == nil {
+ s.ct.symbolTT[s.rleVal].outBits = s.rleVal
+ s.maxBits = s.rleVal
+ return
+ }
+ s.maxBits = transform[s.rleVal]
+ s.ct.symbolTT[s.rleVal].outBits = s.maxBits
+ return
+ }
+ if transform == nil {
+ for i := range s.ct.symbolTT[:s.symbolLen] {
+ s.ct.symbolTT[i].outBits = uint8(i)
+ }
+ s.maxBits = uint8(s.symbolLen - 1)
+ return
+ }
+ s.maxBits = 0
+ for i, v := range transform[:s.symbolLen] {
+ s.ct.symbolTT[i].outBits = v
+ if v > s.maxBits {
+ // We could assume bits always going up, but we play safe.
+ s.maxBits = v
+ }
+ }
+}
+
+// normalizeCount will normalize the count of the symbols so
+// the total is equal to the table size.
+// If successful, compression tables will also be made ready.
+func (s *fseEncoder) normalizeCount(length int) error {
+ if s.reUsed {
+ return nil
+ }
+ s.optimalTableLog(length)
+ var (
+ tableLog = s.actualTableLog
+ scale = 62 - uint64(tableLog)
+ step = (1 << 62) / uint64(length)
+ vStep = uint64(1) << (scale - 20)
+ stillToDistribute = int16(1 << tableLog)
+ largest int
+ largestP int16
+ lowThreshold = (uint32)(length >> tableLog)
+ )
+ if s.maxCount == length {
+ s.useRLE = true
+ return nil
+ }
+ s.useRLE = false
+ for i, cnt := range s.count[:s.symbolLen] {
+ // already handled
+ // if (count[s] == s.length) return 0; /* rle special case */
+
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ stillToDistribute--
+ } else {
+ proba := (int16)((uint64(cnt) * step) >> scale)
+ if proba < 8 {
+ restToBeat := vStep * uint64(rtbTable[proba])
+ v := uint64(cnt)*step - (uint64(proba) << scale)
+ if v > restToBeat {
+ proba++
+ }
+ }
+ if proba > largestP {
+ largestP = proba
+ largest = i
+ }
+ s.norm[i] = proba
+ stillToDistribute -= proba
+ }
+ }
+
+ if -stillToDistribute >= (s.norm[largest] >> 1) {
+ // corner case, need another normalization method
+ err := s.normalizeCount2(length)
+ if err != nil {
+ return err
+ }
+ if debugAsserts {
+ err = s.validateNorm()
+ if err != nil {
+ return err
+ }
+ }
+ return s.buildCTable()
+ }
+ s.norm[largest] += stillToDistribute
+ if debugAsserts {
+ err := s.validateNorm()
+ if err != nil {
+ return err
+ }
+ }
+ return s.buildCTable()
+}
+
+// Secondary normalization method.
+// To be used when primary method fails.
+func (s *fseEncoder) normalizeCount2(length int) error {
+ const notYetAssigned = -2
+ var (
+ distributed uint32
+ total = uint32(length)
+ tableLog = s.actualTableLog
+ lowThreshold = total >> tableLog
+ lowOne = (total * 3) >> (tableLog + 1)
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt == 0 {
+ s.norm[i] = 0
+ continue
+ }
+ if cnt <= lowThreshold {
+ s.norm[i] = -1
+ distributed++
+ total -= cnt
+ continue
+ }
+ if cnt <= lowOne {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ s.norm[i] = notYetAssigned
+ }
+ toDistribute := (1 << tableLog) - distributed
+
+ if (total / toDistribute) > lowOne {
+ // risk of rounding to zero
+ lowOne = (total * 3) / (toDistribute * 2)
+ for i, cnt := range s.count[:s.symbolLen] {
+ if (s.norm[i] == notYetAssigned) && (cnt <= lowOne) {
+ s.norm[i] = 1
+ distributed++
+ total -= cnt
+ continue
+ }
+ }
+ toDistribute = (1 << tableLog) - distributed
+ }
+ if distributed == uint32(s.symbolLen)+1 {
+ // all values are pretty poor;
+ // probably incompressible data (should have already been detected);
+ // find max, then give all remaining points to max
+ var maxV int
+ var maxC uint32
+ for i, cnt := range s.count[:s.symbolLen] {
+ if cnt > maxC {
+ maxV = i
+ maxC = cnt
+ }
+ }
+ s.norm[maxV] += int16(toDistribute)
+ return nil
+ }
+
+ if total == 0 {
+ // all of the symbols were low enough for the lowOne or lowThreshold
+ for i := uint32(0); toDistribute > 0; i = (i + 1) % (uint32(s.symbolLen)) {
+ if s.norm[i] > 0 {
+ toDistribute--
+ s.norm[i]++
+ }
+ }
+ return nil
+ }
+
+ var (
+ vStepLog = 62 - uint64(tableLog)
+ mid = uint64((1 << (vStepLog - 1)) - 1)
+ rStep = (((1 << vStepLog) * uint64(toDistribute)) + mid) / uint64(total) // scale on remaining
+ tmpTotal = mid
+ )
+ for i, cnt := range s.count[:s.symbolLen] {
+ if s.norm[i] == notYetAssigned {
+ var (
+ end = tmpTotal + uint64(cnt)*rStep
+ sStart = uint32(tmpTotal >> vStepLog)
+ sEnd = uint32(end >> vStepLog)
+ weight = sEnd - sStart
+ )
+ if weight < 1 {
+ return errors.New("weight < 1")
+ }
+ s.norm[i] = int16(weight)
+ tmpTotal = end
+ }
+ }
+ return nil
+}
+
+// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog
+func (s *fseEncoder) optimalTableLog(length int) {
+ tableLog := uint8(maxEncTableLog)
+ minBitsSrc := highBit(uint32(length)) + 1
+ minBitsSymbols := highBit(uint32(s.symbolLen-1)) + 2
+ minBits := uint8(minBitsSymbols)
+ if minBitsSrc < minBitsSymbols {
+ minBits = uint8(minBitsSrc)
+ }
+
+ maxBitsSrc := uint8(highBit(uint32(length-1))) - 2
+ if maxBitsSrc < tableLog {
+ // Accuracy can be reduced
+ tableLog = maxBitsSrc
+ }
+ if minBits > tableLog {
+ tableLog = minBits
+ }
+ // Need a minimum to safely represent all symbol values
+ if tableLog < minEncTablelog {
+ tableLog = minEncTablelog
+ }
+ if tableLog > maxEncTableLog {
+ tableLog = maxEncTableLog
+ }
+ s.actualTableLog = tableLog
+}
+
+// validateNorm validates the normalized histogram table.
+func (s *fseEncoder) validateNorm() (err error) {
+ var total int
+ for _, v := range s.norm[:s.symbolLen] {
+ if v >= 0 {
+ total += int(v)
+ } else {
+ total -= int(v)
+ }
+ }
+ defer func() {
+ if err == nil {
+ return
+ }
+ fmt.Printf("selected TableLog: %d, Symbol length: %d\n", s.actualTableLog, s.symbolLen)
+ for i, v := range s.norm[:s.symbolLen] {
+ fmt.Printf("%3d: %5d -> %4d \n", i, s.count[i], v)
+ }
+ }()
+ if total != (1 << s.actualTableLog) {
+ return fmt.Errorf("warning: Total == %d != %d", total, 1<> 3) + 3 + 2
+
+ // Write Table Size
+ bitStream = uint32(tableLog - minEncTablelog)
+ bitCount = uint(4)
+ remaining = int16(tableSize + 1) /* +1 for extra accuracy */
+ threshold = int16(tableSize)
+ nbBits = uint(tableLog + 1)
+ outP = len(out)
+ )
+ if cap(out) < outP+maxHeaderSize {
+ out = append(out, make([]byte, maxHeaderSize*3)...)
+ out = out[:len(out)-maxHeaderSize*3]
+ }
+ out = out[:outP+maxHeaderSize]
+
+ // stops at 1
+ for remaining > 1 {
+ if previous0 {
+ start := charnum
+ for s.norm[charnum] == 0 {
+ charnum++
+ }
+ for charnum >= start+24 {
+ start += 24
+ bitStream += uint32(0xFFFF) << bitCount
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ }
+ for charnum >= start+3 {
+ start += 3
+ bitStream += 3 << bitCount
+ bitCount += 2
+ }
+ bitStream += uint32(charnum-start) << bitCount
+ bitCount += 2
+ if bitCount > 16 {
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ bitCount -= 16
+ }
+ }
+
+ count := s.norm[charnum]
+ charnum++
+ max := (2*threshold - 1) - remaining
+ if count < 0 {
+ remaining += count
+ } else {
+ remaining -= count
+ }
+ count++ // +1 for extra accuracy
+ if count >= threshold {
+ count += max // [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[
+ }
+ bitStream += uint32(count) << bitCount
+ bitCount += nbBits
+ if count < max {
+ bitCount--
+ }
+
+ previous0 = count == 1
+ if remaining < 1 {
+ return nil, errors.New("internal error: remaining < 1")
+ }
+ for remaining < threshold {
+ nbBits--
+ threshold >>= 1
+ }
+
+ if bitCount > 16 {
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += 2
+ bitStream >>= 16
+ bitCount -= 16
+ }
+ }
+
+ if outP+2 > len(out) {
+ return nil, fmt.Errorf("internal error: %d > %d, maxheader: %d, sl: %d, tl: %d, normcount: %v", outP+2, len(out), maxHeaderSize, s.symbolLen, int(tableLog), s.norm[:s.symbolLen])
+ }
+ out[outP] = byte(bitStream)
+ out[outP+1] = byte(bitStream >> 8)
+ outP += int((bitCount + 7) / 8)
+
+ if charnum > s.symbolLen {
+ return nil, errors.New("internal error: charnum > s.symbolLen")
+ }
+ return out[:outP], nil
+}
+
+// Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits)
+// note 1 : assume symbolValue is valid (<= maxSymbolValue)
+// note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits *
+func (s *fseEncoder) bitCost(symbolValue uint8, accuracyLog uint32) uint32 {
+ minNbBits := s.ct.symbolTT[symbolValue].deltaNbBits >> 16
+ threshold := (minNbBits + 1) << 16
+ if debugAsserts {
+ if !(s.actualTableLog < 16) {
+ panic("!s.actualTableLog < 16")
+ }
+ // ensure enough room for renormalization double shift
+ if !(uint8(accuracyLog) < 31-s.actualTableLog) {
+ panic("!uint8(accuracyLog) < 31-s.actualTableLog")
+ }
+ }
+ tableSize := uint32(1) << s.actualTableLog
+ deltaFromThreshold := threshold - (s.ct.symbolTT[symbolValue].deltaNbBits + tableSize)
+ // linear interpolation (very approximate)
+ normalizedDeltaFromThreshold := (deltaFromThreshold << accuracyLog) >> s.actualTableLog
+ bitMultiplier := uint32(1) << accuracyLog
+ if debugAsserts {
+ if s.ct.symbolTT[symbolValue].deltaNbBits+tableSize > threshold {
+ panic("s.ct.symbolTT[symbolValue].deltaNbBits+tableSize > threshold")
+ }
+ if normalizedDeltaFromThreshold > bitMultiplier {
+ panic("normalizedDeltaFromThreshold > bitMultiplier")
+ }
+ }
+ return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold
+}
+
+// Returns the cost in bits of encoding the distribution in count using ctable.
+// Histogram should only be up to the last non-zero symbol.
+// Returns an -1 if ctable cannot represent all the symbols in count.
+func (s *fseEncoder) approxSize(hist []uint32) uint32 {
+ if int(s.symbolLen) < len(hist) {
+ // More symbols than we have.
+ return math.MaxUint32
+ }
+ if s.useRLE {
+ // We will never reuse RLE encoders.
+ return math.MaxUint32
+ }
+ const kAccuracyLog = 8
+ badCost := (uint32(s.actualTableLog) + 1) << kAccuracyLog
+ var cost uint32
+ for i, v := range hist {
+ if v == 0 {
+ continue
+ }
+ if s.norm[i] == 0 {
+ return math.MaxUint32
+ }
+ bitCost := s.bitCost(uint8(i), kAccuracyLog)
+ if bitCost > badCost {
+ return math.MaxUint32
+ }
+ cost += v * bitCost
+ }
+ return cost >> kAccuracyLog
+}
+
+// maxHeaderSize returns the maximum header size in bits.
+// This is not exact size, but we want a penalty for new tables anyway.
+func (s *fseEncoder) maxHeaderSize() uint32 {
+ if s.preDefined {
+ return 0
+ }
+ if s.useRLE {
+ return 8
+ }
+ return (((uint32(s.symbolLen) * uint32(s.actualTableLog)) >> 3) + 3) * 8
+}
+
+// cState contains the compression state of a stream.
+type cState struct {
+ bw *bitWriter
+ stateTable []uint16
+ state uint16
+}
+
+// init will initialize the compression state to the first symbol of the stream.
+func (c *cState) init(bw *bitWriter, ct *cTable, first symbolTransform) {
+ c.bw = bw
+ c.stateTable = ct.stateTable
+ if len(c.stateTable) == 1 {
+ // RLE
+ c.stateTable[0] = uint16(0)
+ c.state = 0
+ return
+ }
+ nbBitsOut := (first.deltaNbBits + (1 << 15)) >> 16
+ im := int32((nbBitsOut << 16) - first.deltaNbBits)
+ lu := (im >> nbBitsOut) + int32(first.deltaFindState)
+ c.state = c.stateTable[lu]
+}
+
+// flush will write the tablelog to the output and flush the remaining full bytes.
+func (c *cState) flush(tableLog uint8) {
+ c.bw.flush32()
+ c.bw.addBits16NC(c.state, tableLog)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/fse_predefined.go b/vendor/github.com/klauspost/compress/zstd/fse_predefined.go
new file mode 100644
index 00000000..474cb77d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/fse_predefined.go
@@ -0,0 +1,158 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "fmt"
+ "math"
+ "sync"
+)
+
+var (
+ // fsePredef are the predefined fse tables as defined here:
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#default-distributions
+ // These values are already transformed.
+ fsePredef [3]fseDecoder
+
+ // fsePredefEnc are the predefined encoder based on fse tables as defined here:
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#default-distributions
+ // These values are already transformed.
+ fsePredefEnc [3]fseEncoder
+
+ // symbolTableX contain the transformations needed for each type as defined in
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#the-codes-for-literals-lengths-match-lengths-and-offsets
+ symbolTableX [3][]baseOffset
+
+ // maxTableSymbol is the biggest supported symbol for each table type
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#the-codes-for-literals-lengths-match-lengths-and-offsets
+ maxTableSymbol = [3]uint8{tableLiteralLengths: maxLiteralLengthSymbol, tableOffsets: maxOffsetLengthSymbol, tableMatchLengths: maxMatchLengthSymbol}
+
+ // bitTables is the bits table for each table.
+ bitTables = [3][]byte{tableLiteralLengths: llBitsTable[:], tableOffsets: nil, tableMatchLengths: mlBitsTable[:]}
+)
+
+type tableIndex uint8
+
+const (
+ // indexes for fsePredef and symbolTableX
+ tableLiteralLengths tableIndex = 0
+ tableOffsets tableIndex = 1
+ tableMatchLengths tableIndex = 2
+
+ maxLiteralLengthSymbol = 35
+ maxOffsetLengthSymbol = 30
+ maxMatchLengthSymbol = 52
+)
+
+// baseOffset is used for calculating transformations.
+type baseOffset struct {
+ baseLine uint32
+ addBits uint8
+}
+
+// fillBase will precalculate base offsets with the given bit distributions.
+func fillBase(dst []baseOffset, base uint32, bits ...uint8) {
+ if len(bits) != len(dst) {
+ panic(fmt.Sprintf("len(dst) (%d) != len(bits) (%d)", len(dst), len(bits)))
+ }
+ for i, bit := range bits {
+ if base > math.MaxInt32 {
+ panic("invalid decoding table, base overflows int32")
+ }
+
+ dst[i] = baseOffset{
+ baseLine: base,
+ addBits: bit,
+ }
+ base += 1 << bit
+ }
+}
+
+var predef sync.Once
+
+func initPredefined() {
+ predef.Do(func() {
+ // Literals length codes
+ tmp := make([]baseOffset, 36)
+ for i := range tmp[:16] {
+ tmp[i] = baseOffset{
+ baseLine: uint32(i),
+ addBits: 0,
+ }
+ }
+ fillBase(tmp[16:], 16, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
+ symbolTableX[tableLiteralLengths] = tmp
+
+ // Match length codes
+ tmp = make([]baseOffset, 53)
+ for i := range tmp[:32] {
+ tmp[i] = baseOffset{
+ // The transformation adds the 3 length.
+ baseLine: uint32(i) + 3,
+ addBits: 0,
+ }
+ }
+ fillBase(tmp[32:], 35, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
+ symbolTableX[tableMatchLengths] = tmp
+
+ // Offset codes
+ tmp = make([]baseOffset, maxOffsetBits+1)
+ tmp[1] = baseOffset{
+ baseLine: 1,
+ addBits: 1,
+ }
+ fillBase(tmp[2:], 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)
+ symbolTableX[tableOffsets] = tmp
+
+ // Fill predefined tables and transform them.
+ // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#default-distributions
+ for i := range fsePredef[:] {
+ f := &fsePredef[i]
+ switch tableIndex(i) {
+ case tableLiteralLengths:
+ // https://github.com/facebook/zstd/blob/ededcfca57366461021c922720878c81a5854a0a/lib/decompress/zstd_decompress_block.c#L243
+ f.actualTableLog = 6
+ copy(f.norm[:], []int16{4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
+ -1, -1, -1, -1})
+ f.symbolLen = 36
+ case tableOffsets:
+ // https://github.com/facebook/zstd/blob/ededcfca57366461021c922720878c81a5854a0a/lib/decompress/zstd_decompress_block.c#L281
+ f.actualTableLog = 5
+ copy(f.norm[:], []int16{
+ 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1})
+ f.symbolLen = 29
+ case tableMatchLengths:
+ //https://github.com/facebook/zstd/blob/ededcfca57366461021c922720878c81a5854a0a/lib/decompress/zstd_decompress_block.c#L304
+ f.actualTableLog = 6
+ copy(f.norm[:], []int16{
+ 1, 4, 3, 2, 2, 2, 2, 2, 2, 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})
+ f.symbolLen = 53
+ }
+ if err := f.buildDtable(); err != nil {
+ panic(fmt.Errorf("building table %v: %v", tableIndex(i), err))
+ }
+ if err := f.transform(symbolTableX[i]); err != nil {
+ panic(fmt.Errorf("building table %v: %v", tableIndex(i), err))
+ }
+ f.preDefined = true
+
+ // Create encoder as well
+ enc := &fsePredefEnc[i]
+ copy(enc.norm[:], f.norm[:])
+ enc.symbolLen = f.symbolLen
+ enc.actualTableLog = f.actualTableLog
+ if err := enc.buildCTable(); err != nil {
+ panic(fmt.Errorf("building encoding table %v: %v", tableIndex(i), err))
+ }
+ enc.setBits(bitTables[i])
+ enc.preDefined = true
+ }
+ })
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/hash.go b/vendor/github.com/klauspost/compress/zstd/hash.go
new file mode 100644
index 00000000..5d73c21e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/hash.go
@@ -0,0 +1,35 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+const (
+ prime3bytes = 506832829
+ prime4bytes = 2654435761
+ prime5bytes = 889523592379
+ prime6bytes = 227718039650203
+ prime7bytes = 58295818150454627
+ prime8bytes = 0xcf1bbcdcb7a56463
+)
+
+// 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)
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/history.go b/vendor/github.com/klauspost/compress/zstd/history.go
new file mode 100644
index 00000000..09164856
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/history.go
@@ -0,0 +1,116 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "github.com/klauspost/compress/huff0"
+)
+
+// history contains the information transferred between blocks.
+type history struct {
+ // Literal decompression
+ huffTree *huff0.Scratch
+
+ // Sequence decompression
+ decoders sequenceDecs
+ recentOffsets [3]int
+
+ // History buffer...
+ b []byte
+
+ // ignoreBuffer is meant to ignore a number of bytes
+ // when checking for matches in history
+ ignoreBuffer int
+
+ windowSize int
+ allocFrameBuffer int // needed?
+ error bool
+ dict *dict
+}
+
+// reset will reset the history to initial state of a frame.
+// The history must already have been initialized to the desired size.
+func (h *history) reset() {
+ h.b = h.b[:0]
+ h.ignoreBuffer = 0
+ h.error = false
+ h.recentOffsets = [3]int{1, 4, 8}
+ h.decoders.freeDecoders()
+ h.decoders = sequenceDecs{br: h.decoders.br}
+ h.freeHuffDecoder()
+ h.huffTree = nil
+ h.dict = nil
+ //printf("history created: %+v (l: %d, c: %d)", *h, len(h.b), cap(h.b))
+}
+
+func (h *history) freeHuffDecoder() {
+ if h.huffTree != nil {
+ if h.dict == nil || h.dict.litEnc != h.huffTree {
+ huffDecoderPool.Put(h.huffTree)
+ h.huffTree = nil
+ }
+ }
+}
+
+func (h *history) setDict(dict *dict) {
+ if dict == nil {
+ return
+ }
+ h.dict = dict
+ h.decoders.litLengths = dict.llDec
+ h.decoders.offsets = dict.ofDec
+ h.decoders.matchLengths = dict.mlDec
+ h.decoders.dict = dict.content
+ h.recentOffsets = dict.offsets
+ h.huffTree = dict.litEnc
+}
+
+// append bytes to history.
+// This function will make sure there is space for it,
+// if the buffer has been allocated with enough extra space.
+func (h *history) append(b []byte) {
+ if len(b) >= h.windowSize {
+ // Discard all history by simply overwriting
+ h.b = h.b[:h.windowSize]
+ copy(h.b, b[len(b)-h.windowSize:])
+ return
+ }
+
+ // If there is space, append it.
+ if len(b) < cap(h.b)-len(h.b) {
+ h.b = append(h.b, b...)
+ return
+ }
+
+ // Move data down so we only have window size left.
+ // We know we have less than window size in b at this point.
+ discard := len(b) + len(h.b) - h.windowSize
+ copy(h.b, h.b[discard:])
+ h.b = h.b[:h.windowSize]
+ copy(h.b[h.windowSize-len(b):], b)
+}
+
+// ensureBlock will ensure there is space for at least one block...
+func (h *history) ensureBlock() {
+ if cap(h.b) < h.allocFrameBuffer {
+ h.b = make([]byte, 0, h.allocFrameBuffer)
+ return
+ }
+
+ avail := cap(h.b) - len(h.b)
+ if avail >= h.windowSize || avail > maxCompressedBlockSize {
+ return
+ }
+ // Move data down so we only have window size left.
+ // We know we have less than window size in b at this point.
+ discard := len(h.b) - h.windowSize
+ copy(h.b, h.b[discard:])
+ h.b = h.b[:h.windowSize]
+}
+
+// append bytes to history without ever discarding anything.
+func (h *history) appendKeep(b []byte) {
+ h.b = append(h.b, b...)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt
new file mode 100644
index 00000000..24b53065
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2016 Caleb Spare
+
+MIT License
+
+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/zstd/internal/xxhash/README.md b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md
new file mode 100644
index 00000000..777290d4
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md
@@ -0,0 +1,71 @@
+# xxhash
+
+VENDORED: Go to [github.com/cespare/xxhash](https://github.com/cespare/xxhash) for original package.
+
+xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a
+high-quality hashing algorithm that is much faster than anything in the Go
+standard library.
+
+This package provides a straightforward API:
+
+```
+func Sum64(b []byte) uint64
+func Sum64String(s string) uint64
+type Digest struct{ ... }
+ func New() *Digest
+```
+
+The `Digest` type implements hash.Hash64. Its key methods are:
+
+```
+func (*Digest) Write([]byte) (int, error)
+func (*Digest) WriteString(string) (int, error)
+func (*Digest) Sum64() uint64
+```
+
+The package is written with optimized pure Go and also contains even faster
+assembly implementations for amd64 and arm64. If desired, the `purego` build tag
+opts into using the Go code even on those architectures.
+
+[xxHash]: http://cyan4973.github.io/xxHash/
+
+## Compatibility
+
+This package is in a module and the latest code is in version 2 of the module.
+You need a version of Go with at least "minimal module compatibility" to use
+github.com/cespare/xxhash/v2:
+
+* 1.9.7+ for Go 1.9
+* 1.10.3+ for Go 1.10
+* Go 1.11 or later
+
+I recommend using the latest release of Go.
+
+## Benchmarks
+
+Here are some quick benchmarks comparing the pure-Go and assembly
+implementations of Sum64.
+
+| input size | purego | asm |
+| ---------- | --------- | --------- |
+| 4 B | 1.3 GB/s | 1.2 GB/s |
+| 16 B | 2.9 GB/s | 3.5 GB/s |
+| 100 B | 6.9 GB/s | 8.1 GB/s |
+| 4 KB | 11.7 GB/s | 16.7 GB/s |
+| 10 MB | 12.0 GB/s | 17.3 GB/s |
+
+These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C
+CPU using the following commands under Go 1.19.2:
+
+```
+benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$')
+benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
+```
+
+## Projects using this package
+
+- [InfluxDB](https://github.com/influxdata/influxdb)
+- [Prometheus](https://github.com/prometheus/prometheus)
+- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
+- [FreeCache](https://github.com/coocood/freecache)
+- [FastCache](https://github.com/VictoriaMetrics/fastcache)
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go
new file mode 100644
index 00000000..fc40c820
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go
@@ -0,0 +1,230 @@
+// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
+// at http://cyan4973.github.io/xxHash/.
+// THIS IS VENDORED: Go to github.com/cespare/xxhash for original package.
+
+package xxhash
+
+import (
+ "encoding/binary"
+ "errors"
+ "math/bits"
+)
+
+const (
+ prime1 uint64 = 11400714785074694791
+ prime2 uint64 = 14029467366897019727
+ prime3 uint64 = 1609587929392839161
+ prime4 uint64 = 9650029242287828579
+ prime5 uint64 = 2870177450012600261
+)
+
+// Store the primes in an array as well.
+//
+// The consts are used when possible in Go code to avoid MOVs but we need a
+// contiguous array of the assembly code.
+var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
+
+// Digest implements hash.Hash64.
+type Digest struct {
+ v1 uint64
+ v2 uint64
+ v3 uint64
+ v4 uint64
+ total uint64
+ mem [32]byte
+ n int // how much of mem is used
+}
+
+// New creates a new Digest that computes the 64-bit xxHash algorithm.
+func New() *Digest {
+ var d Digest
+ d.Reset()
+ return &d
+}
+
+// Reset clears the Digest's state so that it can be reused.
+func (d *Digest) Reset() {
+ d.v1 = primes[0] + prime2
+ d.v2 = prime2
+ d.v3 = 0
+ d.v4 = -primes[0]
+ d.total = 0
+ d.n = 0
+}
+
+// Size always returns 8 bytes.
+func (d *Digest) Size() int { return 8 }
+
+// BlockSize always returns 32 bytes.
+func (d *Digest) BlockSize() int { return 32 }
+
+// Write adds more data to d. It always returns len(b), nil.
+func (d *Digest) Write(b []byte) (n int, err error) {
+ n = len(b)
+ d.total += uint64(n)
+
+ memleft := d.mem[d.n&(len(d.mem)-1):]
+
+ if d.n+n < 32 {
+ // This new data doesn't even fill the current block.
+ copy(memleft, b)
+ d.n += n
+ return
+ }
+
+ if d.n > 0 {
+ // Finish off the partial block.
+ c := copy(memleft, b)
+ d.v1 = round(d.v1, u64(d.mem[0:8]))
+ d.v2 = round(d.v2, u64(d.mem[8:16]))
+ d.v3 = round(d.v3, u64(d.mem[16:24]))
+ d.v4 = round(d.v4, u64(d.mem[24:32]))
+ b = b[c:]
+ d.n = 0
+ }
+
+ if len(b) >= 32 {
+ // One or more full blocks left.
+ nw := writeBlocks(d, b)
+ b = b[nw:]
+ }
+
+ // Store any remaining partial block.
+ copy(d.mem[:], b)
+ d.n = len(b)
+
+ return
+}
+
+// Sum appends the current hash to b and returns the resulting slice.
+func (d *Digest) Sum(b []byte) []byte {
+ s := d.Sum64()
+ return append(
+ b,
+ byte(s>>56),
+ byte(s>>48),
+ byte(s>>40),
+ byte(s>>32),
+ byte(s>>24),
+ byte(s>>16),
+ byte(s>>8),
+ byte(s),
+ )
+}
+
+// Sum64 returns the current hash.
+func (d *Digest) Sum64() uint64 {
+ var h uint64
+
+ if d.total >= 32 {
+ v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
+ h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
+ h = mergeRound(h, v1)
+ h = mergeRound(h, v2)
+ h = mergeRound(h, v3)
+ h = mergeRound(h, v4)
+ } else {
+ h = d.v3 + prime5
+ }
+
+ h += d.total
+
+ b := d.mem[:d.n&(len(d.mem)-1)]
+ for ; len(b) >= 8; b = b[8:] {
+ k1 := round(0, u64(b[:8]))
+ h ^= k1
+ h = rol27(h)*prime1 + prime4
+ }
+ if len(b) >= 4 {
+ h ^= uint64(u32(b[:4])) * prime1
+ h = rol23(h)*prime2 + prime3
+ b = b[4:]
+ }
+ for ; len(b) > 0; b = b[1:] {
+ h ^= uint64(b[0]) * prime5
+ h = rol11(h) * prime1
+ }
+
+ h ^= h >> 33
+ h *= prime2
+ h ^= h >> 29
+ h *= prime3
+ h ^= h >> 32
+
+ return h
+}
+
+const (
+ magic = "xxh\x06"
+ marshaledSize = len(magic) + 8*5 + 32
+)
+
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (d *Digest) MarshalBinary() ([]byte, error) {
+ b := make([]byte, 0, marshaledSize)
+ b = append(b, magic...)
+ b = appendUint64(b, d.v1)
+ b = appendUint64(b, d.v2)
+ b = appendUint64(b, d.v3)
+ b = appendUint64(b, d.v4)
+ b = appendUint64(b, d.total)
+ b = append(b, d.mem[:d.n]...)
+ b = b[:len(b)+len(d.mem)-d.n]
+ return b, nil
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+func (d *Digest) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic) || string(b[:len(magic)]) != magic {
+ return errors.New("xxhash: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize {
+ return errors.New("xxhash: invalid hash state size")
+ }
+ b = b[len(magic):]
+ b, d.v1 = consumeUint64(b)
+ b, d.v2 = consumeUint64(b)
+ b, d.v3 = consumeUint64(b)
+ b, d.v4 = consumeUint64(b)
+ b, d.total = consumeUint64(b)
+ copy(d.mem[:], b)
+ d.n = int(d.total % uint64(len(d.mem)))
+ return nil
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+ var a [8]byte
+ binary.LittleEndian.PutUint64(a[:], x)
+ return append(b, a[:]...)
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ x := u64(b)
+ return b[8:], x
+}
+
+func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
+func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
+
+func round(acc, input uint64) uint64 {
+ acc += input * prime2
+ acc = rol31(acc)
+ acc *= prime1
+ return acc
+}
+
+func mergeRound(acc, val uint64) uint64 {
+ val = round(0, val)
+ acc ^= val
+ acc = acc*prime1 + prime4
+ return acc
+}
+
+func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) }
+func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) }
+func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }
+func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }
+func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }
+func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }
+func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }
+func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s
new file mode 100644
index 00000000..ddb63aa9
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s
@@ -0,0 +1,210 @@
+//go:build !appengine && gc && !purego && !noasm
+// +build !appengine
+// +build gc
+// +build !purego
+// +build !noasm
+
+#include "textflag.h"
+
+// Registers:
+#define h AX
+#define d AX
+#define p SI // pointer to advance through b
+#define n DX
+#define end BX // loop end
+#define v1 R8
+#define v2 R9
+#define v3 R10
+#define v4 R11
+#define x R12
+#define prime1 R13
+#define prime2 R14
+#define prime4 DI
+
+#define round(acc, x) \
+ IMULQ prime2, x \
+ ADDQ x, acc \
+ ROLQ $31, acc \
+ IMULQ prime1, acc
+
+// round0 performs the operation x = round(0, x).
+#define round0(x) \
+ IMULQ prime2, x \
+ ROLQ $31, x \
+ IMULQ prime1, x
+
+// mergeRound applies a merge round on the two registers acc and x.
+// It assumes that prime1, prime2, and prime4 have been loaded.
+#define mergeRound(acc, x) \
+ round0(x) \
+ XORQ x, acc \
+ IMULQ prime1, acc \
+ ADDQ prime4, acc
+
+// blockLoop processes as many 32-byte blocks as possible,
+// updating v1, v2, v3, and v4. It assumes that there is at least one block
+// to process.
+#define blockLoop() \
+loop: \
+ MOVQ +0(p), x \
+ round(v1, x) \
+ MOVQ +8(p), x \
+ round(v2, x) \
+ MOVQ +16(p), x \
+ round(v3, x) \
+ MOVQ +24(p), x \
+ round(v4, x) \
+ ADDQ $32, p \
+ CMPQ p, end \
+ JLE loop
+
+// func Sum64(b []byte) uint64
+TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
+ // Load fixed primes.
+ MOVQ ·primes+0(SB), prime1
+ MOVQ ·primes+8(SB), prime2
+ MOVQ ·primes+24(SB), prime4
+
+ // Load slice.
+ MOVQ b_base+0(FP), p
+ MOVQ b_len+8(FP), n
+ LEAQ (p)(n*1), end
+
+ // The first loop limit will be len(b)-32.
+ SUBQ $32, end
+
+ // Check whether we have at least one block.
+ CMPQ n, $32
+ JLT noBlocks
+
+ // Set up initial state (v1, v2, v3, v4).
+ MOVQ prime1, v1
+ ADDQ prime2, v1
+ MOVQ prime2, v2
+ XORQ v3, v3
+ XORQ v4, v4
+ SUBQ prime1, v4
+
+ blockLoop()
+
+ MOVQ v1, h
+ ROLQ $1, h
+ MOVQ v2, x
+ ROLQ $7, x
+ ADDQ x, h
+ MOVQ v3, x
+ ROLQ $12, x
+ ADDQ x, h
+ MOVQ v4, x
+ ROLQ $18, x
+ ADDQ x, h
+
+ mergeRound(h, v1)
+ mergeRound(h, v2)
+ mergeRound(h, v3)
+ mergeRound(h, v4)
+
+ JMP afterBlocks
+
+noBlocks:
+ MOVQ ·primes+32(SB), h
+
+afterBlocks:
+ ADDQ n, h
+
+ ADDQ $24, end
+ CMPQ p, end
+ JG try4
+
+loop8:
+ MOVQ (p), x
+ ADDQ $8, p
+ round0(x)
+ XORQ x, h
+ ROLQ $27, h
+ IMULQ prime1, h
+ ADDQ prime4, h
+
+ CMPQ p, end
+ JLE loop8
+
+try4:
+ ADDQ $4, end
+ CMPQ p, end
+ JG try1
+
+ MOVL (p), x
+ ADDQ $4, p
+ IMULQ prime1, x
+ XORQ x, h
+
+ ROLQ $23, h
+ IMULQ prime2, h
+ ADDQ ·primes+16(SB), h
+
+try1:
+ ADDQ $4, end
+ CMPQ p, end
+ JGE finalize
+
+loop1:
+ MOVBQZX (p), x
+ ADDQ $1, p
+ IMULQ ·primes+32(SB), x
+ XORQ x, h
+ ROLQ $11, h
+ IMULQ prime1, h
+
+ CMPQ p, end
+ JL loop1
+
+finalize:
+ MOVQ h, x
+ SHRQ $33, x
+ XORQ x, h
+ IMULQ prime2, h
+ MOVQ h, x
+ SHRQ $29, x
+ XORQ x, h
+ IMULQ ·primes+16(SB), h
+ MOVQ h, x
+ SHRQ $32, x
+ XORQ x, h
+
+ MOVQ h, ret+24(FP)
+ RET
+
+// func writeBlocks(d *Digest, b []byte) int
+TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
+ // Load fixed primes needed for round.
+ MOVQ ·primes+0(SB), prime1
+ MOVQ ·primes+8(SB), prime2
+
+ // Load slice.
+ MOVQ b_base+8(FP), p
+ MOVQ b_len+16(FP), n
+ LEAQ (p)(n*1), end
+ SUBQ $32, end
+
+ // Load vN from d.
+ MOVQ s+0(FP), d
+ MOVQ 0(d), v1
+ MOVQ 8(d), v2
+ MOVQ 16(d), v3
+ MOVQ 24(d), v4
+
+ // We don't need to check the loop condition here; this function is
+ // always called with at least one block of data to process.
+ blockLoop()
+
+ // Copy vN back to d.
+ MOVQ v1, 0(d)
+ MOVQ v2, 8(d)
+ MOVQ v3, 16(d)
+ MOVQ v4, 24(d)
+
+ // The number of bytes written is p minus the old base pointer.
+ SUBQ b_base+8(FP), p
+ MOVQ p, ret+32(FP)
+
+ RET
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s
new file mode 100644
index 00000000..ae7d4d32
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s
@@ -0,0 +1,184 @@
+//go:build !appengine && gc && !purego && !noasm
+// +build !appengine
+// +build gc
+// +build !purego
+// +build !noasm
+
+#include "textflag.h"
+
+// Registers:
+#define digest R1
+#define h R2 // return value
+#define p R3 // input pointer
+#define n R4 // input length
+#define nblocks R5 // n / 32
+#define prime1 R7
+#define prime2 R8
+#define prime3 R9
+#define prime4 R10
+#define prime5 R11
+#define v1 R12
+#define v2 R13
+#define v3 R14
+#define v4 R15
+#define x1 R20
+#define x2 R21
+#define x3 R22
+#define x4 R23
+
+#define round(acc, x) \
+ MADD prime2, acc, x, acc \
+ ROR $64-31, acc \
+ MUL prime1, acc
+
+// round0 performs the operation x = round(0, x).
+#define round0(x) \
+ MUL prime2, x \
+ ROR $64-31, x \
+ MUL prime1, x
+
+#define mergeRound(acc, x) \
+ round0(x) \
+ EOR x, acc \
+ MADD acc, prime4, prime1, acc
+
+// blockLoop processes as many 32-byte blocks as possible,
+// updating v1, v2, v3, and v4. It assumes that n >= 32.
+#define blockLoop() \
+ LSR $5, n, nblocks \
+ PCALIGN $16 \
+ loop: \
+ LDP.P 16(p), (x1, x2) \
+ LDP.P 16(p), (x3, x4) \
+ round(v1, x1) \
+ round(v2, x2) \
+ round(v3, x3) \
+ round(v4, x4) \
+ SUB $1, nblocks \
+ CBNZ nblocks, loop
+
+// func Sum64(b []byte) uint64
+TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32
+ LDP b_base+0(FP), (p, n)
+
+ LDP ·primes+0(SB), (prime1, prime2)
+ LDP ·primes+16(SB), (prime3, prime4)
+ MOVD ·primes+32(SB), prime5
+
+ CMP $32, n
+ CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }
+ BLT afterLoop
+
+ ADD prime1, prime2, v1
+ MOVD prime2, v2
+ MOVD $0, v3
+ NEG prime1, v4
+
+ blockLoop()
+
+ ROR $64-1, v1, x1
+ ROR $64-7, v2, x2
+ ADD x1, x2
+ ROR $64-12, v3, x3
+ ROR $64-18, v4, x4
+ ADD x3, x4
+ ADD x2, x4, h
+
+ mergeRound(h, v1)
+ mergeRound(h, v2)
+ mergeRound(h, v3)
+ mergeRound(h, v4)
+
+afterLoop:
+ ADD n, h
+
+ TBZ $4, n, try8
+ LDP.P 16(p), (x1, x2)
+
+ round0(x1)
+
+ // NOTE: here and below, sequencing the EOR after the ROR (using a
+ // rotated register) is worth a small but measurable speedup for small
+ // inputs.
+ ROR $64-27, h
+ EOR x1 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+ round0(x2)
+ ROR $64-27, h
+ EOR x2 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+try8:
+ TBZ $3, n, try4
+ MOVD.P 8(p), x1
+
+ round0(x1)
+ ROR $64-27, h
+ EOR x1 @> 64-27, h, h
+ MADD h, prime4, prime1, h
+
+try4:
+ TBZ $2, n, try2
+ MOVWU.P 4(p), x2
+
+ MUL prime1, x2
+ ROR $64-23, h
+ EOR x2 @> 64-23, h, h
+ MADD h, prime3, prime2, h
+
+try2:
+ TBZ $1, n, try1
+ MOVHU.P 2(p), x3
+ AND $255, x3, x1
+ LSR $8, x3, x2
+
+ MUL prime5, x1
+ ROR $64-11, h
+ EOR x1 @> 64-11, h, h
+ MUL prime1, h
+
+ MUL prime5, x2
+ ROR $64-11, h
+ EOR x2 @> 64-11, h, h
+ MUL prime1, h
+
+try1:
+ TBZ $0, n, finalize
+ MOVBU (p), x4
+
+ MUL prime5, x4
+ ROR $64-11, h
+ EOR x4 @> 64-11, h, h
+ MUL prime1, h
+
+finalize:
+ EOR h >> 33, h
+ MUL prime2, h
+ EOR h >> 29, h
+ MUL prime3, h
+ EOR h >> 32, h
+
+ MOVD h, ret+24(FP)
+ RET
+
+// func writeBlocks(s *Digest, b []byte) int
+TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
+ LDP ·primes+0(SB), (prime1, prime2)
+
+ // Load state. Assume v[1-4] are stored contiguously.
+ MOVD s+0(FP), digest
+ LDP 0(digest), (v1, v2)
+ LDP 16(digest), (v3, v4)
+
+ LDP b_base+8(FP), (p, n)
+
+ blockLoop()
+
+ // Store updated state.
+ STP (v1, v2), 0(digest)
+ STP (v3, v4), 16(digest)
+
+ BIC $31, n
+ MOVD n, ret+32(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go
new file mode 100644
index 00000000..d4221edf
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go
@@ -0,0 +1,16 @@
+//go:build (amd64 || arm64) && !appengine && gc && !purego && !noasm
+// +build amd64 arm64
+// +build !appengine
+// +build gc
+// +build !purego
+// +build !noasm
+
+package xxhash
+
+// Sum64 computes the 64-bit xxHash digest of b.
+//
+//go:noescape
+func Sum64(b []byte) uint64
+
+//go:noescape
+func writeBlocks(s *Digest, b []byte) int
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go
new file mode 100644
index 00000000..9576426e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go
@@ -0,0 +1,75 @@
+//go:build (!amd64 && !arm64) || appengine || !gc || purego || noasm
+
+package xxhash
+
+// Sum64 computes the 64-bit xxHash digest of b.
+func Sum64(b []byte) uint64 {
+ // A simpler version would be
+ // d := New()
+ // d.Write(b)
+ // return d.Sum64()
+ // but this is faster, particularly for small inputs.
+
+ n := len(b)
+ var h uint64
+
+ if n >= 32 {
+ v1 := primes[0] + prime2
+ v2 := prime2
+ v3 := uint64(0)
+ v4 := -primes[0]
+ for len(b) >= 32 {
+ v1 = round(v1, u64(b[0:8:len(b)]))
+ v2 = round(v2, u64(b[8:16:len(b)]))
+ v3 = round(v3, u64(b[16:24:len(b)]))
+ v4 = round(v4, u64(b[24:32:len(b)]))
+ b = b[32:len(b):len(b)]
+ }
+ h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
+ h = mergeRound(h, v1)
+ h = mergeRound(h, v2)
+ h = mergeRound(h, v3)
+ h = mergeRound(h, v4)
+ } else {
+ h = prime5
+ }
+
+ h += uint64(n)
+
+ for ; len(b) >= 8; b = b[8:] {
+ k1 := round(0, u64(b[:8]))
+ h ^= k1
+ h = rol27(h)*prime1 + prime4
+ }
+ if len(b) >= 4 {
+ h ^= uint64(u32(b[:4])) * prime1
+ h = rol23(h)*prime2 + prime3
+ b = b[4:]
+ }
+ for ; len(b) > 0; b = b[1:] {
+ h ^= uint64(b[0]) * prime5
+ h = rol11(h) * prime1
+ }
+
+ h ^= h >> 33
+ h *= prime2
+ h ^= h >> 29
+ h *= prime3
+ h ^= h >> 32
+
+ return h
+}
+
+func writeBlocks(d *Digest, b []byte) int {
+ v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
+ n := len(b)
+ for len(b) >= 32 {
+ v1 = round(v1, u64(b[0:8:len(b)]))
+ v2 = round(v2, u64(b[8:16:len(b)]))
+ v3 = round(v3, u64(b[16:24:len(b)]))
+ v4 = round(v4, u64(b[24:32:len(b)]))
+ b = b[32:len(b):len(b)]
+ }
+ d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4
+ return n - len(b)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go
new file mode 100644
index 00000000..6f3b0cb1
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go
@@ -0,0 +1,11 @@
+package xxhash
+
+// Sum64String computes the 64-bit xxHash digest of s.
+func Sum64String(s string) uint64 {
+ return Sum64([]byte(s))
+}
+
+// WriteString adds more data to d. It always returns len(s), nil.
+func (d *Digest) WriteString(s string) (n int, err error) {
+ return d.Write([]byte(s))
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go
new file mode 100644
index 00000000..1ed18927
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go
@@ -0,0 +1,15 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package zstd
+
+// 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/zstd/matchlen_amd64.s b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s
new file mode 100644
index 00000000..0782b86e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s
@@ -0,0 +1,66 @@
+// Copied from S2 implementation.
+
+//go:build !appengine && !noasm && gc && !noasm
+
+#include "textflag.h"
+
+// func matchLen(a []byte, b []byte) int
+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
+ JZ matchlen_loop_standalone
+
+#ifdef GOAMD64_v3
+ TZCNTQ BX, BX
+#else
+ BSFQ BX, BX
+#endif
+ SHRL $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/zstd/matchlen_generic.go b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go
new file mode 100644
index 00000000..379746c9
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go
@@ -0,0 +1,37 @@
+//go:build !amd64 || appengine || !gc || noasm
+
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package zstd
+
+import (
+ "math/bits"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+// 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) {
+ left := len(a)
+ for left >= 8 {
+ diff := le.Load64(a, n) ^ le.Load64(b, n)
+ if diff != 0 {
+ return n + bits.TrailingZeros64(diff)>>3
+ }
+ n += 8
+ left -= 8
+ }
+ a = a[n:]
+ b = b[n:]
+
+ for i := range a {
+ if a[i] != b[i] {
+ break
+ }
+ n++
+ }
+ return n
+
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec.go b/vendor/github.com/klauspost/compress/zstd/seqdec.go
new file mode 100644
index 00000000..0bfb0e43
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec.go
@@ -0,0 +1,500 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "errors"
+ "fmt"
+ "io"
+)
+
+type seq struct {
+ litLen uint32
+ matchLen uint32
+ offset uint32
+
+ // Codes are stored here for the encoder
+ // so they only have to be looked up once.
+ llCode, mlCode, ofCode uint8
+}
+
+type seqVals struct {
+ ll, ml, mo int
+}
+
+func (s seq) String() string {
+ if s.offset <= 3 {
+ if s.offset == 0 {
+ return fmt.Sprint("litLen:", s.litLen, ", matchLen:", s.matchLen+zstdMinMatch, ", offset: INVALID (0)")
+ }
+ return fmt.Sprint("litLen:", s.litLen, ", matchLen:", s.matchLen+zstdMinMatch, ", offset:", s.offset, " (repeat)")
+ }
+ return fmt.Sprint("litLen:", s.litLen, ", matchLen:", s.matchLen+zstdMinMatch, ", offset:", s.offset-3, " (new)")
+}
+
+type seqCompMode uint8
+
+const (
+ compModePredefined seqCompMode = iota
+ compModeRLE
+ compModeFSE
+ compModeRepeat
+)
+
+type sequenceDec struct {
+ // decoder keeps track of the current state and updates it from the bitstream.
+ fse *fseDecoder
+ state fseState
+ repeat bool
+}
+
+// init the state of the decoder with input from stream.
+func (s *sequenceDec) init(br *bitReader) error {
+ if s.fse == nil {
+ return errors.New("sequence decoder not defined")
+ }
+ s.state.init(br, s.fse.actualTableLog, s.fse.dt[:1< cap(s.out) {
+ addBytes := s.seqSize + len(s.out)
+ s.out = append(s.out, make([]byte, addBytes)...)
+ s.out = s.out[:len(s.out)-addBytes]
+ }
+
+ if debugDecoder {
+ printf("Execute %d seqs with hist %d, dict %d, literals: %d into %d bytes\n", len(seqs), len(hist), len(s.dict), len(s.literals), s.seqSize)
+ }
+
+ var t = len(s.out)
+ out := s.out[:t+s.seqSize]
+
+ for _, seq := range seqs {
+ // Add literals
+ copy(out[t:], s.literals[:seq.ll])
+ t += seq.ll
+ s.literals = s.literals[seq.ll:]
+
+ // Copy from dictionary...
+ if seq.mo > t+len(hist) || seq.mo > s.windowSize {
+ if len(s.dict) == 0 {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)", seq.mo, t+len(hist))
+ }
+
+ // we may be in dictionary.
+ dictO := len(s.dict) - (seq.mo - (t + len(hist)))
+ if dictO < 0 || dictO >= len(s.dict) {
+ return fmt.Errorf("match offset (%d) bigger than current history+dict (%d)", seq.mo, t+len(hist)+len(s.dict))
+ }
+ end := dictO + seq.ml
+ if end > len(s.dict) {
+ n := len(s.dict) - dictO
+ copy(out[t:], s.dict[dictO:])
+ t += n
+ seq.ml -= n
+ } else {
+ copy(out[t:], s.dict[dictO:end])
+ t += end - dictO
+ continue
+ }
+ }
+
+ // Copy from history.
+ if v := seq.mo - t; v > 0 {
+ // v is the start position in history from end.
+ start := len(hist) - v
+ if seq.ml > v {
+ // Some goes into current block.
+ // Copy remainder of history
+ copy(out[t:], hist[start:])
+ t += v
+ seq.ml -= v
+ } else {
+ copy(out[t:], hist[start:start+seq.ml])
+ t += seq.ml
+ continue
+ }
+ }
+ // We must be in current buffer now
+ if seq.ml > 0 {
+ start := t - seq.mo
+ if seq.ml <= t-start {
+ // No overlap
+ copy(out[t:], out[start:start+seq.ml])
+ t += seq.ml
+ continue
+ } else {
+ // Overlapping copy
+ // Extend destination slice and copy one byte at the time.
+ src := out[start : start+seq.ml]
+ dst := out[t:]
+ dst = dst[:len(src)]
+ t += len(src)
+ // Destination is the space we just added.
+ for i := range src {
+ dst[i] = src[i]
+ }
+ }
+ }
+ }
+
+ // Add final literals
+ copy(out[t:], s.literals)
+ if debugDecoder {
+ t += len(s.literals)
+ if t != len(out) {
+ panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize))
+ }
+ }
+ s.out = out
+
+ return nil
+}
+
+// decode sequences from the stream with the provided history.
+func (s *sequenceDecs) decodeSync(hist []byte) error {
+ supported, err := s.decodeSyncSimple(hist)
+ if supported {
+ return err
+ }
+
+ br := s.br
+ seqs := s.nSeqs
+ startSize := len(s.out)
+ // Grab full sizes tables, to avoid bounds checks.
+ llTable, mlTable, ofTable := s.litLengths.fse.dt[:maxTablesize], s.matchLengths.fse.dt[:maxTablesize], s.offsets.fse.dt[:maxTablesize]
+ llState, mlState, ofState := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state
+ out := s.out
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
+
+ if debugDecoder {
+ println("decodeSync: decoding", seqs, "sequences", br.remain(), "bits remain on stream")
+ }
+ for i := seqs - 1; i >= 0; i-- {
+ if br.overread() {
+ printf("reading sequence %d, exceeded available data. Overread by %d\n", seqs-i, -br.remain())
+ return io.ErrUnexpectedEOF
+ }
+ var ll, mo, ml int
+ if br.cursor > 4+((maxOffsetBits+16+16)>>3) {
+ // inlined function:
+ // ll, mo, ml = s.nextFast(br, llState, mlState, ofState)
+
+ // Final will not read from stream.
+ var llB, mlB, moB uint8
+ ll, llB = llState.final()
+ ml, mlB = mlState.final()
+ mo, moB = ofState.final()
+
+ // extra bits are stored in reverse order.
+ br.fillFast()
+ mo += br.getBits(moB)
+ if s.maxBits > 32 {
+ br.fillFast()
+ }
+ ml += br.getBits(mlB)
+ ll += br.getBits(llB)
+
+ if moB > 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = mo
+ } else {
+ // mo = s.adjustOffset(mo, ll, moB)
+ // Inlined for rather big speedup
+ if ll == 0 {
+ // There is an exception though, when current sequence's literals_length = 0.
+ // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
+ // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
+ mo++
+ }
+
+ if mo == 0 {
+ mo = s.prevOffset[0]
+ } else {
+ var temp int
+ if mo == 3 {
+ temp = s.prevOffset[0] - 1
+ } else {
+ temp = s.prevOffset[mo]
+ }
+
+ if temp == 0 {
+ // 0 is not valid; input is corrupted; force offset to 1
+ println("WARNING: temp was 0")
+ temp = 1
+ }
+
+ if mo != 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ }
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = temp
+ mo = temp
+ }
+ }
+ br.fillFast()
+ } else {
+ ll, mo, ml = s.next(br, llState, mlState, ofState)
+ br.fill()
+ }
+
+ if debugSequences {
+ println("Seq", seqs-i-1, "Litlen:", ll, "mo:", mo, "(abs) ml:", ml)
+ }
+
+ if ll > len(s.literals) {
+ return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, len(s.literals))
+ }
+ size := ll + ml + len(out)
+ if size-startSize > maxBlockSize {
+ return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+ if size > cap(out) {
+ // Not enough size, which can happen under high volume block streaming conditions
+ // but could be if destination slice is too small for sync operations.
+ // over-allocating here can create a large amount of GC pressure so we try to keep
+ // it as contained as possible
+ used := len(out) - startSize
+ addBytes := 256 + ll + ml + used>>2
+ // Clamp to max block size.
+ if used+addBytes > maxBlockSize {
+ addBytes = maxBlockSize - used
+ }
+ out = append(out, make([]byte, addBytes)...)
+ out = out[:len(out)-addBytes]
+ }
+ if ml > maxMatchLen {
+ return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
+ }
+
+ // Add literals
+ out = append(out, s.literals[:ll]...)
+ s.literals = s.literals[ll:]
+
+ if mo == 0 && ml > 0 {
+ return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
+ }
+
+ if mo > len(out)+len(hist) || mo > s.windowSize {
+ if len(s.dict) == 0 {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)", mo, len(out)+len(hist)-startSize)
+ }
+
+ // we may be in dictionary.
+ dictO := len(s.dict) - (mo - (len(out) + len(hist)))
+ if dictO < 0 || dictO >= len(s.dict) {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)", mo, len(out)+len(hist)-startSize)
+ }
+ end := dictO + ml
+ if end > len(s.dict) {
+ out = append(out, s.dict[dictO:]...)
+ ml -= len(s.dict) - dictO
+ } else {
+ out = append(out, s.dict[dictO:end]...)
+ mo = 0
+ ml = 0
+ }
+ }
+
+ // Copy from history.
+ // TODO: Blocks without history could be made to ignore this completely.
+ if v := mo - len(out); v > 0 {
+ // v is the start position in history from end.
+ start := len(hist) - v
+ if ml > v {
+ // Some goes into current block.
+ // Copy remainder of history
+ out = append(out, hist[start:]...)
+ ml -= v
+ } else {
+ out = append(out, hist[start:start+ml]...)
+ ml = 0
+ }
+ }
+ // We must be in current buffer now
+ if ml > 0 {
+ start := len(out) - mo
+ if ml <= len(out)-start {
+ // No overlap
+ out = append(out, out[start:start+ml]...)
+ } else {
+ // Overlapping copy
+ // Extend destination slice and copy one byte at the time.
+ out = out[:len(out)+ml]
+ src := out[start : start+ml]
+ // Destination is the space we just added.
+ dst := out[len(out)-ml:]
+ dst = dst[:len(src)]
+ for i := range src {
+ dst[i] = src[i]
+ }
+ }
+ }
+ if i == 0 {
+ // This is the last sequence, so we shouldn't update state.
+ break
+ }
+
+ // Manually inlined, ~ 5-20% faster
+ // Update all 3 states at once. Approx 20% faster.
+ nBits := llState.nbBits() + mlState.nbBits() + ofState.nbBits()
+ if nBits == 0 {
+ llState = llTable[llState.newState()&maxTableMask]
+ mlState = mlTable[mlState.newState()&maxTableMask]
+ ofState = ofTable[ofState.newState()&maxTableMask]
+ } else {
+ bits := br.get32BitsFast(nBits)
+
+ lowBits := uint16(bits >> ((ofState.nbBits() + mlState.nbBits()) & 31))
+ llState = llTable[(llState.newState()+lowBits)&maxTableMask]
+
+ lowBits = uint16(bits >> (ofState.nbBits() & 31))
+ lowBits &= bitMask[mlState.nbBits()&15]
+ mlState = mlTable[(mlState.newState()+lowBits)&maxTableMask]
+
+ lowBits = uint16(bits) & bitMask[ofState.nbBits()&15]
+ ofState = ofTable[(ofState.newState()+lowBits)&maxTableMask]
+ }
+ }
+
+ if size := len(s.literals) + len(out) - startSize; size > maxBlockSize {
+ return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+
+ // Add final literals
+ s.out = append(out, s.literals...)
+ return br.close()
+}
+
+var bitMask [16]uint16
+
+func init() {
+ for i := range bitMask[:] {
+ bitMask[i] = uint16((1 << uint(i)) - 1)
+ }
+}
+
+func (s *sequenceDecs) next(br *bitReader, llState, mlState, ofState decSymbol) (ll, mo, ml int) {
+ // Final will not read from stream.
+ ll, llB := llState.final()
+ ml, mlB := mlState.final()
+ mo, moB := ofState.final()
+
+ // extra bits are stored in reverse order.
+ br.fill()
+ mo += br.getBits(moB)
+ if s.maxBits > 32 {
+ br.fill()
+ }
+ // matchlength+literal length, max 32 bits
+ ml += br.getBits(mlB)
+ ll += br.getBits(llB)
+ mo = s.adjustOffset(mo, ll, moB)
+ return
+}
+
+func (s *sequenceDecs) adjustOffset(offset, litLen int, offsetB uint8) int {
+ if offsetB > 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = offset
+ return offset
+ }
+
+ if litLen == 0 {
+ // There is an exception though, when current sequence's literals_length = 0.
+ // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
+ // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
+ offset++
+ }
+
+ if offset == 0 {
+ return s.prevOffset[0]
+ }
+ var temp int
+ if offset == 3 {
+ temp = s.prevOffset[0] - 1
+ } else {
+ temp = s.prevOffset[offset]
+ }
+
+ if temp == 0 {
+ // 0 is not valid; input is corrupted; force offset to 1
+ println("temp was 0")
+ temp = 1
+ }
+
+ if offset != 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ }
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = temp
+ return temp
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
new file mode 100644
index 00000000..18c3703d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go
@@ -0,0 +1,387 @@
+//go:build amd64 && !appengine && !noasm && gc
+
+package zstd
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/klauspost/compress/internal/cpuinfo"
+)
+
+type decodeSyncAsmContext struct {
+ llTable []decSymbol
+ mlTable []decSymbol
+ ofTable []decSymbol
+ llState uint64
+ mlState uint64
+ ofState uint64
+ iteration int
+ litRemain int
+ out []byte
+ outPosition int
+ literals []byte
+ litPosition int
+ history []byte
+ windowSize int
+ ll int // set on error (not for all errors, please refer to _generate/gen.go)
+ ml int // set on error (not for all errors, please refer to _generate/gen.go)
+ mo int // set on error (not for all errors, please refer to _generate/gen.go)
+}
+
+// sequenceDecs_decodeSync_amd64 implements the main loop of sequenceDecs.decodeSync in x86 asm.
+//
+// Please refer to seqdec_generic.go for the reference implementation.
+//
+//go:noescape
+func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+
+// sequenceDecs_decodeSync_bmi2 implements the main loop of sequenceDecs.decodeSync in x86 asm with BMI2 extensions.
+//
+//go:noescape
+func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+
+// sequenceDecs_decodeSync_safe_amd64 does the same as above, but does not write more than output buffer.
+//
+//go:noescape
+func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+
+// sequenceDecs_decodeSync_safe_bmi2 does the same as above, but does not write more than output buffer.
+//
+//go:noescape
+func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+
+// decode sequences from the stream with the provided history but without a dictionary.
+func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
+ if len(s.dict) > 0 {
+ return false, nil
+ }
+ if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSize {
+ return false, nil
+ }
+
+ // FIXME: Using unsafe memory copies leads to rare, random crashes
+ // with fuzz testing. It is therefore disabled for now.
+ const useSafe = true
+ /*
+ useSafe := false
+ if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc {
+ useSafe = true
+ }
+ if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) {
+ useSafe = true
+ }
+ if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
+ useSafe = true
+ }
+ */
+
+ br := s.br
+
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
+
+ ctx := decodeSyncAsmContext{
+ llTable: s.litLengths.fse.dt[:maxTablesize],
+ mlTable: s.matchLengths.fse.dt[:maxTablesize],
+ ofTable: s.offsets.fse.dt[:maxTablesize],
+ llState: uint64(s.litLengths.state.state),
+ mlState: uint64(s.matchLengths.state.state),
+ ofState: uint64(s.offsets.state.state),
+ iteration: s.nSeqs - 1,
+ litRemain: len(s.literals),
+ out: s.out,
+ outPosition: len(s.out),
+ literals: s.literals,
+ windowSize: s.windowSize,
+ history: hist,
+ }
+
+ s.seqSize = 0
+ startSize := len(s.out)
+
+ var errCode int
+ if cpuinfo.HasBMI2() {
+ if useSafe {
+ errCode = sequenceDecs_decodeSync_safe_bmi2(s, br, &ctx)
+ } else {
+ errCode = sequenceDecs_decodeSync_bmi2(s, br, &ctx)
+ }
+ } else {
+ if useSafe {
+ errCode = sequenceDecs_decodeSync_safe_amd64(s, br, &ctx)
+ } else {
+ errCode = sequenceDecs_decodeSync_amd64(s, br, &ctx)
+ }
+ }
+ switch errCode {
+ case noError:
+ break
+
+ case errorMatchLenOfsMismatch:
+ return true, fmt.Errorf("zero matchoff and matchlen (%d) > 0", ctx.ml)
+
+ case errorMatchLenTooBig:
+ return true, fmt.Errorf("match len (%d) bigger than max allowed length", ctx.ml)
+
+ case errorMatchOffTooBig:
+ return true, fmt.Errorf("match offset (%d) bigger than current history (%d)",
+ ctx.mo, ctx.outPosition+len(hist)-startSize)
+
+ case errorNotEnoughLiterals:
+ return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available",
+ ctx.ll, ctx.litRemain+ctx.ll)
+
+ case errorOverread:
+ return true, io.ErrUnexpectedEOF
+
+ case errorNotEnoughSpace:
+ size := ctx.outPosition + ctx.ll + ctx.ml
+ if debugDecoder {
+ println("msl:", s.maxSyncLen, "cap", cap(s.out), "bef:", startSize, "sz:", size-startSize, "mbs:", maxBlockSize, "outsz:", cap(s.out)-startSize)
+ }
+ return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+
+ default:
+ return true, fmt.Errorf("sequenceDecs_decode returned erroneous code %d", errCode)
+ }
+
+ s.seqSize += ctx.litRemain
+ if s.seqSize > maxBlockSize {
+ return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+ err := br.close()
+ if err != nil {
+ printf("Closing sequences: %v, %+v\n", err, *br)
+ return true, err
+ }
+
+ s.literals = s.literals[ctx.litPosition:]
+ t := ctx.outPosition
+ s.out = s.out[:t]
+
+ // Add final literals
+ s.out = append(s.out, s.literals...)
+ if debugDecoder {
+ t += len(s.literals)
+ if t != len(s.out) {
+ panic(fmt.Errorf("length mismatch, want %d, got %d", len(s.out), t))
+ }
+ }
+
+ return true, nil
+}
+
+// --------------------------------------------------------------------------------
+
+type decodeAsmContext struct {
+ llTable []decSymbol
+ mlTable []decSymbol
+ ofTable []decSymbol
+ llState uint64
+ mlState uint64
+ ofState uint64
+ iteration int
+ seqs []seqVals
+ litRemain int
+}
+
+const noError = 0
+
+// error reported when mo == 0 && ml > 0
+const errorMatchLenOfsMismatch = 1
+
+// error reported when ml > maxMatchLen
+const errorMatchLenTooBig = 2
+
+// error reported when mo > available history or mo > s.windowSize
+const errorMatchOffTooBig = 3
+
+// error reported when the sum of literal lengths exeeceds the literal buffer size
+const errorNotEnoughLiterals = 4
+
+// error reported when capacity of `out` is too small
+const errorNotEnoughSpace = 5
+
+// error reported when bits are overread.
+const errorOverread = 6
+
+// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
+//
+// Please refer to seqdec_generic.go for the reference implementation.
+//
+//go:noescape
+func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+
+// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
+//
+// Please refer to seqdec_generic.go for the reference implementation.
+//
+//go:noescape
+func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+
+// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
+//
+//go:noescape
+func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+
+// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
+//
+//go:noescape
+func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+
+// decode sequences from the stream without the provided history.
+func (s *sequenceDecs) decode(seqs []seqVals) error {
+ br := s.br
+
+ maxBlockSize := min(s.windowSize, maxCompressedBlockSize)
+
+ ctx := decodeAsmContext{
+ llTable: s.litLengths.fse.dt[:maxTablesize],
+ mlTable: s.matchLengths.fse.dt[:maxTablesize],
+ ofTable: s.offsets.fse.dt[:maxTablesize],
+ llState: uint64(s.litLengths.state.state),
+ mlState: uint64(s.matchLengths.state.state),
+ ofState: uint64(s.offsets.state.state),
+ seqs: seqs,
+ iteration: len(seqs) - 1,
+ litRemain: len(s.literals),
+ }
+
+ if debugDecoder {
+ println("decode: decoding", len(seqs), "sequences", br.remain(), "bits remain on stream")
+ }
+
+ s.seqSize = 0
+ lte56bits := s.maxBits+s.offsets.fse.actualTableLog+s.matchLengths.fse.actualTableLog+s.litLengths.fse.actualTableLog <= 56
+ var errCode int
+ if cpuinfo.HasBMI2() {
+ if lte56bits {
+ errCode = sequenceDecs_decode_56_bmi2(s, br, &ctx)
+ } else {
+ errCode = sequenceDecs_decode_bmi2(s, br, &ctx)
+ }
+ } else {
+ if lte56bits {
+ errCode = sequenceDecs_decode_56_amd64(s, br, &ctx)
+ } else {
+ errCode = sequenceDecs_decode_amd64(s, br, &ctx)
+ }
+ }
+ if errCode != 0 {
+ i := len(seqs) - ctx.iteration - 1
+ switch errCode {
+ case errorMatchLenOfsMismatch:
+ ml := ctx.seqs[i].ml
+ return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
+
+ case errorMatchLenTooBig:
+ ml := ctx.seqs[i].ml
+ return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
+
+ case errorNotEnoughLiterals:
+ ll := ctx.seqs[i].ll
+ return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, ctx.litRemain+ll)
+ case errorOverread:
+ return io.ErrUnexpectedEOF
+ }
+
+ return fmt.Errorf("sequenceDecs_decode_amd64 returned erroneous code %d", errCode)
+ }
+
+ if ctx.litRemain < 0 {
+ return fmt.Errorf("literal count is too big: total available %d, total requested %d",
+ len(s.literals), len(s.literals)-ctx.litRemain)
+ }
+
+ s.seqSize += ctx.litRemain
+ if s.seqSize > maxBlockSize {
+ return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+ if debugDecoder {
+ println("decode: ", br.remain(), "bits remain on stream. code:", errCode)
+ }
+ err := br.close()
+ if err != nil {
+ printf("Closing sequences: %v, %+v\n", err, *br)
+ }
+ return err
+}
+
+// --------------------------------------------------------------------------------
+
+type executeAsmContext struct {
+ seqs []seqVals
+ seqIndex int
+ out []byte
+ history []byte
+ literals []byte
+ outPosition int
+ litPosition int
+ windowSize int
+}
+
+// sequenceDecs_executeSimple_amd64 implements the main loop of sequenceDecs.executeSimple in x86 asm.
+//
+// Returns false if a match offset is too big.
+//
+// Please refer to seqdec_generic.go for the reference implementation.
+//
+//go:noescape
+func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool
+
+// Same as above, but with safe memcopies
+//
+//go:noescape
+func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool
+
+// executeSimple handles cases when dictionary is not used.
+func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
+ // Ensure we have enough output size...
+ if len(s.out)+s.seqSize+compressedBlockOverAlloc > cap(s.out) {
+ addBytes := s.seqSize + len(s.out) + compressedBlockOverAlloc
+ s.out = append(s.out, make([]byte, addBytes)...)
+ s.out = s.out[:len(s.out)-addBytes]
+ }
+
+ if debugDecoder {
+ printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize)
+ }
+
+ var t = len(s.out)
+ out := s.out[:t+s.seqSize]
+
+ ctx := executeAsmContext{
+ seqs: seqs,
+ seqIndex: 0,
+ out: out,
+ history: hist,
+ outPosition: t,
+ litPosition: 0,
+ literals: s.literals,
+ windowSize: s.windowSize,
+ }
+ var ok bool
+ if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
+ ok = sequenceDecs_executeSimple_safe_amd64(&ctx)
+ } else {
+ ok = sequenceDecs_executeSimple_amd64(&ctx)
+ }
+ if !ok {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)",
+ seqs[ctx.seqIndex].mo, ctx.outPosition+len(hist))
+ }
+ s.literals = s.literals[ctx.litPosition:]
+ t = ctx.outPosition
+
+ // Add final literals
+ copy(out[t:], s.literals)
+ if debugDecoder {
+ t += len(s.literals)
+ if t != len(out) {
+ panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize))
+ }
+ }
+ s.out = out
+
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
new file mode 100644
index 00000000..a708ca6d
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s
@@ -0,0 +1,4151 @@
+// Code generated by command: go run gen.go -out ../seqdec_amd64.s -pkg=zstd. DO NOT EDIT.
+
+//go:build !appengine && !noasm && gc && !noasm
+
+// func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+// Requires: CMOV
+TEXT ·sequenceDecs_decode_amd64(SB), $8-32
+ MOVQ br+8(FP), CX
+ MOVQ 24(CX), DX
+ MOVBQZX 40(CX), BX
+ MOVQ (CX), AX
+ MOVQ 32(CX), SI
+ ADDQ SI, AX
+ MOVQ AX, (SP)
+ MOVQ ctx+16(FP), AX
+ MOVQ 72(AX), DI
+ MOVQ 80(AX), R8
+ MOVQ 88(AX), R9
+ MOVQ 104(AX), R10
+ MOVQ s+0(FP), AX
+ MOVQ 144(AX), R11
+ MOVQ 152(AX), R12
+ MOVQ 160(AX), R13
+
+sequenceDecs_decode_amd64_main_loop:
+ MOVQ (SP), R14
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ SI, $0x08
+ JL sequenceDecs_decode_amd64_fill_byte_by_byte
+ MOVQ BX, AX
+ SHRQ $0x03, AX
+ SUBQ AX, R14
+ MOVQ (R14), DX
+ SUBQ AX, SI
+ ANDQ $0x07, BX
+ JMP sequenceDecs_decode_amd64_fill_end
+
+sequenceDecs_decode_amd64_fill_byte_by_byte:
+ CMPQ SI, $0x00
+ JLE sequenceDecs_decode_amd64_fill_check_overread
+ CMPQ BX, $0x07
+ JLE sequenceDecs_decode_amd64_fill_end
+ SHLQ $0x08, DX
+ SUBQ $0x01, R14
+ SUBQ $0x01, SI
+ SUBQ $0x08, BX
+ MOVBQZX (R14), AX
+ ORQ AX, DX
+ JMP sequenceDecs_decode_amd64_fill_byte_by_byte
+
+sequenceDecs_decode_amd64_fill_check_overread:
+ CMPQ BX, $0x40
+ JA error_overread
+
+sequenceDecs_decode_amd64_fill_end:
+ // Update offset
+ MOVQ R9, AX
+ MOVQ BX, CX
+ MOVQ DX, R15
+ SHLQ CL, R15
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decode_amd64_of_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decode_amd64_of_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decode_amd64_of_update_zero
+ NEGQ CX
+ SHRQ CL, R15
+ ADDQ R15, AX
+
+sequenceDecs_decode_amd64_of_update_zero:
+ MOVQ AX, 16(R10)
+
+ // Update match length
+ MOVQ R8, AX
+ MOVQ BX, CX
+ MOVQ DX, R15
+ SHLQ CL, R15
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decode_amd64_ml_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decode_amd64_ml_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decode_amd64_ml_update_zero
+ NEGQ CX
+ SHRQ CL, R15
+ ADDQ R15, AX
+
+sequenceDecs_decode_amd64_ml_update_zero:
+ MOVQ AX, 8(R10)
+
+ // Fill bitreader to have enough for the remaining
+ CMPQ SI, $0x08
+ JL sequenceDecs_decode_amd64_fill_2_byte_by_byte
+ MOVQ BX, AX
+ SHRQ $0x03, AX
+ SUBQ AX, R14
+ MOVQ (R14), DX
+ SUBQ AX, SI
+ ANDQ $0x07, BX
+ JMP sequenceDecs_decode_amd64_fill_2_end
+
+sequenceDecs_decode_amd64_fill_2_byte_by_byte:
+ CMPQ SI, $0x00
+ JLE sequenceDecs_decode_amd64_fill_2_check_overread
+ CMPQ BX, $0x07
+ JLE sequenceDecs_decode_amd64_fill_2_end
+ SHLQ $0x08, DX
+ SUBQ $0x01, R14
+ SUBQ $0x01, SI
+ SUBQ $0x08, BX
+ MOVBQZX (R14), AX
+ ORQ AX, DX
+ JMP sequenceDecs_decode_amd64_fill_2_byte_by_byte
+
+sequenceDecs_decode_amd64_fill_2_check_overread:
+ CMPQ BX, $0x40
+ JA error_overread
+
+sequenceDecs_decode_amd64_fill_2_end:
+ // Update literal length
+ MOVQ DI, AX
+ MOVQ BX, CX
+ MOVQ DX, R15
+ SHLQ CL, R15
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decode_amd64_ll_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decode_amd64_ll_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decode_amd64_ll_update_zero
+ NEGQ CX
+ SHRQ CL, R15
+ ADDQ R15, AX
+
+sequenceDecs_decode_amd64_ll_update_zero:
+ MOVQ AX, (R10)
+
+ // Fill bitreader for state updates
+ MOVQ R14, (SP)
+ MOVQ R9, AX
+ SHRQ $0x08, AX
+ MOVBQZX AL, AX
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decode_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBQZX DI, R14
+ SHRL $0x10, DI
+ LEAQ (BX)(R14*1), CX
+ MOVQ DX, R15
+ MOVQ CX, BX
+ ROLQ CL, R15
+ MOVL $0x00000001, BP
+ MOVB R14, CL
+ SHLL CL, BP
+ DECL BP
+ ANDQ BP, R15
+ ADDQ R15, DI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Match Length State
+ MOVBQZX R8, R14
+ SHRL $0x10, R8
+ LEAQ (BX)(R14*1), CX
+ MOVQ DX, R15
+ MOVQ CX, BX
+ ROLQ CL, R15
+ MOVL $0x00000001, BP
+ MOVB R14, CL
+ SHLL CL, BP
+ DECL BP
+ ANDQ BP, R15
+ ADDQ R15, R8
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Offset State
+ MOVBQZX R9, R14
+ SHRL $0x10, R9
+ LEAQ (BX)(R14*1), CX
+ MOVQ DX, R15
+ MOVQ CX, BX
+ ROLQ CL, R15
+ MOVL $0x00000001, BP
+ MOVB R14, CL
+ SHLL CL, BP
+ DECL BP
+ ANDQ BP, R15
+ ADDQ R15, R9
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R9*8), R9
+
+sequenceDecs_decode_amd64_skip_update:
+ // Adjust offset
+ MOVQ 16(R10), CX
+ CMPQ AX, $0x01
+ JBE sequenceDecs_decode_amd64_adjust_offsetB_1_or_0
+ MOVQ R12, R13
+ MOVQ R11, R12
+ MOVQ CX, R11
+ JMP sequenceDecs_decode_amd64_after_adjust
+
+sequenceDecs_decode_amd64_adjust_offsetB_1_or_0:
+ CMPQ (R10), $0x00000000
+ JNE sequenceDecs_decode_amd64_adjust_offset_maybezero
+ INCQ CX
+ JMP sequenceDecs_decode_amd64_adjust_offset_nonzero
+
+sequenceDecs_decode_amd64_adjust_offset_maybezero:
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_amd64_adjust_offset_nonzero
+ MOVQ R11, CX
+ JMP sequenceDecs_decode_amd64_after_adjust
+
+sequenceDecs_decode_amd64_adjust_offset_nonzero:
+ CMPQ CX, $0x01
+ JB sequenceDecs_decode_amd64_adjust_zero
+ JEQ sequenceDecs_decode_amd64_adjust_one
+ CMPQ CX, $0x02
+ JA sequenceDecs_decode_amd64_adjust_three
+ JMP sequenceDecs_decode_amd64_adjust_two
+
+sequenceDecs_decode_amd64_adjust_zero:
+ MOVQ R11, AX
+ JMP sequenceDecs_decode_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_amd64_adjust_one:
+ MOVQ R12, AX
+ JMP sequenceDecs_decode_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_amd64_adjust_two:
+ MOVQ R13, AX
+ JMP sequenceDecs_decode_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_amd64_adjust_three:
+ LEAQ -1(R11), AX
+
+sequenceDecs_decode_amd64_adjust_test_temp_valid:
+ TESTQ AX, AX
+ JNZ sequenceDecs_decode_amd64_adjust_temp_valid
+ MOVQ $0x00000001, AX
+
+sequenceDecs_decode_amd64_adjust_temp_valid:
+ CMPQ CX, $0x01
+ CMOVQNE R12, R13
+ MOVQ R11, R12
+ MOVQ AX, R11
+ MOVQ AX, CX
+
+sequenceDecs_decode_amd64_after_adjust:
+ MOVQ CX, 16(R10)
+
+ // Check values
+ MOVQ 8(R10), AX
+ MOVQ (R10), R14
+ LEAQ (AX)(R14*1), R15
+ MOVQ s+0(FP), BP
+ ADDQ R15, 256(BP)
+ MOVQ ctx+16(FP), R15
+ SUBQ R14, 128(R15)
+ JS error_not_enough_literals
+ CMPQ AX, $0x00020002
+ JA sequenceDecs_decode_amd64_error_match_len_too_big
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_amd64_match_len_ofs_ok
+ TESTQ AX, AX
+ JNZ sequenceDecs_decode_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decode_amd64_match_len_ofs_ok:
+ ADDQ $0x18, R10
+ MOVQ ctx+16(FP), AX
+ DECQ 96(AX)
+ JNS sequenceDecs_decode_amd64_main_loop
+ MOVQ s+0(FP), AX
+ MOVQ R11, 144(AX)
+ MOVQ R12, 152(AX)
+ MOVQ R13, 160(AX)
+ MOVQ br+8(FP), AX
+ MOVQ DX, 24(AX)
+ MOVB BL, 40(AX)
+ MOVQ SI, 32(AX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decode_amd64_error_match_len_ofs_mismatch:
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decode_amd64_error_match_len_too_big:
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+// func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+// Requires: CMOV
+TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32
+ MOVQ br+8(FP), CX
+ MOVQ 24(CX), DX
+ MOVBQZX 40(CX), BX
+ MOVQ (CX), AX
+ MOVQ 32(CX), SI
+ ADDQ SI, AX
+ MOVQ AX, (SP)
+ MOVQ ctx+16(FP), AX
+ MOVQ 72(AX), DI
+ MOVQ 80(AX), R8
+ MOVQ 88(AX), R9
+ MOVQ 104(AX), R10
+ MOVQ s+0(FP), AX
+ MOVQ 144(AX), R11
+ MOVQ 152(AX), R12
+ MOVQ 160(AX), R13
+
+sequenceDecs_decode_56_amd64_main_loop:
+ MOVQ (SP), R14
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ SI, $0x08
+ JL sequenceDecs_decode_56_amd64_fill_byte_by_byte
+ MOVQ BX, AX
+ SHRQ $0x03, AX
+ SUBQ AX, R14
+ MOVQ (R14), DX
+ SUBQ AX, SI
+ ANDQ $0x07, BX
+ JMP sequenceDecs_decode_56_amd64_fill_end
+
+sequenceDecs_decode_56_amd64_fill_byte_by_byte:
+ CMPQ SI, $0x00
+ JLE sequenceDecs_decode_56_amd64_fill_check_overread
+ CMPQ BX, $0x07
+ JLE sequenceDecs_decode_56_amd64_fill_end
+ SHLQ $0x08, DX
+ SUBQ $0x01, R14
+ SUBQ $0x01, SI
+ SUBQ $0x08, BX
+ MOVBQZX (R14), AX
+ ORQ AX, DX
+ JMP sequenceDecs_decode_56_amd64_fill_byte_by_byte
+
+sequenceDecs_decode_56_amd64_fill_check_overread:
+ CMPQ BX, $0x40
+ JA error_overread
+
+sequenceDecs_decode_56_amd64_fill_end:
+ // Update offset
+ MOVQ R9, AX
+ MOVQ BX, CX
+ MOVQ DX, R15
+ SHLQ CL, R15
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decode_56_amd64_of_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decode_56_amd64_of_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decode_56_amd64_of_update_zero
+ NEGQ CX
+ SHRQ CL, R15
+ ADDQ R15, AX
+
+sequenceDecs_decode_56_amd64_of_update_zero:
+ MOVQ AX, 16(R10)
+
+ // Update match length
+ MOVQ R8, AX
+ MOVQ BX, CX
+ MOVQ DX, R15
+ SHLQ CL, R15
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decode_56_amd64_ml_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decode_56_amd64_ml_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decode_56_amd64_ml_update_zero
+ NEGQ CX
+ SHRQ CL, R15
+ ADDQ R15, AX
+
+sequenceDecs_decode_56_amd64_ml_update_zero:
+ MOVQ AX, 8(R10)
+
+ // Update literal length
+ MOVQ DI, AX
+ MOVQ BX, CX
+ MOVQ DX, R15
+ SHLQ CL, R15
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decode_56_amd64_ll_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decode_56_amd64_ll_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decode_56_amd64_ll_update_zero
+ NEGQ CX
+ SHRQ CL, R15
+ ADDQ R15, AX
+
+sequenceDecs_decode_56_amd64_ll_update_zero:
+ MOVQ AX, (R10)
+
+ // Fill bitreader for state updates
+ MOVQ R14, (SP)
+ MOVQ R9, AX
+ SHRQ $0x08, AX
+ MOVBQZX AL, AX
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decode_56_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBQZX DI, R14
+ SHRL $0x10, DI
+ LEAQ (BX)(R14*1), CX
+ MOVQ DX, R15
+ MOVQ CX, BX
+ ROLQ CL, R15
+ MOVL $0x00000001, BP
+ MOVB R14, CL
+ SHLL CL, BP
+ DECL BP
+ ANDQ BP, R15
+ ADDQ R15, DI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Match Length State
+ MOVBQZX R8, R14
+ SHRL $0x10, R8
+ LEAQ (BX)(R14*1), CX
+ MOVQ DX, R15
+ MOVQ CX, BX
+ ROLQ CL, R15
+ MOVL $0x00000001, BP
+ MOVB R14, CL
+ SHLL CL, BP
+ DECL BP
+ ANDQ BP, R15
+ ADDQ R15, R8
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Offset State
+ MOVBQZX R9, R14
+ SHRL $0x10, R9
+ LEAQ (BX)(R14*1), CX
+ MOVQ DX, R15
+ MOVQ CX, BX
+ ROLQ CL, R15
+ MOVL $0x00000001, BP
+ MOVB R14, CL
+ SHLL CL, BP
+ DECL BP
+ ANDQ BP, R15
+ ADDQ R15, R9
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R9*8), R9
+
+sequenceDecs_decode_56_amd64_skip_update:
+ // Adjust offset
+ MOVQ 16(R10), CX
+ CMPQ AX, $0x01
+ JBE sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0
+ MOVQ R12, R13
+ MOVQ R11, R12
+ MOVQ CX, R11
+ JMP sequenceDecs_decode_56_amd64_after_adjust
+
+sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0:
+ CMPQ (R10), $0x00000000
+ JNE sequenceDecs_decode_56_amd64_adjust_offset_maybezero
+ INCQ CX
+ JMP sequenceDecs_decode_56_amd64_adjust_offset_nonzero
+
+sequenceDecs_decode_56_amd64_adjust_offset_maybezero:
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_56_amd64_adjust_offset_nonzero
+ MOVQ R11, CX
+ JMP sequenceDecs_decode_56_amd64_after_adjust
+
+sequenceDecs_decode_56_amd64_adjust_offset_nonzero:
+ CMPQ CX, $0x01
+ JB sequenceDecs_decode_56_amd64_adjust_zero
+ JEQ sequenceDecs_decode_56_amd64_adjust_one
+ CMPQ CX, $0x02
+ JA sequenceDecs_decode_56_amd64_adjust_three
+ JMP sequenceDecs_decode_56_amd64_adjust_two
+
+sequenceDecs_decode_56_amd64_adjust_zero:
+ MOVQ R11, AX
+ JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_56_amd64_adjust_one:
+ MOVQ R12, AX
+ JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_56_amd64_adjust_two:
+ MOVQ R13, AX
+ JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid
+
+sequenceDecs_decode_56_amd64_adjust_three:
+ LEAQ -1(R11), AX
+
+sequenceDecs_decode_56_amd64_adjust_test_temp_valid:
+ TESTQ AX, AX
+ JNZ sequenceDecs_decode_56_amd64_adjust_temp_valid
+ MOVQ $0x00000001, AX
+
+sequenceDecs_decode_56_amd64_adjust_temp_valid:
+ CMPQ CX, $0x01
+ CMOVQNE R12, R13
+ MOVQ R11, R12
+ MOVQ AX, R11
+ MOVQ AX, CX
+
+sequenceDecs_decode_56_amd64_after_adjust:
+ MOVQ CX, 16(R10)
+
+ // Check values
+ MOVQ 8(R10), AX
+ MOVQ (R10), R14
+ LEAQ (AX)(R14*1), R15
+ MOVQ s+0(FP), BP
+ ADDQ R15, 256(BP)
+ MOVQ ctx+16(FP), R15
+ SUBQ R14, 128(R15)
+ JS error_not_enough_literals
+ CMPQ AX, $0x00020002
+ JA sequenceDecs_decode_56_amd64_error_match_len_too_big
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_56_amd64_match_len_ofs_ok
+ TESTQ AX, AX
+ JNZ sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decode_56_amd64_match_len_ofs_ok:
+ ADDQ $0x18, R10
+ MOVQ ctx+16(FP), AX
+ DECQ 96(AX)
+ JNS sequenceDecs_decode_56_amd64_main_loop
+ MOVQ s+0(FP), AX
+ MOVQ R11, 144(AX)
+ MOVQ R12, 152(AX)
+ MOVQ R13, 160(AX)
+ MOVQ br+8(FP), AX
+ MOVQ DX, 24(AX)
+ MOVB BL, 40(AX)
+ MOVQ SI, 32(AX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch:
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decode_56_amd64_error_match_len_too_big:
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+// func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+// Requires: BMI, BMI2, CMOV
+TEXT ·sequenceDecs_decode_bmi2(SB), $8-32
+ MOVQ br+8(FP), BX
+ MOVQ 24(BX), AX
+ MOVBQZX 40(BX), DX
+ MOVQ (BX), CX
+ MOVQ 32(BX), BX
+ ADDQ BX, CX
+ MOVQ CX, (SP)
+ MOVQ ctx+16(FP), CX
+ MOVQ 72(CX), SI
+ MOVQ 80(CX), DI
+ MOVQ 88(CX), R8
+ MOVQ 104(CX), R9
+ MOVQ s+0(FP), CX
+ MOVQ 144(CX), R10
+ MOVQ 152(CX), R11
+ MOVQ 160(CX), R12
+
+sequenceDecs_decode_bmi2_main_loop:
+ MOVQ (SP), R13
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ BX, $0x08
+ JL sequenceDecs_decode_bmi2_fill_byte_by_byte
+ MOVQ DX, CX
+ SHRQ $0x03, CX
+ SUBQ CX, R13
+ MOVQ (R13), AX
+ SUBQ CX, BX
+ ANDQ $0x07, DX
+ JMP sequenceDecs_decode_bmi2_fill_end
+
+sequenceDecs_decode_bmi2_fill_byte_by_byte:
+ CMPQ BX, $0x00
+ JLE sequenceDecs_decode_bmi2_fill_check_overread
+ CMPQ DX, $0x07
+ JLE sequenceDecs_decode_bmi2_fill_end
+ SHLQ $0x08, AX
+ SUBQ $0x01, R13
+ SUBQ $0x01, BX
+ SUBQ $0x08, DX
+ MOVBQZX (R13), CX
+ ORQ CX, AX
+ JMP sequenceDecs_decode_bmi2_fill_byte_by_byte
+
+sequenceDecs_decode_bmi2_fill_check_overread:
+ CMPQ DX, $0x40
+ JA error_overread
+
+sequenceDecs_decode_bmi2_fill_end:
+ // Update offset
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R14
+ MOVQ AX, R15
+ LEAQ (DX)(R14*1), CX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+ MOVQ CX, DX
+ MOVQ R8, CX
+ SHRQ $0x20, CX
+ ADDQ R15, CX
+ MOVQ CX, 16(R9)
+
+ // Update match length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, DI, R14
+ MOVQ AX, R15
+ LEAQ (DX)(R14*1), CX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+ MOVQ CX, DX
+ MOVQ DI, CX
+ SHRQ $0x20, CX
+ ADDQ R15, CX
+ MOVQ CX, 8(R9)
+
+ // Fill bitreader to have enough for the remaining
+ CMPQ BX, $0x08
+ JL sequenceDecs_decode_bmi2_fill_2_byte_by_byte
+ MOVQ DX, CX
+ SHRQ $0x03, CX
+ SUBQ CX, R13
+ MOVQ (R13), AX
+ SUBQ CX, BX
+ ANDQ $0x07, DX
+ JMP sequenceDecs_decode_bmi2_fill_2_end
+
+sequenceDecs_decode_bmi2_fill_2_byte_by_byte:
+ CMPQ BX, $0x00
+ JLE sequenceDecs_decode_bmi2_fill_2_check_overread
+ CMPQ DX, $0x07
+ JLE sequenceDecs_decode_bmi2_fill_2_end
+ SHLQ $0x08, AX
+ SUBQ $0x01, R13
+ SUBQ $0x01, BX
+ SUBQ $0x08, DX
+ MOVBQZX (R13), CX
+ ORQ CX, AX
+ JMP sequenceDecs_decode_bmi2_fill_2_byte_by_byte
+
+sequenceDecs_decode_bmi2_fill_2_check_overread:
+ CMPQ DX, $0x40
+ JA error_overread
+
+sequenceDecs_decode_bmi2_fill_2_end:
+ // Update literal length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, SI, R14
+ MOVQ AX, R15
+ LEAQ (DX)(R14*1), CX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+ MOVQ CX, DX
+ MOVQ SI, CX
+ SHRQ $0x20, CX
+ ADDQ R15, CX
+ MOVQ CX, (R9)
+
+ // Fill bitreader for state updates
+ MOVQ R13, (SP)
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R13
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decode_bmi2_skip_update
+ LEAQ (SI)(DI*1), R14
+ ADDQ R8, R14
+ MOVBQZX R14, R14
+ LEAQ (DX)(R14*1), CX
+ MOVQ AX, R15
+ MOVQ CX, DX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+
+ // Update Offset State
+ BZHIQ R8, R15, CX
+ SHRXQ R8, R15, R15
+ SHRL $0x10, R8
+ ADDQ CX, R8
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Match Length State
+ BZHIQ DI, R15, CX
+ SHRXQ DI, R15, R15
+ SHRL $0x10, DI
+ ADDQ CX, DI
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Literal Length State
+ BZHIQ SI, R15, CX
+ SHRL $0x10, SI
+ ADDQ CX, SI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(SI*8), SI
+
+sequenceDecs_decode_bmi2_skip_update:
+ // Adjust offset
+ MOVQ 16(R9), CX
+ CMPQ R13, $0x01
+ JBE sequenceDecs_decode_bmi2_adjust_offsetB_1_or_0
+ MOVQ R11, R12
+ MOVQ R10, R11
+ MOVQ CX, R10
+ JMP sequenceDecs_decode_bmi2_after_adjust
+
+sequenceDecs_decode_bmi2_adjust_offsetB_1_or_0:
+ CMPQ (R9), $0x00000000
+ JNE sequenceDecs_decode_bmi2_adjust_offset_maybezero
+ INCQ CX
+ JMP sequenceDecs_decode_bmi2_adjust_offset_nonzero
+
+sequenceDecs_decode_bmi2_adjust_offset_maybezero:
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_bmi2_adjust_offset_nonzero
+ MOVQ R10, CX
+ JMP sequenceDecs_decode_bmi2_after_adjust
+
+sequenceDecs_decode_bmi2_adjust_offset_nonzero:
+ CMPQ CX, $0x01
+ JB sequenceDecs_decode_bmi2_adjust_zero
+ JEQ sequenceDecs_decode_bmi2_adjust_one
+ CMPQ CX, $0x02
+ JA sequenceDecs_decode_bmi2_adjust_three
+ JMP sequenceDecs_decode_bmi2_adjust_two
+
+sequenceDecs_decode_bmi2_adjust_zero:
+ MOVQ R10, R13
+ JMP sequenceDecs_decode_bmi2_adjust_test_temp_valid
+
+sequenceDecs_decode_bmi2_adjust_one:
+ MOVQ R11, R13
+ JMP sequenceDecs_decode_bmi2_adjust_test_temp_valid
+
+sequenceDecs_decode_bmi2_adjust_two:
+ MOVQ R12, R13
+ JMP sequenceDecs_decode_bmi2_adjust_test_temp_valid
+
+sequenceDecs_decode_bmi2_adjust_three:
+ LEAQ -1(R10), R13
+
+sequenceDecs_decode_bmi2_adjust_test_temp_valid:
+ TESTQ R13, R13
+ JNZ sequenceDecs_decode_bmi2_adjust_temp_valid
+ MOVQ $0x00000001, R13
+
+sequenceDecs_decode_bmi2_adjust_temp_valid:
+ CMPQ CX, $0x01
+ CMOVQNE R11, R12
+ MOVQ R10, R11
+ MOVQ R13, R10
+ MOVQ R13, CX
+
+sequenceDecs_decode_bmi2_after_adjust:
+ MOVQ CX, 16(R9)
+
+ // Check values
+ MOVQ 8(R9), R13
+ MOVQ (R9), R14
+ LEAQ (R13)(R14*1), R15
+ MOVQ s+0(FP), BP
+ ADDQ R15, 256(BP)
+ MOVQ ctx+16(FP), R15
+ SUBQ R14, 128(R15)
+ JS error_not_enough_literals
+ CMPQ R13, $0x00020002
+ JA sequenceDecs_decode_bmi2_error_match_len_too_big
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_bmi2_match_len_ofs_ok
+ TESTQ R13, R13
+ JNZ sequenceDecs_decode_bmi2_error_match_len_ofs_mismatch
+
+sequenceDecs_decode_bmi2_match_len_ofs_ok:
+ ADDQ $0x18, R9
+ MOVQ ctx+16(FP), CX
+ DECQ 96(CX)
+ JNS sequenceDecs_decode_bmi2_main_loop
+ MOVQ s+0(FP), CX
+ MOVQ R10, 144(CX)
+ MOVQ R11, 152(CX)
+ MOVQ R12, 160(CX)
+ MOVQ br+8(FP), CX
+ MOVQ AX, 24(CX)
+ MOVB DL, 40(CX)
+ MOVQ BX, 32(CX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decode_bmi2_error_match_len_ofs_mismatch:
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decode_bmi2_error_match_len_too_big:
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+// func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int
+// Requires: BMI, BMI2, CMOV
+TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32
+ MOVQ br+8(FP), BX
+ MOVQ 24(BX), AX
+ MOVBQZX 40(BX), DX
+ MOVQ (BX), CX
+ MOVQ 32(BX), BX
+ ADDQ BX, CX
+ MOVQ CX, (SP)
+ MOVQ ctx+16(FP), CX
+ MOVQ 72(CX), SI
+ MOVQ 80(CX), DI
+ MOVQ 88(CX), R8
+ MOVQ 104(CX), R9
+ MOVQ s+0(FP), CX
+ MOVQ 144(CX), R10
+ MOVQ 152(CX), R11
+ MOVQ 160(CX), R12
+
+sequenceDecs_decode_56_bmi2_main_loop:
+ MOVQ (SP), R13
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ BX, $0x08
+ JL sequenceDecs_decode_56_bmi2_fill_byte_by_byte
+ MOVQ DX, CX
+ SHRQ $0x03, CX
+ SUBQ CX, R13
+ MOVQ (R13), AX
+ SUBQ CX, BX
+ ANDQ $0x07, DX
+ JMP sequenceDecs_decode_56_bmi2_fill_end
+
+sequenceDecs_decode_56_bmi2_fill_byte_by_byte:
+ CMPQ BX, $0x00
+ JLE sequenceDecs_decode_56_bmi2_fill_check_overread
+ CMPQ DX, $0x07
+ JLE sequenceDecs_decode_56_bmi2_fill_end
+ SHLQ $0x08, AX
+ SUBQ $0x01, R13
+ SUBQ $0x01, BX
+ SUBQ $0x08, DX
+ MOVBQZX (R13), CX
+ ORQ CX, AX
+ JMP sequenceDecs_decode_56_bmi2_fill_byte_by_byte
+
+sequenceDecs_decode_56_bmi2_fill_check_overread:
+ CMPQ DX, $0x40
+ JA error_overread
+
+sequenceDecs_decode_56_bmi2_fill_end:
+ // Update offset
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R14
+ MOVQ AX, R15
+ LEAQ (DX)(R14*1), CX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+ MOVQ CX, DX
+ MOVQ R8, CX
+ SHRQ $0x20, CX
+ ADDQ R15, CX
+ MOVQ CX, 16(R9)
+
+ // Update match length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, DI, R14
+ MOVQ AX, R15
+ LEAQ (DX)(R14*1), CX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+ MOVQ CX, DX
+ MOVQ DI, CX
+ SHRQ $0x20, CX
+ ADDQ R15, CX
+ MOVQ CX, 8(R9)
+
+ // Update literal length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, SI, R14
+ MOVQ AX, R15
+ LEAQ (DX)(R14*1), CX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+ MOVQ CX, DX
+ MOVQ SI, CX
+ SHRQ $0x20, CX
+ ADDQ R15, CX
+ MOVQ CX, (R9)
+
+ // Fill bitreader for state updates
+ MOVQ R13, (SP)
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R13
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decode_56_bmi2_skip_update
+ LEAQ (SI)(DI*1), R14
+ ADDQ R8, R14
+ MOVBQZX R14, R14
+ LEAQ (DX)(R14*1), CX
+ MOVQ AX, R15
+ MOVQ CX, DX
+ ROLQ CL, R15
+ BZHIQ R14, R15, R15
+
+ // Update Offset State
+ BZHIQ R8, R15, CX
+ SHRXQ R8, R15, R15
+ SHRL $0x10, R8
+ ADDQ CX, R8
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Match Length State
+ BZHIQ DI, R15, CX
+ SHRXQ DI, R15, R15
+ SHRL $0x10, DI
+ ADDQ CX, DI
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Literal Length State
+ BZHIQ SI, R15, CX
+ SHRL $0x10, SI
+ ADDQ CX, SI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(SI*8), SI
+
+sequenceDecs_decode_56_bmi2_skip_update:
+ // Adjust offset
+ MOVQ 16(R9), CX
+ CMPQ R13, $0x01
+ JBE sequenceDecs_decode_56_bmi2_adjust_offsetB_1_or_0
+ MOVQ R11, R12
+ MOVQ R10, R11
+ MOVQ CX, R10
+ JMP sequenceDecs_decode_56_bmi2_after_adjust
+
+sequenceDecs_decode_56_bmi2_adjust_offsetB_1_or_0:
+ CMPQ (R9), $0x00000000
+ JNE sequenceDecs_decode_56_bmi2_adjust_offset_maybezero
+ INCQ CX
+ JMP sequenceDecs_decode_56_bmi2_adjust_offset_nonzero
+
+sequenceDecs_decode_56_bmi2_adjust_offset_maybezero:
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_56_bmi2_adjust_offset_nonzero
+ MOVQ R10, CX
+ JMP sequenceDecs_decode_56_bmi2_after_adjust
+
+sequenceDecs_decode_56_bmi2_adjust_offset_nonzero:
+ CMPQ CX, $0x01
+ JB sequenceDecs_decode_56_bmi2_adjust_zero
+ JEQ sequenceDecs_decode_56_bmi2_adjust_one
+ CMPQ CX, $0x02
+ JA sequenceDecs_decode_56_bmi2_adjust_three
+ JMP sequenceDecs_decode_56_bmi2_adjust_two
+
+sequenceDecs_decode_56_bmi2_adjust_zero:
+ MOVQ R10, R13
+ JMP sequenceDecs_decode_56_bmi2_adjust_test_temp_valid
+
+sequenceDecs_decode_56_bmi2_adjust_one:
+ MOVQ R11, R13
+ JMP sequenceDecs_decode_56_bmi2_adjust_test_temp_valid
+
+sequenceDecs_decode_56_bmi2_adjust_two:
+ MOVQ R12, R13
+ JMP sequenceDecs_decode_56_bmi2_adjust_test_temp_valid
+
+sequenceDecs_decode_56_bmi2_adjust_three:
+ LEAQ -1(R10), R13
+
+sequenceDecs_decode_56_bmi2_adjust_test_temp_valid:
+ TESTQ R13, R13
+ JNZ sequenceDecs_decode_56_bmi2_adjust_temp_valid
+ MOVQ $0x00000001, R13
+
+sequenceDecs_decode_56_bmi2_adjust_temp_valid:
+ CMPQ CX, $0x01
+ CMOVQNE R11, R12
+ MOVQ R10, R11
+ MOVQ R13, R10
+ MOVQ R13, CX
+
+sequenceDecs_decode_56_bmi2_after_adjust:
+ MOVQ CX, 16(R9)
+
+ // Check values
+ MOVQ 8(R9), R13
+ MOVQ (R9), R14
+ LEAQ (R13)(R14*1), R15
+ MOVQ s+0(FP), BP
+ ADDQ R15, 256(BP)
+ MOVQ ctx+16(FP), R15
+ SUBQ R14, 128(R15)
+ JS error_not_enough_literals
+ CMPQ R13, $0x00020002
+ JA sequenceDecs_decode_56_bmi2_error_match_len_too_big
+ TESTQ CX, CX
+ JNZ sequenceDecs_decode_56_bmi2_match_len_ofs_ok
+ TESTQ R13, R13
+ JNZ sequenceDecs_decode_56_bmi2_error_match_len_ofs_mismatch
+
+sequenceDecs_decode_56_bmi2_match_len_ofs_ok:
+ ADDQ $0x18, R9
+ MOVQ ctx+16(FP), CX
+ DECQ 96(CX)
+ JNS sequenceDecs_decode_56_bmi2_main_loop
+ MOVQ s+0(FP), CX
+ MOVQ R10, 144(CX)
+ MOVQ R11, 152(CX)
+ MOVQ R12, 160(CX)
+ MOVQ br+8(FP), CX
+ MOVQ AX, 24(CX)
+ MOVB DL, 40(CX)
+ MOVQ BX, 32(CX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decode_56_bmi2_error_match_len_ofs_mismatch:
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decode_56_bmi2_error_match_len_too_big:
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+// func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool
+// Requires: SSE
+TEXT ·sequenceDecs_executeSimple_amd64(SB), $8-9
+ MOVQ ctx+0(FP), R10
+ MOVQ 8(R10), CX
+ TESTQ CX, CX
+ JZ empty_seqs
+ MOVQ (R10), AX
+ MOVQ 24(R10), DX
+ MOVQ 32(R10), BX
+ MOVQ 80(R10), SI
+ MOVQ 104(R10), DI
+ MOVQ 120(R10), R8
+ MOVQ 56(R10), R9
+ MOVQ 64(R10), R10
+ ADDQ R10, R9
+
+ // seqsBase += 24 * seqIndex
+ LEAQ (DX)(DX*2), R11
+ SHLQ $0x03, R11
+ ADDQ R11, AX
+
+ // outBase += outPosition
+ ADDQ DI, BX
+
+main_loop:
+ MOVQ (AX), R11
+ MOVQ 16(AX), R12
+ MOVQ 8(AX), R13
+
+ // Copy literals
+ TESTQ R11, R11
+ JZ check_offset
+ XORQ R14, R14
+
+copy_1:
+ MOVUPS (SI)(R14*1), X0
+ MOVUPS X0, (BX)(R14*1)
+ ADDQ $0x10, R14
+ CMPQ R14, R11
+ JB copy_1
+ ADDQ R11, SI
+ ADDQ R11, BX
+ ADDQ R11, DI
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ LEAQ (DI)(R10*1), R11
+ CMPQ R12, R11
+ JG error_match_off_too_big
+ CMPQ R12, R8
+ JG error_match_off_too_big
+
+ // Copy match from history
+ MOVQ R12, R11
+ SUBQ DI, R11
+ JLS copy_match
+ MOVQ R9, R14
+ SUBQ R11, R14
+ CMPQ R13, R11
+ JG copy_all_from_history
+ MOVQ R13, R11
+ SUBQ $0x10, R11
+ JB copy_4_small
+
+copy_4_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (BX)
+ ADDQ $0x10, R14
+ ADDQ $0x10, BX
+ SUBQ $0x10, R11
+ JAE copy_4_loop
+ LEAQ 16(R14)(R11*1), R14
+ LEAQ 16(BX)(R11*1), BX
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(BX)
+ JMP copy_4_end
+
+copy_4_small:
+ CMPQ R13, $0x03
+ JE copy_4_move_3
+ CMPQ R13, $0x08
+ JB copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVW (R14), R11
+ MOVB 2(R14), R12
+ MOVW R11, (BX)
+ MOVB R12, 2(BX)
+ ADDQ R13, R14
+ ADDQ R13, BX
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVL (R14), R11
+ MOVL -4(R14)(R13*1), R12
+ MOVL R11, (BX)
+ MOVL R12, -4(BX)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, BX
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVQ (R14), R11
+ MOVQ -8(R14)(R13*1), R12
+ MOVQ R11, (BX)
+ MOVQ R12, -8(BX)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, BX
+
+copy_4_end:
+ ADDQ R13, DI
+ ADDQ $0x18, AX
+ INCQ DX
+ CMPQ DX, CX
+ JB main_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVQ R11, R15
+ SUBQ $0x10, R15
+ JB copy_5_small
+
+copy_5_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (BX)
+ ADDQ $0x10, R14
+ ADDQ $0x10, BX
+ SUBQ $0x10, R15
+ JAE copy_5_loop
+ LEAQ 16(R14)(R15*1), R14
+ LEAQ 16(BX)(R15*1), BX
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(BX)
+ JMP copy_5_end
+
+copy_5_small:
+ CMPQ R11, $0x03
+ JE copy_5_move_3
+ JB copy_5_move_1or2
+ CMPQ R11, $0x08
+ JB copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVB (R14), R15
+ MOVB -1(R14)(R11*1), BP
+ MOVB R15, (BX)
+ MOVB BP, -1(BX)(R11*1)
+ ADDQ R11, R14
+ ADDQ R11, BX
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVW (R14), R15
+ MOVB 2(R14), BP
+ MOVW R15, (BX)
+ MOVB BP, 2(BX)
+ ADDQ R11, R14
+ ADDQ R11, BX
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVL (R14), R15
+ MOVL -4(R14)(R11*1), BP
+ MOVL R15, (BX)
+ MOVL BP, -4(BX)(R11*1)
+ ADDQ R11, R14
+ ADDQ R11, BX
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVQ (R14), R15
+ MOVQ -8(R14)(R11*1), BP
+ MOVQ R15, (BX)
+ MOVQ BP, -8(BX)(R11*1)
+ ADDQ R11, R14
+ ADDQ R11, BX
+
+copy_5_end:
+ ADDQ R11, DI
+ SUBQ R11, R13
+
+ // Copy match from the current buffer
+copy_match:
+ MOVQ BX, R11
+ SUBQ R12, R11
+
+ // ml <= mo
+ CMPQ R13, R12
+ JA copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADDQ R13, DI
+ MOVQ BX, R12
+ ADDQ R13, BX
+
+copy_2:
+ MOVUPS (R11), X0
+ MOVUPS X0, (R12)
+ ADDQ $0x10, R11
+ ADDQ $0x10, R12
+ SUBQ $0x10, R13
+ JHI copy_2
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADDQ R13, DI
+
+copy_slow_3:
+ MOVB (R11), R12
+ MOVB R12, (BX)
+ INCQ R11
+ INCQ BX
+ DECQ R13
+ JNZ copy_slow_3
+
+handle_loop:
+ ADDQ $0x18, AX
+ INCQ DX
+ CMPQ DX, CX
+ JB main_loop
+
+loop_finished:
+ // Return value
+ MOVB $0x01, ret+8(FP)
+
+ // Update the context
+ MOVQ ctx+0(FP), AX
+ MOVQ DX, 24(AX)
+ MOVQ DI, 104(AX)
+ SUBQ 80(AX), SI
+ MOVQ SI, 112(AX)
+ RET
+
+error_match_off_too_big:
+ // Return value
+ MOVB $0x00, ret+8(FP)
+
+ // Update the context
+ MOVQ ctx+0(FP), AX
+ MOVQ DX, 24(AX)
+ MOVQ DI, 104(AX)
+ SUBQ 80(AX), SI
+ MOVQ SI, 112(AX)
+ RET
+
+empty_seqs:
+ // Return value
+ MOVB $0x01, ret+8(FP)
+ RET
+
+// func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool
+// Requires: SSE
+TEXT ·sequenceDecs_executeSimple_safe_amd64(SB), $8-9
+ MOVQ ctx+0(FP), R10
+ MOVQ 8(R10), CX
+ TESTQ CX, CX
+ JZ empty_seqs
+ MOVQ (R10), AX
+ MOVQ 24(R10), DX
+ MOVQ 32(R10), BX
+ MOVQ 80(R10), SI
+ MOVQ 104(R10), DI
+ MOVQ 120(R10), R8
+ MOVQ 56(R10), R9
+ MOVQ 64(R10), R10
+ ADDQ R10, R9
+
+ // seqsBase += 24 * seqIndex
+ LEAQ (DX)(DX*2), R11
+ SHLQ $0x03, R11
+ ADDQ R11, AX
+
+ // outBase += outPosition
+ ADDQ DI, BX
+
+main_loop:
+ MOVQ (AX), R11
+ MOVQ 16(AX), R12
+ MOVQ 8(AX), R13
+
+ // Copy literals
+ TESTQ R11, R11
+ JZ check_offset
+ MOVQ R11, R14
+ SUBQ $0x10, R14
+ JB copy_1_small
+
+copy_1_loop:
+ MOVUPS (SI), X0
+ MOVUPS X0, (BX)
+ ADDQ $0x10, SI
+ ADDQ $0x10, BX
+ SUBQ $0x10, R14
+ JAE copy_1_loop
+ LEAQ 16(SI)(R14*1), SI
+ LEAQ 16(BX)(R14*1), BX
+ MOVUPS -16(SI), X0
+ MOVUPS X0, -16(BX)
+ JMP copy_1_end
+
+copy_1_small:
+ CMPQ R11, $0x03
+ JE copy_1_move_3
+ JB copy_1_move_1or2
+ CMPQ R11, $0x08
+ JB copy_1_move_4through7
+ JMP copy_1_move_8through16
+
+copy_1_move_1or2:
+ MOVB (SI), R14
+ MOVB -1(SI)(R11*1), R15
+ MOVB R14, (BX)
+ MOVB R15, -1(BX)(R11*1)
+ ADDQ R11, SI
+ ADDQ R11, BX
+ JMP copy_1_end
+
+copy_1_move_3:
+ MOVW (SI), R14
+ MOVB 2(SI), R15
+ MOVW R14, (BX)
+ MOVB R15, 2(BX)
+ ADDQ R11, SI
+ ADDQ R11, BX
+ JMP copy_1_end
+
+copy_1_move_4through7:
+ MOVL (SI), R14
+ MOVL -4(SI)(R11*1), R15
+ MOVL R14, (BX)
+ MOVL R15, -4(BX)(R11*1)
+ ADDQ R11, SI
+ ADDQ R11, BX
+ JMP copy_1_end
+
+copy_1_move_8through16:
+ MOVQ (SI), R14
+ MOVQ -8(SI)(R11*1), R15
+ MOVQ R14, (BX)
+ MOVQ R15, -8(BX)(R11*1)
+ ADDQ R11, SI
+ ADDQ R11, BX
+
+copy_1_end:
+ ADDQ R11, DI
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ LEAQ (DI)(R10*1), R11
+ CMPQ R12, R11
+ JG error_match_off_too_big
+ CMPQ R12, R8
+ JG error_match_off_too_big
+
+ // Copy match from history
+ MOVQ R12, R11
+ SUBQ DI, R11
+ JLS copy_match
+ MOVQ R9, R14
+ SUBQ R11, R14
+ CMPQ R13, R11
+ JG copy_all_from_history
+ MOVQ R13, R11
+ SUBQ $0x10, R11
+ JB copy_4_small
+
+copy_4_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (BX)
+ ADDQ $0x10, R14
+ ADDQ $0x10, BX
+ SUBQ $0x10, R11
+ JAE copy_4_loop
+ LEAQ 16(R14)(R11*1), R14
+ LEAQ 16(BX)(R11*1), BX
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(BX)
+ JMP copy_4_end
+
+copy_4_small:
+ CMPQ R13, $0x03
+ JE copy_4_move_3
+ CMPQ R13, $0x08
+ JB copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVW (R14), R11
+ MOVB 2(R14), R12
+ MOVW R11, (BX)
+ MOVB R12, 2(BX)
+ ADDQ R13, R14
+ ADDQ R13, BX
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVL (R14), R11
+ MOVL -4(R14)(R13*1), R12
+ MOVL R11, (BX)
+ MOVL R12, -4(BX)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, BX
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVQ (R14), R11
+ MOVQ -8(R14)(R13*1), R12
+ MOVQ R11, (BX)
+ MOVQ R12, -8(BX)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, BX
+
+copy_4_end:
+ ADDQ R13, DI
+ ADDQ $0x18, AX
+ INCQ DX
+ CMPQ DX, CX
+ JB main_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVQ R11, R15
+ SUBQ $0x10, R15
+ JB copy_5_small
+
+copy_5_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (BX)
+ ADDQ $0x10, R14
+ ADDQ $0x10, BX
+ SUBQ $0x10, R15
+ JAE copy_5_loop
+ LEAQ 16(R14)(R15*1), R14
+ LEAQ 16(BX)(R15*1), BX
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(BX)
+ JMP copy_5_end
+
+copy_5_small:
+ CMPQ R11, $0x03
+ JE copy_5_move_3
+ JB copy_5_move_1or2
+ CMPQ R11, $0x08
+ JB copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVB (R14), R15
+ MOVB -1(R14)(R11*1), BP
+ MOVB R15, (BX)
+ MOVB BP, -1(BX)(R11*1)
+ ADDQ R11, R14
+ ADDQ R11, BX
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVW (R14), R15
+ MOVB 2(R14), BP
+ MOVW R15, (BX)
+ MOVB BP, 2(BX)
+ ADDQ R11, R14
+ ADDQ R11, BX
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVL (R14), R15
+ MOVL -4(R14)(R11*1), BP
+ MOVL R15, (BX)
+ MOVL BP, -4(BX)(R11*1)
+ ADDQ R11, R14
+ ADDQ R11, BX
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVQ (R14), R15
+ MOVQ -8(R14)(R11*1), BP
+ MOVQ R15, (BX)
+ MOVQ BP, -8(BX)(R11*1)
+ ADDQ R11, R14
+ ADDQ R11, BX
+
+copy_5_end:
+ ADDQ R11, DI
+ SUBQ R11, R13
+
+ // Copy match from the current buffer
+copy_match:
+ MOVQ BX, R11
+ SUBQ R12, R11
+
+ // ml <= mo
+ CMPQ R13, R12
+ JA copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADDQ R13, DI
+ MOVQ R13, R12
+ SUBQ $0x10, R12
+ JB copy_2_small
+
+copy_2_loop:
+ MOVUPS (R11), X0
+ MOVUPS X0, (BX)
+ ADDQ $0x10, R11
+ ADDQ $0x10, BX
+ SUBQ $0x10, R12
+ JAE copy_2_loop
+ LEAQ 16(R11)(R12*1), R11
+ LEAQ 16(BX)(R12*1), BX
+ MOVUPS -16(R11), X0
+ MOVUPS X0, -16(BX)
+ JMP copy_2_end
+
+copy_2_small:
+ CMPQ R13, $0x03
+ JE copy_2_move_3
+ JB copy_2_move_1or2
+ CMPQ R13, $0x08
+ JB copy_2_move_4through7
+ JMP copy_2_move_8through16
+
+copy_2_move_1or2:
+ MOVB (R11), R12
+ MOVB -1(R11)(R13*1), R14
+ MOVB R12, (BX)
+ MOVB R14, -1(BX)(R13*1)
+ ADDQ R13, R11
+ ADDQ R13, BX
+ JMP copy_2_end
+
+copy_2_move_3:
+ MOVW (R11), R12
+ MOVB 2(R11), R14
+ MOVW R12, (BX)
+ MOVB R14, 2(BX)
+ ADDQ R13, R11
+ ADDQ R13, BX
+ JMP copy_2_end
+
+copy_2_move_4through7:
+ MOVL (R11), R12
+ MOVL -4(R11)(R13*1), R14
+ MOVL R12, (BX)
+ MOVL R14, -4(BX)(R13*1)
+ ADDQ R13, R11
+ ADDQ R13, BX
+ JMP copy_2_end
+
+copy_2_move_8through16:
+ MOVQ (R11), R12
+ MOVQ -8(R11)(R13*1), R14
+ MOVQ R12, (BX)
+ MOVQ R14, -8(BX)(R13*1)
+ ADDQ R13, R11
+ ADDQ R13, BX
+
+copy_2_end:
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADDQ R13, DI
+
+copy_slow_3:
+ MOVB (R11), R12
+ MOVB R12, (BX)
+ INCQ R11
+ INCQ BX
+ DECQ R13
+ JNZ copy_slow_3
+
+handle_loop:
+ ADDQ $0x18, AX
+ INCQ DX
+ CMPQ DX, CX
+ JB main_loop
+
+loop_finished:
+ // Return value
+ MOVB $0x01, ret+8(FP)
+
+ // Update the context
+ MOVQ ctx+0(FP), AX
+ MOVQ DX, 24(AX)
+ MOVQ DI, 104(AX)
+ SUBQ 80(AX), SI
+ MOVQ SI, 112(AX)
+ RET
+
+error_match_off_too_big:
+ // Return value
+ MOVB $0x00, ret+8(FP)
+
+ // Update the context
+ MOVQ ctx+0(FP), AX
+ MOVQ DX, 24(AX)
+ MOVQ DI, 104(AX)
+ SUBQ 80(AX), SI
+ MOVQ SI, 112(AX)
+ RET
+
+empty_seqs:
+ // Return value
+ MOVB $0x01, ret+8(FP)
+ RET
+
+// func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+// Requires: CMOV, SSE
+TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32
+ MOVQ br+8(FP), CX
+ MOVQ 24(CX), DX
+ MOVBQZX 40(CX), BX
+ MOVQ (CX), AX
+ MOVQ 32(CX), SI
+ ADDQ SI, AX
+ MOVQ AX, (SP)
+ MOVQ ctx+16(FP), AX
+ MOVQ 72(AX), DI
+ MOVQ 80(AX), R8
+ MOVQ 88(AX), R9
+ XORQ CX, CX
+ MOVQ CX, 8(SP)
+ MOVQ CX, 16(SP)
+ MOVQ CX, 24(SP)
+ MOVQ 112(AX), R10
+ MOVQ 128(AX), CX
+ MOVQ CX, 32(SP)
+ MOVQ 144(AX), R11
+ MOVQ 136(AX), R12
+ MOVQ 200(AX), CX
+ MOVQ CX, 56(SP)
+ MOVQ 176(AX), CX
+ MOVQ CX, 48(SP)
+ MOVQ 184(AX), AX
+ MOVQ AX, 40(SP)
+ MOVQ 40(SP), AX
+ ADDQ AX, 48(SP)
+
+ // Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
+ ADDQ R10, 32(SP)
+
+ // outBase += outPosition
+ ADDQ R12, R10
+
+sequenceDecs_decodeSync_amd64_main_loop:
+ MOVQ (SP), R13
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ SI, $0x08
+ JL sequenceDecs_decodeSync_amd64_fill_byte_by_byte
+ MOVQ BX, AX
+ SHRQ $0x03, AX
+ SUBQ AX, R13
+ MOVQ (R13), DX
+ SUBQ AX, SI
+ ANDQ $0x07, BX
+ JMP sequenceDecs_decodeSync_amd64_fill_end
+
+sequenceDecs_decodeSync_amd64_fill_byte_by_byte:
+ CMPQ SI, $0x00
+ JLE sequenceDecs_decodeSync_amd64_fill_check_overread
+ CMPQ BX, $0x07
+ JLE sequenceDecs_decodeSync_amd64_fill_end
+ SHLQ $0x08, DX
+ SUBQ $0x01, R13
+ SUBQ $0x01, SI
+ SUBQ $0x08, BX
+ MOVBQZX (R13), AX
+ ORQ AX, DX
+ JMP sequenceDecs_decodeSync_amd64_fill_byte_by_byte
+
+sequenceDecs_decodeSync_amd64_fill_check_overread:
+ CMPQ BX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_amd64_fill_end:
+ // Update offset
+ MOVQ R9, AX
+ MOVQ BX, CX
+ MOVQ DX, R14
+ SHLQ CL, R14
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decodeSync_amd64_of_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decodeSync_amd64_of_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decodeSync_amd64_of_update_zero
+ NEGQ CX
+ SHRQ CL, R14
+ ADDQ R14, AX
+
+sequenceDecs_decodeSync_amd64_of_update_zero:
+ MOVQ AX, 8(SP)
+
+ // Update match length
+ MOVQ R8, AX
+ MOVQ BX, CX
+ MOVQ DX, R14
+ SHLQ CL, R14
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decodeSync_amd64_ml_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decodeSync_amd64_ml_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decodeSync_amd64_ml_update_zero
+ NEGQ CX
+ SHRQ CL, R14
+ ADDQ R14, AX
+
+sequenceDecs_decodeSync_amd64_ml_update_zero:
+ MOVQ AX, 16(SP)
+
+ // Fill bitreader to have enough for the remaining
+ CMPQ SI, $0x08
+ JL sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte
+ MOVQ BX, AX
+ SHRQ $0x03, AX
+ SUBQ AX, R13
+ MOVQ (R13), DX
+ SUBQ AX, SI
+ ANDQ $0x07, BX
+ JMP sequenceDecs_decodeSync_amd64_fill_2_end
+
+sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte:
+ CMPQ SI, $0x00
+ JLE sequenceDecs_decodeSync_amd64_fill_2_check_overread
+ CMPQ BX, $0x07
+ JLE sequenceDecs_decodeSync_amd64_fill_2_end
+ SHLQ $0x08, DX
+ SUBQ $0x01, R13
+ SUBQ $0x01, SI
+ SUBQ $0x08, BX
+ MOVBQZX (R13), AX
+ ORQ AX, DX
+ JMP sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte
+
+sequenceDecs_decodeSync_amd64_fill_2_check_overread:
+ CMPQ BX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_amd64_fill_2_end:
+ // Update literal length
+ MOVQ DI, AX
+ MOVQ BX, CX
+ MOVQ DX, R14
+ SHLQ CL, R14
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decodeSync_amd64_ll_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decodeSync_amd64_ll_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decodeSync_amd64_ll_update_zero
+ NEGQ CX
+ SHRQ CL, R14
+ ADDQ R14, AX
+
+sequenceDecs_decodeSync_amd64_ll_update_zero:
+ MOVQ AX, 24(SP)
+
+ // Fill bitreader for state updates
+ MOVQ R13, (SP)
+ MOVQ R9, AX
+ SHRQ $0x08, AX
+ MOVBQZX AL, AX
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decodeSync_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBQZX DI, R13
+ SHRL $0x10, DI
+ LEAQ (BX)(R13*1), CX
+ MOVQ DX, R14
+ MOVQ CX, BX
+ ROLQ CL, R14
+ MOVL $0x00000001, R15
+ MOVB R13, CL
+ SHLL CL, R15
+ DECL R15
+ ANDQ R15, R14
+ ADDQ R14, DI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Match Length State
+ MOVBQZX R8, R13
+ SHRL $0x10, R8
+ LEAQ (BX)(R13*1), CX
+ MOVQ DX, R14
+ MOVQ CX, BX
+ ROLQ CL, R14
+ MOVL $0x00000001, R15
+ MOVB R13, CL
+ SHLL CL, R15
+ DECL R15
+ ANDQ R15, R14
+ ADDQ R14, R8
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Offset State
+ MOVBQZX R9, R13
+ SHRL $0x10, R9
+ LEAQ (BX)(R13*1), CX
+ MOVQ DX, R14
+ MOVQ CX, BX
+ ROLQ CL, R14
+ MOVL $0x00000001, R15
+ MOVB R13, CL
+ SHLL CL, R15
+ DECL R15
+ ANDQ R15, R14
+ ADDQ R14, R9
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R9*8), R9
+
+sequenceDecs_decodeSync_amd64_skip_update:
+ // Adjust offset
+ MOVQ s+0(FP), CX
+ MOVQ 8(SP), R13
+ CMPQ AX, $0x01
+ JBE sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0
+ MOVUPS 144(CX), X0
+ MOVQ R13, 144(CX)
+ MOVUPS X0, 152(CX)
+ JMP sequenceDecs_decodeSync_amd64_after_adjust
+
+sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0:
+ CMPQ 24(SP), $0x00000000
+ JNE sequenceDecs_decodeSync_amd64_adjust_offset_maybezero
+ INCQ R13
+ JMP sequenceDecs_decodeSync_amd64_adjust_offset_nonzero
+
+sequenceDecs_decodeSync_amd64_adjust_offset_maybezero:
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_amd64_adjust_offset_nonzero
+ MOVQ 144(CX), R13
+ JMP sequenceDecs_decodeSync_amd64_after_adjust
+
+sequenceDecs_decodeSync_amd64_adjust_offset_nonzero:
+ MOVQ R13, AX
+ XORQ R14, R14
+ MOVQ $-1, R15
+ CMPQ R13, $0x03
+ CMOVQEQ R14, AX
+ CMOVQEQ R15, R14
+ ADDQ 144(CX)(AX*8), R14
+ JNZ sequenceDecs_decodeSync_amd64_adjust_temp_valid
+ MOVQ $0x00000001, R14
+
+sequenceDecs_decodeSync_amd64_adjust_temp_valid:
+ CMPQ R13, $0x01
+ JZ sequenceDecs_decodeSync_amd64_adjust_skip
+ MOVQ 152(CX), AX
+ MOVQ AX, 160(CX)
+
+sequenceDecs_decodeSync_amd64_adjust_skip:
+ MOVQ 144(CX), AX
+ MOVQ AX, 152(CX)
+ MOVQ R14, 144(CX)
+ MOVQ R14, R13
+
+sequenceDecs_decodeSync_amd64_after_adjust:
+ MOVQ R13, 8(SP)
+
+ // Check values
+ MOVQ 16(SP), AX
+ MOVQ 24(SP), CX
+ LEAQ (AX)(CX*1), R14
+ MOVQ s+0(FP), R15
+ ADDQ R14, 256(R15)
+ MOVQ ctx+16(FP), R14
+ SUBQ CX, 104(R14)
+ JS error_not_enough_literals
+ CMPQ AX, $0x00020002
+ JA sequenceDecs_decodeSync_amd64_error_match_len_too_big
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_amd64_match_len_ofs_ok
+ TESTQ AX, AX
+ JNZ sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decodeSync_amd64_match_len_ofs_ok:
+ MOVQ 24(SP), AX
+ MOVQ 8(SP), CX
+ MOVQ 16(SP), R13
+
+ // Check if we have enough space in s.out
+ LEAQ (AX)(R13*1), R14
+ ADDQ R10, R14
+ CMPQ R14, 32(SP)
+ JA error_not_enough_space
+
+ // Copy literals
+ TESTQ AX, AX
+ JZ check_offset
+ XORQ R14, R14
+
+copy_1:
+ MOVUPS (R11)(R14*1), X0
+ MOVUPS X0, (R10)(R14*1)
+ ADDQ $0x10, R14
+ CMPQ R14, AX
+ JB copy_1
+ ADDQ AX, R11
+ ADDQ AX, R10
+ ADDQ AX, R12
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ MOVQ R12, AX
+ ADDQ 40(SP), AX
+ CMPQ CX, AX
+ JG error_match_off_too_big
+ CMPQ CX, 56(SP)
+ JG error_match_off_too_big
+
+ // Copy match from history
+ MOVQ CX, AX
+ SUBQ R12, AX
+ JLS copy_match
+ MOVQ 48(SP), R14
+ SUBQ AX, R14
+ CMPQ R13, AX
+ JG copy_all_from_history
+ MOVQ R13, AX
+ SUBQ $0x10, AX
+ JB copy_4_small
+
+copy_4_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R10)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R10
+ SUBQ $0x10, AX
+ JAE copy_4_loop
+ LEAQ 16(R14)(AX*1), R14
+ LEAQ 16(R10)(AX*1), R10
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R10)
+ JMP copy_4_end
+
+copy_4_small:
+ CMPQ R13, $0x03
+ JE copy_4_move_3
+ CMPQ R13, $0x08
+ JB copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVW (R14), AX
+ MOVB 2(R14), CL
+ MOVW AX, (R10)
+ MOVB CL, 2(R10)
+ ADDQ R13, R14
+ ADDQ R13, R10
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVL (R14), AX
+ MOVL -4(R14)(R13*1), CX
+ MOVL AX, (R10)
+ MOVL CX, -4(R10)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R10
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVQ (R14), AX
+ MOVQ -8(R14)(R13*1), CX
+ MOVQ AX, (R10)
+ MOVQ CX, -8(R10)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R10
+
+copy_4_end:
+ ADDQ R13, R12
+ JMP handle_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVQ AX, R15
+ SUBQ $0x10, R15
+ JB copy_5_small
+
+copy_5_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R10)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R10
+ SUBQ $0x10, R15
+ JAE copy_5_loop
+ LEAQ 16(R14)(R15*1), R14
+ LEAQ 16(R10)(R15*1), R10
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R10)
+ JMP copy_5_end
+
+copy_5_small:
+ CMPQ AX, $0x03
+ JE copy_5_move_3
+ JB copy_5_move_1or2
+ CMPQ AX, $0x08
+ JB copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVB (R14), R15
+ MOVB -1(R14)(AX*1), BP
+ MOVB R15, (R10)
+ MOVB BP, -1(R10)(AX*1)
+ ADDQ AX, R14
+ ADDQ AX, R10
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVW (R14), R15
+ MOVB 2(R14), BP
+ MOVW R15, (R10)
+ MOVB BP, 2(R10)
+ ADDQ AX, R14
+ ADDQ AX, R10
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVL (R14), R15
+ MOVL -4(R14)(AX*1), BP
+ MOVL R15, (R10)
+ MOVL BP, -4(R10)(AX*1)
+ ADDQ AX, R14
+ ADDQ AX, R10
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVQ (R14), R15
+ MOVQ -8(R14)(AX*1), BP
+ MOVQ R15, (R10)
+ MOVQ BP, -8(R10)(AX*1)
+ ADDQ AX, R14
+ ADDQ AX, R10
+
+copy_5_end:
+ ADDQ AX, R12
+ SUBQ AX, R13
+
+ // Copy match from the current buffer
+copy_match:
+ MOVQ R10, AX
+ SUBQ CX, AX
+
+ // ml <= mo
+ CMPQ R13, CX
+ JA copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADDQ R13, R12
+ MOVQ R10, CX
+ ADDQ R13, R10
+
+copy_2:
+ MOVUPS (AX), X0
+ MOVUPS X0, (CX)
+ ADDQ $0x10, AX
+ ADDQ $0x10, CX
+ SUBQ $0x10, R13
+ JHI copy_2
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADDQ R13, R12
+
+copy_slow_3:
+ MOVB (AX), CL
+ MOVB CL, (R10)
+ INCQ AX
+ INCQ R10
+ DECQ R13
+ JNZ copy_slow_3
+
+handle_loop:
+ MOVQ ctx+16(FP), AX
+ DECQ 96(AX)
+ JNS sequenceDecs_decodeSync_amd64_main_loop
+
+loop_finished:
+ MOVQ br+8(FP), AX
+ MOVQ DX, 24(AX)
+ MOVB BL, 40(AX)
+ MOVQ SI, 32(AX)
+
+ // Update the context
+ MOVQ ctx+16(FP), AX
+ MOVQ R12, 136(AX)
+ MOVQ 144(AX), CX
+ SUBQ CX, R11
+ MOVQ R11, 168(AX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch:
+ MOVQ 16(SP), AX
+ MOVQ ctx+16(FP), CX
+ MOVQ AX, 216(CX)
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decodeSync_amd64_error_match_len_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+error_match_off_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 8(SP), CX
+ MOVQ CX, 224(AX)
+ MOVQ R12, 136(AX)
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+ // Return with not enough output space error
+error_not_enough_space:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ R12, 136(AX)
+ MOVQ $0x00000005, ret+24(FP)
+ RET
+
+// func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+// Requires: BMI, BMI2, CMOV, SSE
+TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32
+ MOVQ br+8(FP), BX
+ MOVQ 24(BX), AX
+ MOVBQZX 40(BX), DX
+ MOVQ (BX), CX
+ MOVQ 32(BX), BX
+ ADDQ BX, CX
+ MOVQ CX, (SP)
+ MOVQ ctx+16(FP), CX
+ MOVQ 72(CX), SI
+ MOVQ 80(CX), DI
+ MOVQ 88(CX), R8
+ XORQ R9, R9
+ MOVQ R9, 8(SP)
+ MOVQ R9, 16(SP)
+ MOVQ R9, 24(SP)
+ MOVQ 112(CX), R9
+ MOVQ 128(CX), R10
+ MOVQ R10, 32(SP)
+ MOVQ 144(CX), R10
+ MOVQ 136(CX), R11
+ MOVQ 200(CX), R12
+ MOVQ R12, 56(SP)
+ MOVQ 176(CX), R12
+ MOVQ R12, 48(SP)
+ MOVQ 184(CX), CX
+ MOVQ CX, 40(SP)
+ MOVQ 40(SP), CX
+ ADDQ CX, 48(SP)
+
+ // Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
+ ADDQ R9, 32(SP)
+
+ // outBase += outPosition
+ ADDQ R11, R9
+
+sequenceDecs_decodeSync_bmi2_main_loop:
+ MOVQ (SP), R12
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ BX, $0x08
+ JL sequenceDecs_decodeSync_bmi2_fill_byte_by_byte
+ MOVQ DX, CX
+ SHRQ $0x03, CX
+ SUBQ CX, R12
+ MOVQ (R12), AX
+ SUBQ CX, BX
+ ANDQ $0x07, DX
+ JMP sequenceDecs_decodeSync_bmi2_fill_end
+
+sequenceDecs_decodeSync_bmi2_fill_byte_by_byte:
+ CMPQ BX, $0x00
+ JLE sequenceDecs_decodeSync_bmi2_fill_check_overread
+ CMPQ DX, $0x07
+ JLE sequenceDecs_decodeSync_bmi2_fill_end
+ SHLQ $0x08, AX
+ SUBQ $0x01, R12
+ SUBQ $0x01, BX
+ SUBQ $0x08, DX
+ MOVBQZX (R12), CX
+ ORQ CX, AX
+ JMP sequenceDecs_decodeSync_bmi2_fill_byte_by_byte
+
+sequenceDecs_decodeSync_bmi2_fill_check_overread:
+ CMPQ DX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_bmi2_fill_end:
+ // Update offset
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R13
+ MOVQ AX, R14
+ LEAQ (DX)(R13*1), CX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+ MOVQ CX, DX
+ MOVQ R8, CX
+ SHRQ $0x20, CX
+ ADDQ R14, CX
+ MOVQ CX, 8(SP)
+
+ // Update match length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, DI, R13
+ MOVQ AX, R14
+ LEAQ (DX)(R13*1), CX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+ MOVQ CX, DX
+ MOVQ DI, CX
+ SHRQ $0x20, CX
+ ADDQ R14, CX
+ MOVQ CX, 16(SP)
+
+ // Fill bitreader to have enough for the remaining
+ CMPQ BX, $0x08
+ JL sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte
+ MOVQ DX, CX
+ SHRQ $0x03, CX
+ SUBQ CX, R12
+ MOVQ (R12), AX
+ SUBQ CX, BX
+ ANDQ $0x07, DX
+ JMP sequenceDecs_decodeSync_bmi2_fill_2_end
+
+sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte:
+ CMPQ BX, $0x00
+ JLE sequenceDecs_decodeSync_bmi2_fill_2_check_overread
+ CMPQ DX, $0x07
+ JLE sequenceDecs_decodeSync_bmi2_fill_2_end
+ SHLQ $0x08, AX
+ SUBQ $0x01, R12
+ SUBQ $0x01, BX
+ SUBQ $0x08, DX
+ MOVBQZX (R12), CX
+ ORQ CX, AX
+ JMP sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte
+
+sequenceDecs_decodeSync_bmi2_fill_2_check_overread:
+ CMPQ DX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_bmi2_fill_2_end:
+ // Update literal length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, SI, R13
+ MOVQ AX, R14
+ LEAQ (DX)(R13*1), CX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+ MOVQ CX, DX
+ MOVQ SI, CX
+ SHRQ $0x20, CX
+ ADDQ R14, CX
+ MOVQ CX, 24(SP)
+
+ // Fill bitreader for state updates
+ MOVQ R12, (SP)
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R12
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decodeSync_bmi2_skip_update
+ LEAQ (SI)(DI*1), R13
+ ADDQ R8, R13
+ MOVBQZX R13, R13
+ LEAQ (DX)(R13*1), CX
+ MOVQ AX, R14
+ MOVQ CX, DX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+
+ // Update Offset State
+ BZHIQ R8, R14, CX
+ SHRXQ R8, R14, R14
+ SHRL $0x10, R8
+ ADDQ CX, R8
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Match Length State
+ BZHIQ DI, R14, CX
+ SHRXQ DI, R14, R14
+ SHRL $0x10, DI
+ ADDQ CX, DI
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Literal Length State
+ BZHIQ SI, R14, CX
+ SHRL $0x10, SI
+ ADDQ CX, SI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(SI*8), SI
+
+sequenceDecs_decodeSync_bmi2_skip_update:
+ // Adjust offset
+ MOVQ s+0(FP), CX
+ MOVQ 8(SP), R13
+ CMPQ R12, $0x01
+ JBE sequenceDecs_decodeSync_bmi2_adjust_offsetB_1_or_0
+ MOVUPS 144(CX), X0
+ MOVQ R13, 144(CX)
+ MOVUPS X0, 152(CX)
+ JMP sequenceDecs_decodeSync_bmi2_after_adjust
+
+sequenceDecs_decodeSync_bmi2_adjust_offsetB_1_or_0:
+ CMPQ 24(SP), $0x00000000
+ JNE sequenceDecs_decodeSync_bmi2_adjust_offset_maybezero
+ INCQ R13
+ JMP sequenceDecs_decodeSync_bmi2_adjust_offset_nonzero
+
+sequenceDecs_decodeSync_bmi2_adjust_offset_maybezero:
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_bmi2_adjust_offset_nonzero
+ MOVQ 144(CX), R13
+ JMP sequenceDecs_decodeSync_bmi2_after_adjust
+
+sequenceDecs_decodeSync_bmi2_adjust_offset_nonzero:
+ MOVQ R13, R12
+ XORQ R14, R14
+ MOVQ $-1, R15
+ CMPQ R13, $0x03
+ CMOVQEQ R14, R12
+ CMOVQEQ R15, R14
+ ADDQ 144(CX)(R12*8), R14
+ JNZ sequenceDecs_decodeSync_bmi2_adjust_temp_valid
+ MOVQ $0x00000001, R14
+
+sequenceDecs_decodeSync_bmi2_adjust_temp_valid:
+ CMPQ R13, $0x01
+ JZ sequenceDecs_decodeSync_bmi2_adjust_skip
+ MOVQ 152(CX), R12
+ MOVQ R12, 160(CX)
+
+sequenceDecs_decodeSync_bmi2_adjust_skip:
+ MOVQ 144(CX), R12
+ MOVQ R12, 152(CX)
+ MOVQ R14, 144(CX)
+ MOVQ R14, R13
+
+sequenceDecs_decodeSync_bmi2_after_adjust:
+ MOVQ R13, 8(SP)
+
+ // Check values
+ MOVQ 16(SP), CX
+ MOVQ 24(SP), R12
+ LEAQ (CX)(R12*1), R14
+ MOVQ s+0(FP), R15
+ ADDQ R14, 256(R15)
+ MOVQ ctx+16(FP), R14
+ SUBQ R12, 104(R14)
+ JS error_not_enough_literals
+ CMPQ CX, $0x00020002
+ JA sequenceDecs_decodeSync_bmi2_error_match_len_too_big
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_bmi2_match_len_ofs_ok
+ TESTQ CX, CX
+ JNZ sequenceDecs_decodeSync_bmi2_error_match_len_ofs_mismatch
+
+sequenceDecs_decodeSync_bmi2_match_len_ofs_ok:
+ MOVQ 24(SP), CX
+ MOVQ 8(SP), R12
+ MOVQ 16(SP), R13
+
+ // Check if we have enough space in s.out
+ LEAQ (CX)(R13*1), R14
+ ADDQ R9, R14
+ CMPQ R14, 32(SP)
+ JA error_not_enough_space
+
+ // Copy literals
+ TESTQ CX, CX
+ JZ check_offset
+ XORQ R14, R14
+
+copy_1:
+ MOVUPS (R10)(R14*1), X0
+ MOVUPS X0, (R9)(R14*1)
+ ADDQ $0x10, R14
+ CMPQ R14, CX
+ JB copy_1
+ ADDQ CX, R10
+ ADDQ CX, R9
+ ADDQ CX, R11
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ MOVQ R11, CX
+ ADDQ 40(SP), CX
+ CMPQ R12, CX
+ JG error_match_off_too_big
+ CMPQ R12, 56(SP)
+ JG error_match_off_too_big
+
+ // Copy match from history
+ MOVQ R12, CX
+ SUBQ R11, CX
+ JLS copy_match
+ MOVQ 48(SP), R14
+ SUBQ CX, R14
+ CMPQ R13, CX
+ JG copy_all_from_history
+ MOVQ R13, CX
+ SUBQ $0x10, CX
+ JB copy_4_small
+
+copy_4_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R9)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R9
+ SUBQ $0x10, CX
+ JAE copy_4_loop
+ LEAQ 16(R14)(CX*1), R14
+ LEAQ 16(R9)(CX*1), R9
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R9)
+ JMP copy_4_end
+
+copy_4_small:
+ CMPQ R13, $0x03
+ JE copy_4_move_3
+ CMPQ R13, $0x08
+ JB copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVW (R14), CX
+ MOVB 2(R14), R12
+ MOVW CX, (R9)
+ MOVB R12, 2(R9)
+ ADDQ R13, R14
+ ADDQ R13, R9
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVL (R14), CX
+ MOVL -4(R14)(R13*1), R12
+ MOVL CX, (R9)
+ MOVL R12, -4(R9)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R9
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVQ (R14), CX
+ MOVQ -8(R14)(R13*1), R12
+ MOVQ CX, (R9)
+ MOVQ R12, -8(R9)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R9
+
+copy_4_end:
+ ADDQ R13, R11
+ JMP handle_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVQ CX, R15
+ SUBQ $0x10, R15
+ JB copy_5_small
+
+copy_5_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R9)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R9
+ SUBQ $0x10, R15
+ JAE copy_5_loop
+ LEAQ 16(R14)(R15*1), R14
+ LEAQ 16(R9)(R15*1), R9
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R9)
+ JMP copy_5_end
+
+copy_5_small:
+ CMPQ CX, $0x03
+ JE copy_5_move_3
+ JB copy_5_move_1or2
+ CMPQ CX, $0x08
+ JB copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVB (R14), R15
+ MOVB -1(R14)(CX*1), BP
+ MOVB R15, (R9)
+ MOVB BP, -1(R9)(CX*1)
+ ADDQ CX, R14
+ ADDQ CX, R9
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVW (R14), R15
+ MOVB 2(R14), BP
+ MOVW R15, (R9)
+ MOVB BP, 2(R9)
+ ADDQ CX, R14
+ ADDQ CX, R9
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVL (R14), R15
+ MOVL -4(R14)(CX*1), BP
+ MOVL R15, (R9)
+ MOVL BP, -4(R9)(CX*1)
+ ADDQ CX, R14
+ ADDQ CX, R9
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVQ (R14), R15
+ MOVQ -8(R14)(CX*1), BP
+ MOVQ R15, (R9)
+ MOVQ BP, -8(R9)(CX*1)
+ ADDQ CX, R14
+ ADDQ CX, R9
+
+copy_5_end:
+ ADDQ CX, R11
+ SUBQ CX, R13
+
+ // Copy match from the current buffer
+copy_match:
+ MOVQ R9, CX
+ SUBQ R12, CX
+
+ // ml <= mo
+ CMPQ R13, R12
+ JA copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADDQ R13, R11
+ MOVQ R9, R12
+ ADDQ R13, R9
+
+copy_2:
+ MOVUPS (CX), X0
+ MOVUPS X0, (R12)
+ ADDQ $0x10, CX
+ ADDQ $0x10, R12
+ SUBQ $0x10, R13
+ JHI copy_2
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADDQ R13, R11
+
+copy_slow_3:
+ MOVB (CX), R12
+ MOVB R12, (R9)
+ INCQ CX
+ INCQ R9
+ DECQ R13
+ JNZ copy_slow_3
+
+handle_loop:
+ MOVQ ctx+16(FP), CX
+ DECQ 96(CX)
+ JNS sequenceDecs_decodeSync_bmi2_main_loop
+
+loop_finished:
+ MOVQ br+8(FP), CX
+ MOVQ AX, 24(CX)
+ MOVB DL, 40(CX)
+ MOVQ BX, 32(CX)
+
+ // Update the context
+ MOVQ ctx+16(FP), AX
+ MOVQ R11, 136(AX)
+ MOVQ 144(AX), CX
+ SUBQ CX, R10
+ MOVQ R10, 168(AX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decodeSync_bmi2_error_match_len_ofs_mismatch:
+ MOVQ 16(SP), AX
+ MOVQ ctx+16(FP), CX
+ MOVQ AX, 216(CX)
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decodeSync_bmi2_error_match_len_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+error_match_off_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 8(SP), CX
+ MOVQ CX, 224(AX)
+ MOVQ R11, 136(AX)
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+ // Return with not enough output space error
+error_not_enough_space:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ R11, 136(AX)
+ MOVQ $0x00000005, ret+24(FP)
+ RET
+
+// func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+// Requires: CMOV, SSE
+TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32
+ MOVQ br+8(FP), CX
+ MOVQ 24(CX), DX
+ MOVBQZX 40(CX), BX
+ MOVQ (CX), AX
+ MOVQ 32(CX), SI
+ ADDQ SI, AX
+ MOVQ AX, (SP)
+ MOVQ ctx+16(FP), AX
+ MOVQ 72(AX), DI
+ MOVQ 80(AX), R8
+ MOVQ 88(AX), R9
+ XORQ CX, CX
+ MOVQ CX, 8(SP)
+ MOVQ CX, 16(SP)
+ MOVQ CX, 24(SP)
+ MOVQ 112(AX), R10
+ MOVQ 128(AX), CX
+ MOVQ CX, 32(SP)
+ MOVQ 144(AX), R11
+ MOVQ 136(AX), R12
+ MOVQ 200(AX), CX
+ MOVQ CX, 56(SP)
+ MOVQ 176(AX), CX
+ MOVQ CX, 48(SP)
+ MOVQ 184(AX), AX
+ MOVQ AX, 40(SP)
+ MOVQ 40(SP), AX
+ ADDQ AX, 48(SP)
+
+ // Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
+ ADDQ R10, 32(SP)
+
+ // outBase += outPosition
+ ADDQ R12, R10
+
+sequenceDecs_decodeSync_safe_amd64_main_loop:
+ MOVQ (SP), R13
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ SI, $0x08
+ JL sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte
+ MOVQ BX, AX
+ SHRQ $0x03, AX
+ SUBQ AX, R13
+ MOVQ (R13), DX
+ SUBQ AX, SI
+ ANDQ $0x07, BX
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_end
+
+sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte:
+ CMPQ SI, $0x00
+ JLE sequenceDecs_decodeSync_safe_amd64_fill_check_overread
+ CMPQ BX, $0x07
+ JLE sequenceDecs_decodeSync_safe_amd64_fill_end
+ SHLQ $0x08, DX
+ SUBQ $0x01, R13
+ SUBQ $0x01, SI
+ SUBQ $0x08, BX
+ MOVBQZX (R13), AX
+ ORQ AX, DX
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte
+
+sequenceDecs_decodeSync_safe_amd64_fill_check_overread:
+ CMPQ BX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_safe_amd64_fill_end:
+ // Update offset
+ MOVQ R9, AX
+ MOVQ BX, CX
+ MOVQ DX, R14
+ SHLQ CL, R14
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decodeSync_safe_amd64_of_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decodeSync_safe_amd64_of_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decodeSync_safe_amd64_of_update_zero
+ NEGQ CX
+ SHRQ CL, R14
+ ADDQ R14, AX
+
+sequenceDecs_decodeSync_safe_amd64_of_update_zero:
+ MOVQ AX, 8(SP)
+
+ // Update match length
+ MOVQ R8, AX
+ MOVQ BX, CX
+ MOVQ DX, R14
+ SHLQ CL, R14
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decodeSync_safe_amd64_ml_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decodeSync_safe_amd64_ml_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decodeSync_safe_amd64_ml_update_zero
+ NEGQ CX
+ SHRQ CL, R14
+ ADDQ R14, AX
+
+sequenceDecs_decodeSync_safe_amd64_ml_update_zero:
+ MOVQ AX, 16(SP)
+
+ // Fill bitreader to have enough for the remaining
+ CMPQ SI, $0x08
+ JL sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte
+ MOVQ BX, AX
+ SHRQ $0x03, AX
+ SUBQ AX, R13
+ MOVQ (R13), DX
+ SUBQ AX, SI
+ ANDQ $0x07, BX
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_2_end
+
+sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte:
+ CMPQ SI, $0x00
+ JLE sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread
+ CMPQ BX, $0x07
+ JLE sequenceDecs_decodeSync_safe_amd64_fill_2_end
+ SHLQ $0x08, DX
+ SUBQ $0x01, R13
+ SUBQ $0x01, SI
+ SUBQ $0x08, BX
+ MOVBQZX (R13), AX
+ ORQ AX, DX
+ JMP sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte
+
+sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread:
+ CMPQ BX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_safe_amd64_fill_2_end:
+ // Update literal length
+ MOVQ DI, AX
+ MOVQ BX, CX
+ MOVQ DX, R14
+ SHLQ CL, R14
+ MOVB AH, CL
+ SHRQ $0x20, AX
+ TESTQ CX, CX
+ JZ sequenceDecs_decodeSync_safe_amd64_ll_update_zero
+ ADDQ CX, BX
+ CMPQ BX, $0x40
+ JA sequenceDecs_decodeSync_safe_amd64_ll_update_zero
+ CMPQ CX, $0x40
+ JAE sequenceDecs_decodeSync_safe_amd64_ll_update_zero
+ NEGQ CX
+ SHRQ CL, R14
+ ADDQ R14, AX
+
+sequenceDecs_decodeSync_safe_amd64_ll_update_zero:
+ MOVQ AX, 24(SP)
+
+ // Fill bitreader for state updates
+ MOVQ R13, (SP)
+ MOVQ R9, AX
+ SHRQ $0x08, AX
+ MOVBQZX AL, AX
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decodeSync_safe_amd64_skip_update
+
+ // Update Literal Length State
+ MOVBQZX DI, R13
+ SHRL $0x10, DI
+ LEAQ (BX)(R13*1), CX
+ MOVQ DX, R14
+ MOVQ CX, BX
+ ROLQ CL, R14
+ MOVL $0x00000001, R15
+ MOVB R13, CL
+ SHLL CL, R15
+ DECL R15
+ ANDQ R15, R14
+ ADDQ R14, DI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Match Length State
+ MOVBQZX R8, R13
+ SHRL $0x10, R8
+ LEAQ (BX)(R13*1), CX
+ MOVQ DX, R14
+ MOVQ CX, BX
+ ROLQ CL, R14
+ MOVL $0x00000001, R15
+ MOVB R13, CL
+ SHLL CL, R15
+ DECL R15
+ ANDQ R15, R14
+ ADDQ R14, R8
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Offset State
+ MOVBQZX R9, R13
+ SHRL $0x10, R9
+ LEAQ (BX)(R13*1), CX
+ MOVQ DX, R14
+ MOVQ CX, BX
+ ROLQ CL, R14
+ MOVL $0x00000001, R15
+ MOVB R13, CL
+ SHLL CL, R15
+ DECL R15
+ ANDQ R15, R14
+ ADDQ R14, R9
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R9*8), R9
+
+sequenceDecs_decodeSync_safe_amd64_skip_update:
+ // Adjust offset
+ MOVQ s+0(FP), CX
+ MOVQ 8(SP), R13
+ CMPQ AX, $0x01
+ JBE sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0
+ MOVUPS 144(CX), X0
+ MOVQ R13, 144(CX)
+ MOVUPS X0, 152(CX)
+ JMP sequenceDecs_decodeSync_safe_amd64_after_adjust
+
+sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0:
+ CMPQ 24(SP), $0x00000000
+ JNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero
+ INCQ R13
+ JMP sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero
+
+sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero:
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero
+ MOVQ 144(CX), R13
+ JMP sequenceDecs_decodeSync_safe_amd64_after_adjust
+
+sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero:
+ MOVQ R13, AX
+ XORQ R14, R14
+ MOVQ $-1, R15
+ CMPQ R13, $0x03
+ CMOVQEQ R14, AX
+ CMOVQEQ R15, R14
+ ADDQ 144(CX)(AX*8), R14
+ JNZ sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid
+ MOVQ $0x00000001, R14
+
+sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid:
+ CMPQ R13, $0x01
+ JZ sequenceDecs_decodeSync_safe_amd64_adjust_skip
+ MOVQ 152(CX), AX
+ MOVQ AX, 160(CX)
+
+sequenceDecs_decodeSync_safe_amd64_adjust_skip:
+ MOVQ 144(CX), AX
+ MOVQ AX, 152(CX)
+ MOVQ R14, 144(CX)
+ MOVQ R14, R13
+
+sequenceDecs_decodeSync_safe_amd64_after_adjust:
+ MOVQ R13, 8(SP)
+
+ // Check values
+ MOVQ 16(SP), AX
+ MOVQ 24(SP), CX
+ LEAQ (AX)(CX*1), R14
+ MOVQ s+0(FP), R15
+ ADDQ R14, 256(R15)
+ MOVQ ctx+16(FP), R14
+ SUBQ CX, 104(R14)
+ JS error_not_enough_literals
+ CMPQ AX, $0x00020002
+ JA sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok
+ TESTQ AX, AX
+ JNZ sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch
+
+sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok:
+ MOVQ 24(SP), AX
+ MOVQ 8(SP), CX
+ MOVQ 16(SP), R13
+
+ // Check if we have enough space in s.out
+ LEAQ (AX)(R13*1), R14
+ ADDQ R10, R14
+ CMPQ R14, 32(SP)
+ JA error_not_enough_space
+
+ // Copy literals
+ TESTQ AX, AX
+ JZ check_offset
+ MOVQ AX, R14
+ SUBQ $0x10, R14
+ JB copy_1_small
+
+copy_1_loop:
+ MOVUPS (R11), X0
+ MOVUPS X0, (R10)
+ ADDQ $0x10, R11
+ ADDQ $0x10, R10
+ SUBQ $0x10, R14
+ JAE copy_1_loop
+ LEAQ 16(R11)(R14*1), R11
+ LEAQ 16(R10)(R14*1), R10
+ MOVUPS -16(R11), X0
+ MOVUPS X0, -16(R10)
+ JMP copy_1_end
+
+copy_1_small:
+ CMPQ AX, $0x03
+ JE copy_1_move_3
+ JB copy_1_move_1or2
+ CMPQ AX, $0x08
+ JB copy_1_move_4through7
+ JMP copy_1_move_8through16
+
+copy_1_move_1or2:
+ MOVB (R11), R14
+ MOVB -1(R11)(AX*1), R15
+ MOVB R14, (R10)
+ MOVB R15, -1(R10)(AX*1)
+ ADDQ AX, R11
+ ADDQ AX, R10
+ JMP copy_1_end
+
+copy_1_move_3:
+ MOVW (R11), R14
+ MOVB 2(R11), R15
+ MOVW R14, (R10)
+ MOVB R15, 2(R10)
+ ADDQ AX, R11
+ ADDQ AX, R10
+ JMP copy_1_end
+
+copy_1_move_4through7:
+ MOVL (R11), R14
+ MOVL -4(R11)(AX*1), R15
+ MOVL R14, (R10)
+ MOVL R15, -4(R10)(AX*1)
+ ADDQ AX, R11
+ ADDQ AX, R10
+ JMP copy_1_end
+
+copy_1_move_8through16:
+ MOVQ (R11), R14
+ MOVQ -8(R11)(AX*1), R15
+ MOVQ R14, (R10)
+ MOVQ R15, -8(R10)(AX*1)
+ ADDQ AX, R11
+ ADDQ AX, R10
+
+copy_1_end:
+ ADDQ AX, R12
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ MOVQ R12, AX
+ ADDQ 40(SP), AX
+ CMPQ CX, AX
+ JG error_match_off_too_big
+ CMPQ CX, 56(SP)
+ JG error_match_off_too_big
+
+ // Copy match from history
+ MOVQ CX, AX
+ SUBQ R12, AX
+ JLS copy_match
+ MOVQ 48(SP), R14
+ SUBQ AX, R14
+ CMPQ R13, AX
+ JG copy_all_from_history
+ MOVQ R13, AX
+ SUBQ $0x10, AX
+ JB copy_4_small
+
+copy_4_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R10)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R10
+ SUBQ $0x10, AX
+ JAE copy_4_loop
+ LEAQ 16(R14)(AX*1), R14
+ LEAQ 16(R10)(AX*1), R10
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R10)
+ JMP copy_4_end
+
+copy_4_small:
+ CMPQ R13, $0x03
+ JE copy_4_move_3
+ CMPQ R13, $0x08
+ JB copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVW (R14), AX
+ MOVB 2(R14), CL
+ MOVW AX, (R10)
+ MOVB CL, 2(R10)
+ ADDQ R13, R14
+ ADDQ R13, R10
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVL (R14), AX
+ MOVL -4(R14)(R13*1), CX
+ MOVL AX, (R10)
+ MOVL CX, -4(R10)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R10
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVQ (R14), AX
+ MOVQ -8(R14)(R13*1), CX
+ MOVQ AX, (R10)
+ MOVQ CX, -8(R10)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R10
+
+copy_4_end:
+ ADDQ R13, R12
+ JMP handle_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVQ AX, R15
+ SUBQ $0x10, R15
+ JB copy_5_small
+
+copy_5_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R10)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R10
+ SUBQ $0x10, R15
+ JAE copy_5_loop
+ LEAQ 16(R14)(R15*1), R14
+ LEAQ 16(R10)(R15*1), R10
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R10)
+ JMP copy_5_end
+
+copy_5_small:
+ CMPQ AX, $0x03
+ JE copy_5_move_3
+ JB copy_5_move_1or2
+ CMPQ AX, $0x08
+ JB copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVB (R14), R15
+ MOVB -1(R14)(AX*1), BP
+ MOVB R15, (R10)
+ MOVB BP, -1(R10)(AX*1)
+ ADDQ AX, R14
+ ADDQ AX, R10
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVW (R14), R15
+ MOVB 2(R14), BP
+ MOVW R15, (R10)
+ MOVB BP, 2(R10)
+ ADDQ AX, R14
+ ADDQ AX, R10
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVL (R14), R15
+ MOVL -4(R14)(AX*1), BP
+ MOVL R15, (R10)
+ MOVL BP, -4(R10)(AX*1)
+ ADDQ AX, R14
+ ADDQ AX, R10
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVQ (R14), R15
+ MOVQ -8(R14)(AX*1), BP
+ MOVQ R15, (R10)
+ MOVQ BP, -8(R10)(AX*1)
+ ADDQ AX, R14
+ ADDQ AX, R10
+
+copy_5_end:
+ ADDQ AX, R12
+ SUBQ AX, R13
+
+ // Copy match from the current buffer
+copy_match:
+ MOVQ R10, AX
+ SUBQ CX, AX
+
+ // ml <= mo
+ CMPQ R13, CX
+ JA copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADDQ R13, R12
+ MOVQ R13, CX
+ SUBQ $0x10, CX
+ JB copy_2_small
+
+copy_2_loop:
+ MOVUPS (AX), X0
+ MOVUPS X0, (R10)
+ ADDQ $0x10, AX
+ ADDQ $0x10, R10
+ SUBQ $0x10, CX
+ JAE copy_2_loop
+ LEAQ 16(AX)(CX*1), AX
+ LEAQ 16(R10)(CX*1), R10
+ MOVUPS -16(AX), X0
+ MOVUPS X0, -16(R10)
+ JMP copy_2_end
+
+copy_2_small:
+ CMPQ R13, $0x03
+ JE copy_2_move_3
+ JB copy_2_move_1or2
+ CMPQ R13, $0x08
+ JB copy_2_move_4through7
+ JMP copy_2_move_8through16
+
+copy_2_move_1or2:
+ MOVB (AX), CL
+ MOVB -1(AX)(R13*1), R14
+ MOVB CL, (R10)
+ MOVB R14, -1(R10)(R13*1)
+ ADDQ R13, AX
+ ADDQ R13, R10
+ JMP copy_2_end
+
+copy_2_move_3:
+ MOVW (AX), CX
+ MOVB 2(AX), R14
+ MOVW CX, (R10)
+ MOVB R14, 2(R10)
+ ADDQ R13, AX
+ ADDQ R13, R10
+ JMP copy_2_end
+
+copy_2_move_4through7:
+ MOVL (AX), CX
+ MOVL -4(AX)(R13*1), R14
+ MOVL CX, (R10)
+ MOVL R14, -4(R10)(R13*1)
+ ADDQ R13, AX
+ ADDQ R13, R10
+ JMP copy_2_end
+
+copy_2_move_8through16:
+ MOVQ (AX), CX
+ MOVQ -8(AX)(R13*1), R14
+ MOVQ CX, (R10)
+ MOVQ R14, -8(R10)(R13*1)
+ ADDQ R13, AX
+ ADDQ R13, R10
+
+copy_2_end:
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADDQ R13, R12
+
+copy_slow_3:
+ MOVB (AX), CL
+ MOVB CL, (R10)
+ INCQ AX
+ INCQ R10
+ DECQ R13
+ JNZ copy_slow_3
+
+handle_loop:
+ MOVQ ctx+16(FP), AX
+ DECQ 96(AX)
+ JNS sequenceDecs_decodeSync_safe_amd64_main_loop
+
+loop_finished:
+ MOVQ br+8(FP), AX
+ MOVQ DX, 24(AX)
+ MOVB BL, 40(AX)
+ MOVQ SI, 32(AX)
+
+ // Update the context
+ MOVQ ctx+16(FP), AX
+ MOVQ R12, 136(AX)
+ MOVQ 144(AX), CX
+ SUBQ CX, R11
+ MOVQ R11, 168(AX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch:
+ MOVQ 16(SP), AX
+ MOVQ ctx+16(FP), CX
+ MOVQ AX, 216(CX)
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+error_match_off_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 8(SP), CX
+ MOVQ CX, 224(AX)
+ MOVQ R12, 136(AX)
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+ // Return with not enough output space error
+error_not_enough_space:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ R12, 136(AX)
+ MOVQ $0x00000005, ret+24(FP)
+ RET
+
+// func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int
+// Requires: BMI, BMI2, CMOV, SSE
+TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32
+ MOVQ br+8(FP), BX
+ MOVQ 24(BX), AX
+ MOVBQZX 40(BX), DX
+ MOVQ (BX), CX
+ MOVQ 32(BX), BX
+ ADDQ BX, CX
+ MOVQ CX, (SP)
+ MOVQ ctx+16(FP), CX
+ MOVQ 72(CX), SI
+ MOVQ 80(CX), DI
+ MOVQ 88(CX), R8
+ XORQ R9, R9
+ MOVQ R9, 8(SP)
+ MOVQ R9, 16(SP)
+ MOVQ R9, 24(SP)
+ MOVQ 112(CX), R9
+ MOVQ 128(CX), R10
+ MOVQ R10, 32(SP)
+ MOVQ 144(CX), R10
+ MOVQ 136(CX), R11
+ MOVQ 200(CX), R12
+ MOVQ R12, 56(SP)
+ MOVQ 176(CX), R12
+ MOVQ R12, 48(SP)
+ MOVQ 184(CX), CX
+ MOVQ CX, 40(SP)
+ MOVQ 40(SP), CX
+ ADDQ CX, 48(SP)
+
+ // Calculate pointer to s.out[cap(s.out)] (a past-end pointer)
+ ADDQ R9, 32(SP)
+
+ // outBase += outPosition
+ ADDQ R11, R9
+
+sequenceDecs_decodeSync_safe_bmi2_main_loop:
+ MOVQ (SP), R12
+
+ // Fill bitreader to have enough for the offset and match length.
+ CMPQ BX, $0x08
+ JL sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte
+ MOVQ DX, CX
+ SHRQ $0x03, CX
+ SUBQ CX, R12
+ MOVQ (R12), AX
+ SUBQ CX, BX
+ ANDQ $0x07, DX
+ JMP sequenceDecs_decodeSync_safe_bmi2_fill_end
+
+sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte:
+ CMPQ BX, $0x00
+ JLE sequenceDecs_decodeSync_safe_bmi2_fill_check_overread
+ CMPQ DX, $0x07
+ JLE sequenceDecs_decodeSync_safe_bmi2_fill_end
+ SHLQ $0x08, AX
+ SUBQ $0x01, R12
+ SUBQ $0x01, BX
+ SUBQ $0x08, DX
+ MOVBQZX (R12), CX
+ ORQ CX, AX
+ JMP sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte
+
+sequenceDecs_decodeSync_safe_bmi2_fill_check_overread:
+ CMPQ DX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_safe_bmi2_fill_end:
+ // Update offset
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R13
+ MOVQ AX, R14
+ LEAQ (DX)(R13*1), CX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+ MOVQ CX, DX
+ MOVQ R8, CX
+ SHRQ $0x20, CX
+ ADDQ R14, CX
+ MOVQ CX, 8(SP)
+
+ // Update match length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, DI, R13
+ MOVQ AX, R14
+ LEAQ (DX)(R13*1), CX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+ MOVQ CX, DX
+ MOVQ DI, CX
+ SHRQ $0x20, CX
+ ADDQ R14, CX
+ MOVQ CX, 16(SP)
+
+ // Fill bitreader to have enough for the remaining
+ CMPQ BX, $0x08
+ JL sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte
+ MOVQ DX, CX
+ SHRQ $0x03, CX
+ SUBQ CX, R12
+ MOVQ (R12), AX
+ SUBQ CX, BX
+ ANDQ $0x07, DX
+ JMP sequenceDecs_decodeSync_safe_bmi2_fill_2_end
+
+sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte:
+ CMPQ BX, $0x00
+ JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread
+ CMPQ DX, $0x07
+ JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_end
+ SHLQ $0x08, AX
+ SUBQ $0x01, R12
+ SUBQ $0x01, BX
+ SUBQ $0x08, DX
+ MOVBQZX (R12), CX
+ ORQ CX, AX
+ JMP sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte
+
+sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread:
+ CMPQ DX, $0x40
+ JA error_overread
+
+sequenceDecs_decodeSync_safe_bmi2_fill_2_end:
+ // Update literal length
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, SI, R13
+ MOVQ AX, R14
+ LEAQ (DX)(R13*1), CX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+ MOVQ CX, DX
+ MOVQ SI, CX
+ SHRQ $0x20, CX
+ ADDQ R14, CX
+ MOVQ CX, 24(SP)
+
+ // Fill bitreader for state updates
+ MOVQ R12, (SP)
+ MOVQ $0x00000808, CX
+ BEXTRQ CX, R8, R12
+ MOVQ ctx+16(FP), CX
+ CMPQ 96(CX), $0x00
+ JZ sequenceDecs_decodeSync_safe_bmi2_skip_update
+ LEAQ (SI)(DI*1), R13
+ ADDQ R8, R13
+ MOVBQZX R13, R13
+ LEAQ (DX)(R13*1), CX
+ MOVQ AX, R14
+ MOVQ CX, DX
+ ROLQ CL, R14
+ BZHIQ R13, R14, R14
+
+ // Update Offset State
+ BZHIQ R8, R14, CX
+ SHRXQ R8, R14, R14
+ SHRL $0x10, R8
+ ADDQ CX, R8
+
+ // Load ctx.ofTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 48(CX), CX
+ MOVQ (CX)(R8*8), R8
+
+ // Update Match Length State
+ BZHIQ DI, R14, CX
+ SHRXQ DI, R14, R14
+ SHRL $0x10, DI
+ ADDQ CX, DI
+
+ // Load ctx.mlTable
+ MOVQ ctx+16(FP), CX
+ MOVQ 24(CX), CX
+ MOVQ (CX)(DI*8), DI
+
+ // Update Literal Length State
+ BZHIQ SI, R14, CX
+ SHRL $0x10, SI
+ ADDQ CX, SI
+
+ // Load ctx.llTable
+ MOVQ ctx+16(FP), CX
+ MOVQ (CX), CX
+ MOVQ (CX)(SI*8), SI
+
+sequenceDecs_decodeSync_safe_bmi2_skip_update:
+ // Adjust offset
+ MOVQ s+0(FP), CX
+ MOVQ 8(SP), R13
+ CMPQ R12, $0x01
+ JBE sequenceDecs_decodeSync_safe_bmi2_adjust_offsetB_1_or_0
+ MOVUPS 144(CX), X0
+ MOVQ R13, 144(CX)
+ MOVUPS X0, 152(CX)
+ JMP sequenceDecs_decodeSync_safe_bmi2_after_adjust
+
+sequenceDecs_decodeSync_safe_bmi2_adjust_offsetB_1_or_0:
+ CMPQ 24(SP), $0x00000000
+ JNE sequenceDecs_decodeSync_safe_bmi2_adjust_offset_maybezero
+ INCQ R13
+ JMP sequenceDecs_decodeSync_safe_bmi2_adjust_offset_nonzero
+
+sequenceDecs_decodeSync_safe_bmi2_adjust_offset_maybezero:
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_safe_bmi2_adjust_offset_nonzero
+ MOVQ 144(CX), R13
+ JMP sequenceDecs_decodeSync_safe_bmi2_after_adjust
+
+sequenceDecs_decodeSync_safe_bmi2_adjust_offset_nonzero:
+ MOVQ R13, R12
+ XORQ R14, R14
+ MOVQ $-1, R15
+ CMPQ R13, $0x03
+ CMOVQEQ R14, R12
+ CMOVQEQ R15, R14
+ ADDQ 144(CX)(R12*8), R14
+ JNZ sequenceDecs_decodeSync_safe_bmi2_adjust_temp_valid
+ MOVQ $0x00000001, R14
+
+sequenceDecs_decodeSync_safe_bmi2_adjust_temp_valid:
+ CMPQ R13, $0x01
+ JZ sequenceDecs_decodeSync_safe_bmi2_adjust_skip
+ MOVQ 152(CX), R12
+ MOVQ R12, 160(CX)
+
+sequenceDecs_decodeSync_safe_bmi2_adjust_skip:
+ MOVQ 144(CX), R12
+ MOVQ R12, 152(CX)
+ MOVQ R14, 144(CX)
+ MOVQ R14, R13
+
+sequenceDecs_decodeSync_safe_bmi2_after_adjust:
+ MOVQ R13, 8(SP)
+
+ // Check values
+ MOVQ 16(SP), CX
+ MOVQ 24(SP), R12
+ LEAQ (CX)(R12*1), R14
+ MOVQ s+0(FP), R15
+ ADDQ R14, 256(R15)
+ MOVQ ctx+16(FP), R14
+ SUBQ R12, 104(R14)
+ JS error_not_enough_literals
+ CMPQ CX, $0x00020002
+ JA sequenceDecs_decodeSync_safe_bmi2_error_match_len_too_big
+ TESTQ R13, R13
+ JNZ sequenceDecs_decodeSync_safe_bmi2_match_len_ofs_ok
+ TESTQ CX, CX
+ JNZ sequenceDecs_decodeSync_safe_bmi2_error_match_len_ofs_mismatch
+
+sequenceDecs_decodeSync_safe_bmi2_match_len_ofs_ok:
+ MOVQ 24(SP), CX
+ MOVQ 8(SP), R12
+ MOVQ 16(SP), R13
+
+ // Check if we have enough space in s.out
+ LEAQ (CX)(R13*1), R14
+ ADDQ R9, R14
+ CMPQ R14, 32(SP)
+ JA error_not_enough_space
+
+ // Copy literals
+ TESTQ CX, CX
+ JZ check_offset
+ MOVQ CX, R14
+ SUBQ $0x10, R14
+ JB copy_1_small
+
+copy_1_loop:
+ MOVUPS (R10), X0
+ MOVUPS X0, (R9)
+ ADDQ $0x10, R10
+ ADDQ $0x10, R9
+ SUBQ $0x10, R14
+ JAE copy_1_loop
+ LEAQ 16(R10)(R14*1), R10
+ LEAQ 16(R9)(R14*1), R9
+ MOVUPS -16(R10), X0
+ MOVUPS X0, -16(R9)
+ JMP copy_1_end
+
+copy_1_small:
+ CMPQ CX, $0x03
+ JE copy_1_move_3
+ JB copy_1_move_1or2
+ CMPQ CX, $0x08
+ JB copy_1_move_4through7
+ JMP copy_1_move_8through16
+
+copy_1_move_1or2:
+ MOVB (R10), R14
+ MOVB -1(R10)(CX*1), R15
+ MOVB R14, (R9)
+ MOVB R15, -1(R9)(CX*1)
+ ADDQ CX, R10
+ ADDQ CX, R9
+ JMP copy_1_end
+
+copy_1_move_3:
+ MOVW (R10), R14
+ MOVB 2(R10), R15
+ MOVW R14, (R9)
+ MOVB R15, 2(R9)
+ ADDQ CX, R10
+ ADDQ CX, R9
+ JMP copy_1_end
+
+copy_1_move_4through7:
+ MOVL (R10), R14
+ MOVL -4(R10)(CX*1), R15
+ MOVL R14, (R9)
+ MOVL R15, -4(R9)(CX*1)
+ ADDQ CX, R10
+ ADDQ CX, R9
+ JMP copy_1_end
+
+copy_1_move_8through16:
+ MOVQ (R10), R14
+ MOVQ -8(R10)(CX*1), R15
+ MOVQ R14, (R9)
+ MOVQ R15, -8(R9)(CX*1)
+ ADDQ CX, R10
+ ADDQ CX, R9
+
+copy_1_end:
+ ADDQ CX, R11
+
+ // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize)
+check_offset:
+ MOVQ R11, CX
+ ADDQ 40(SP), CX
+ CMPQ R12, CX
+ JG error_match_off_too_big
+ CMPQ R12, 56(SP)
+ JG error_match_off_too_big
+
+ // Copy match from history
+ MOVQ R12, CX
+ SUBQ R11, CX
+ JLS copy_match
+ MOVQ 48(SP), R14
+ SUBQ CX, R14
+ CMPQ R13, CX
+ JG copy_all_from_history
+ MOVQ R13, CX
+ SUBQ $0x10, CX
+ JB copy_4_small
+
+copy_4_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R9)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R9
+ SUBQ $0x10, CX
+ JAE copy_4_loop
+ LEAQ 16(R14)(CX*1), R14
+ LEAQ 16(R9)(CX*1), R9
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R9)
+ JMP copy_4_end
+
+copy_4_small:
+ CMPQ R13, $0x03
+ JE copy_4_move_3
+ CMPQ R13, $0x08
+ JB copy_4_move_4through7
+ JMP copy_4_move_8through16
+
+copy_4_move_3:
+ MOVW (R14), CX
+ MOVB 2(R14), R12
+ MOVW CX, (R9)
+ MOVB R12, 2(R9)
+ ADDQ R13, R14
+ ADDQ R13, R9
+ JMP copy_4_end
+
+copy_4_move_4through7:
+ MOVL (R14), CX
+ MOVL -4(R14)(R13*1), R12
+ MOVL CX, (R9)
+ MOVL R12, -4(R9)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R9
+ JMP copy_4_end
+
+copy_4_move_8through16:
+ MOVQ (R14), CX
+ MOVQ -8(R14)(R13*1), R12
+ MOVQ CX, (R9)
+ MOVQ R12, -8(R9)(R13*1)
+ ADDQ R13, R14
+ ADDQ R13, R9
+
+copy_4_end:
+ ADDQ R13, R11
+ JMP handle_loop
+ JMP loop_finished
+
+copy_all_from_history:
+ MOVQ CX, R15
+ SUBQ $0x10, R15
+ JB copy_5_small
+
+copy_5_loop:
+ MOVUPS (R14), X0
+ MOVUPS X0, (R9)
+ ADDQ $0x10, R14
+ ADDQ $0x10, R9
+ SUBQ $0x10, R15
+ JAE copy_5_loop
+ LEAQ 16(R14)(R15*1), R14
+ LEAQ 16(R9)(R15*1), R9
+ MOVUPS -16(R14), X0
+ MOVUPS X0, -16(R9)
+ JMP copy_5_end
+
+copy_5_small:
+ CMPQ CX, $0x03
+ JE copy_5_move_3
+ JB copy_5_move_1or2
+ CMPQ CX, $0x08
+ JB copy_5_move_4through7
+ JMP copy_5_move_8through16
+
+copy_5_move_1or2:
+ MOVB (R14), R15
+ MOVB -1(R14)(CX*1), BP
+ MOVB R15, (R9)
+ MOVB BP, -1(R9)(CX*1)
+ ADDQ CX, R14
+ ADDQ CX, R9
+ JMP copy_5_end
+
+copy_5_move_3:
+ MOVW (R14), R15
+ MOVB 2(R14), BP
+ MOVW R15, (R9)
+ MOVB BP, 2(R9)
+ ADDQ CX, R14
+ ADDQ CX, R9
+ JMP copy_5_end
+
+copy_5_move_4through7:
+ MOVL (R14), R15
+ MOVL -4(R14)(CX*1), BP
+ MOVL R15, (R9)
+ MOVL BP, -4(R9)(CX*1)
+ ADDQ CX, R14
+ ADDQ CX, R9
+ JMP copy_5_end
+
+copy_5_move_8through16:
+ MOVQ (R14), R15
+ MOVQ -8(R14)(CX*1), BP
+ MOVQ R15, (R9)
+ MOVQ BP, -8(R9)(CX*1)
+ ADDQ CX, R14
+ ADDQ CX, R9
+
+copy_5_end:
+ ADDQ CX, R11
+ SUBQ CX, R13
+
+ // Copy match from the current buffer
+copy_match:
+ MOVQ R9, CX
+ SUBQ R12, CX
+
+ // ml <= mo
+ CMPQ R13, R12
+ JA copy_overlapping_match
+
+ // Copy non-overlapping match
+ ADDQ R13, R11
+ MOVQ R13, R12
+ SUBQ $0x10, R12
+ JB copy_2_small
+
+copy_2_loop:
+ MOVUPS (CX), X0
+ MOVUPS X0, (R9)
+ ADDQ $0x10, CX
+ ADDQ $0x10, R9
+ SUBQ $0x10, R12
+ JAE copy_2_loop
+ LEAQ 16(CX)(R12*1), CX
+ LEAQ 16(R9)(R12*1), R9
+ MOVUPS -16(CX), X0
+ MOVUPS X0, -16(R9)
+ JMP copy_2_end
+
+copy_2_small:
+ CMPQ R13, $0x03
+ JE copy_2_move_3
+ JB copy_2_move_1or2
+ CMPQ R13, $0x08
+ JB copy_2_move_4through7
+ JMP copy_2_move_8through16
+
+copy_2_move_1or2:
+ MOVB (CX), R12
+ MOVB -1(CX)(R13*1), R14
+ MOVB R12, (R9)
+ MOVB R14, -1(R9)(R13*1)
+ ADDQ R13, CX
+ ADDQ R13, R9
+ JMP copy_2_end
+
+copy_2_move_3:
+ MOVW (CX), R12
+ MOVB 2(CX), R14
+ MOVW R12, (R9)
+ MOVB R14, 2(R9)
+ ADDQ R13, CX
+ ADDQ R13, R9
+ JMP copy_2_end
+
+copy_2_move_4through7:
+ MOVL (CX), R12
+ MOVL -4(CX)(R13*1), R14
+ MOVL R12, (R9)
+ MOVL R14, -4(R9)(R13*1)
+ ADDQ R13, CX
+ ADDQ R13, R9
+ JMP copy_2_end
+
+copy_2_move_8through16:
+ MOVQ (CX), R12
+ MOVQ -8(CX)(R13*1), R14
+ MOVQ R12, (R9)
+ MOVQ R14, -8(R9)(R13*1)
+ ADDQ R13, CX
+ ADDQ R13, R9
+
+copy_2_end:
+ JMP handle_loop
+
+ // Copy overlapping match
+copy_overlapping_match:
+ ADDQ R13, R11
+
+copy_slow_3:
+ MOVB (CX), R12
+ MOVB R12, (R9)
+ INCQ CX
+ INCQ R9
+ DECQ R13
+ JNZ copy_slow_3
+
+handle_loop:
+ MOVQ ctx+16(FP), CX
+ DECQ 96(CX)
+ JNS sequenceDecs_decodeSync_safe_bmi2_main_loop
+
+loop_finished:
+ MOVQ br+8(FP), CX
+ MOVQ AX, 24(CX)
+ MOVB DL, 40(CX)
+ MOVQ BX, 32(CX)
+
+ // Update the context
+ MOVQ ctx+16(FP), AX
+ MOVQ R11, 136(AX)
+ MOVQ 144(AX), CX
+ SUBQ CX, R10
+ MOVQ R10, 168(AX)
+
+ // Return success
+ MOVQ $0x00000000, ret+24(FP)
+ RET
+
+ // Return with match length error
+sequenceDecs_decodeSync_safe_bmi2_error_match_len_ofs_mismatch:
+ MOVQ 16(SP), AX
+ MOVQ ctx+16(FP), CX
+ MOVQ AX, 216(CX)
+ MOVQ $0x00000001, ret+24(FP)
+ RET
+
+ // Return with match too long error
+sequenceDecs_decodeSync_safe_bmi2_error_match_len_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ $0x00000002, ret+24(FP)
+ RET
+
+ // Return with match offset too long error
+error_match_off_too_big:
+ MOVQ ctx+16(FP), AX
+ MOVQ 8(SP), CX
+ MOVQ CX, 224(AX)
+ MOVQ R11, 136(AX)
+ MOVQ $0x00000003, ret+24(FP)
+ RET
+
+ // Return with not enough literals error
+error_not_enough_literals:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ $0x00000004, ret+24(FP)
+ RET
+
+ // Return with overread error
+error_overread:
+ MOVQ $0x00000006, ret+24(FP)
+ RET
+
+ // Return with not enough output space error
+error_not_enough_space:
+ MOVQ ctx+16(FP), AX
+ MOVQ 24(SP), CX
+ MOVQ CX, 208(AX)
+ MOVQ 16(SP), CX
+ MOVQ CX, 216(AX)
+ MOVQ R11, 136(AX)
+ MOVQ $0x00000005, ret+24(FP)
+ RET
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go
new file mode 100644
index 00000000..516cd9b0
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go
@@ -0,0 +1,236 @@
+//go:build !amd64 || appengine || !gc || noasm
+
+package zstd
+
+import (
+ "fmt"
+ "io"
+)
+
+// decode sequences from the stream with the provided history but without dictionary.
+func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
+ return false, nil
+}
+
+// decode sequences from the stream without the provided history.
+func (s *sequenceDecs) decode(seqs []seqVals) error {
+ br := s.br
+
+ // Grab full sizes tables, to avoid bounds checks.
+ llTable, mlTable, ofTable := s.litLengths.fse.dt[:maxTablesize], s.matchLengths.fse.dt[:maxTablesize], s.offsets.fse.dt[:maxTablesize]
+ llState, mlState, ofState := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state
+ s.seqSize = 0
+ litRemain := len(s.literals)
+
+ maxBlockSize := maxCompressedBlockSize
+ if s.windowSize < maxBlockSize {
+ maxBlockSize = s.windowSize
+ }
+ for i := range seqs {
+ var ll, mo, ml int
+ if br.cursor > 4+((maxOffsetBits+16+16)>>3) {
+ // inlined function:
+ // ll, mo, ml = s.nextFast(br, llState, mlState, ofState)
+
+ // Final will not read from stream.
+ var llB, mlB, moB uint8
+ ll, llB = llState.final()
+ ml, mlB = mlState.final()
+ mo, moB = ofState.final()
+
+ // extra bits are stored in reverse order.
+ br.fillFast()
+ mo += br.getBits(moB)
+ if s.maxBits > 32 {
+ br.fillFast()
+ }
+ ml += br.getBits(mlB)
+ ll += br.getBits(llB)
+
+ if moB > 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = mo
+ } else {
+ // mo = s.adjustOffset(mo, ll, moB)
+ // Inlined for rather big speedup
+ if ll == 0 {
+ // There is an exception though, when current sequence's literals_length = 0.
+ // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2,
+ // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte.
+ mo++
+ }
+
+ if mo == 0 {
+ mo = s.prevOffset[0]
+ } else {
+ var temp int
+ if mo == 3 {
+ temp = s.prevOffset[0] - 1
+ } else {
+ temp = s.prevOffset[mo]
+ }
+
+ if temp == 0 {
+ // 0 is not valid; input is corrupted; force offset to 1
+ println("WARNING: temp was 0")
+ temp = 1
+ }
+
+ if mo != 1 {
+ s.prevOffset[2] = s.prevOffset[1]
+ }
+ s.prevOffset[1] = s.prevOffset[0]
+ s.prevOffset[0] = temp
+ mo = temp
+ }
+ }
+ br.fillFast()
+ } else {
+ if br.overread() {
+ if debugDecoder {
+ printf("reading sequence %d, exceeded available data\n", i)
+ }
+ return io.ErrUnexpectedEOF
+ }
+ ll, mo, ml = s.next(br, llState, mlState, ofState)
+ br.fill()
+ }
+
+ if debugSequences {
+ println("Seq", i, "Litlen:", ll, "mo:", mo, "(abs) ml:", ml)
+ }
+ // Evaluate.
+ // We might be doing this async, so do it early.
+ if mo == 0 && ml > 0 {
+ return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
+ }
+ if ml > maxMatchLen {
+ return fmt.Errorf("match len (%d) bigger than max allowed length", ml)
+ }
+ s.seqSize += ll + ml
+ if s.seqSize > maxBlockSize {
+ return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+ litRemain -= ll
+ if litRemain < 0 {
+ return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, litRemain+ll)
+ }
+ seqs[i] = seqVals{
+ ll: ll,
+ ml: ml,
+ mo: mo,
+ }
+ if i == len(seqs)-1 {
+ // This is the last sequence, so we shouldn't update state.
+ break
+ }
+
+ // Manually inlined, ~ 5-20% faster
+ // Update all 3 states at once. Approx 20% faster.
+ nBits := llState.nbBits() + mlState.nbBits() + ofState.nbBits()
+ if nBits == 0 {
+ llState = llTable[llState.newState()&maxTableMask]
+ mlState = mlTable[mlState.newState()&maxTableMask]
+ ofState = ofTable[ofState.newState()&maxTableMask]
+ } else {
+ bits := br.get32BitsFast(nBits)
+ lowBits := uint16(bits >> ((ofState.nbBits() + mlState.nbBits()) & 31))
+ llState = llTable[(llState.newState()+lowBits)&maxTableMask]
+
+ lowBits = uint16(bits >> (ofState.nbBits() & 31))
+ lowBits &= bitMask[mlState.nbBits()&15]
+ mlState = mlTable[(mlState.newState()+lowBits)&maxTableMask]
+
+ lowBits = uint16(bits) & bitMask[ofState.nbBits()&15]
+ ofState = ofTable[(ofState.newState()+lowBits)&maxTableMask]
+ }
+ }
+ s.seqSize += litRemain
+ if s.seqSize > maxBlockSize {
+ return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize)
+ }
+ err := br.close()
+ if err != nil {
+ printf("Closing sequences: %v, %+v\n", err, *br)
+ }
+ return err
+}
+
+// executeSimple handles cases when a dictionary is not used.
+func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error {
+ // Ensure we have enough output size...
+ if len(s.out)+s.seqSize > cap(s.out) {
+ addBytes := s.seqSize + len(s.out)
+ s.out = append(s.out, make([]byte, addBytes)...)
+ s.out = s.out[:len(s.out)-addBytes]
+ }
+
+ if debugDecoder {
+ printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize)
+ }
+
+ var t = len(s.out)
+ out := s.out[:t+s.seqSize]
+
+ for _, seq := range seqs {
+ // Add literals
+ copy(out[t:], s.literals[:seq.ll])
+ t += seq.ll
+ s.literals = s.literals[seq.ll:]
+
+ // Malformed input
+ if seq.mo > t+len(hist) || seq.mo > s.windowSize {
+ return fmt.Errorf("match offset (%d) bigger than current history (%d)", seq.mo, t+len(hist))
+ }
+
+ // Copy from history.
+ if v := seq.mo - t; v > 0 {
+ // v is the start position in history from end.
+ start := len(hist) - v
+ if seq.ml > v {
+ // Some goes into the current block.
+ // Copy remainder of history
+ copy(out[t:], hist[start:])
+ t += v
+ seq.ml -= v
+ } else {
+ copy(out[t:], hist[start:start+seq.ml])
+ t += seq.ml
+ continue
+ }
+ }
+
+ // We must be in the current buffer now
+ if seq.ml > 0 {
+ start := t - seq.mo
+ if seq.ml <= t-start {
+ // No overlap
+ copy(out[t:], out[start:start+seq.ml])
+ t += seq.ml
+ } else {
+ // Overlapping copy
+ // Extend destination slice and copy one byte at the time.
+ src := out[start : start+seq.ml]
+ dst := out[t:]
+ dst = dst[:len(src)]
+ t += len(src)
+ // Destination is the space we just added.
+ for i := range src {
+ dst[i] = src[i]
+ }
+ }
+ }
+ }
+ // Add final literals
+ copy(out[t:], s.literals)
+ if debugDecoder {
+ t += len(s.literals)
+ if t != len(out) {
+ panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize))
+ }
+ }
+ s.out = out
+
+ return nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/seqenc.go b/vendor/github.com/klauspost/compress/zstd/seqenc.go
new file mode 100644
index 00000000..65045eab
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/seqenc.go
@@ -0,0 +1,112 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import "math/bits"
+
+type seqCoders struct {
+ llEnc, ofEnc, mlEnc *fseEncoder
+ llPrev, ofPrev, mlPrev *fseEncoder
+}
+
+// swap coders with another (block).
+func (s *seqCoders) swap(other *seqCoders) {
+ *s, *other = *other, *s
+}
+
+// setPrev will update the previous encoders to the actually used ones
+// and make sure a fresh one is in the main slot.
+func (s *seqCoders) setPrev(ll, ml, of *fseEncoder) {
+ compareSwap := func(used *fseEncoder, current, prev **fseEncoder) {
+ // We used the new one, more current to history and reuse the previous history
+ if *current == used {
+ *prev, *current = *current, *prev
+ c := *current
+ p := *prev
+ c.reUsed = false
+ p.reUsed = true
+ return
+ }
+ if used == *prev {
+ return
+ }
+ // Ensure we cannot reuse by accident
+ prevEnc := *prev
+ prevEnc.symbolLen = 0
+ }
+ compareSwap(ll, &s.llEnc, &s.llPrev)
+ compareSwap(ml, &s.mlEnc, &s.mlPrev)
+ compareSwap(of, &s.ofEnc, &s.ofPrev)
+}
+
+func highBit(val uint32) (n uint32) {
+ return uint32(bits.Len32(val) - 1)
+}
+
+var llCodeTable = [64]byte{0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21,
+ 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23,
+ 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24}
+
+// Up to 6 bits
+const maxLLCode = 35
+
+// llBitsTable translates from ll code to number of bits.
+var llBitsTable = [maxLLCode + 1]byte{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 4, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16}
+
+// llCode returns the code that represents the literal length requested.
+func llCode(litLength uint32) uint8 {
+ const llDeltaCode = 19
+ if litLength <= 63 {
+ return llCodeTable[litLength&63]
+ }
+ return uint8(highBit(litLength)) + llDeltaCode
+}
+
+var mlCodeTable = [128]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, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
+ 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42}
+
+// Up to 6 bits
+const maxMLCode = 52
+
+// mlBitsTable translates from ml code to number of bits.
+var mlBitsTable = [maxMLCode + 1]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,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16}
+
+// note : mlBase = matchLength - MINMATCH;
+// because it's the format it's stored in seqStore->sequences
+func mlCode(mlBase uint32) uint8 {
+ const mlDeltaCode = 36
+ if mlBase <= 127 {
+ return mlCodeTable[mlBase&127]
+ }
+ return uint8(highBit(mlBase)) + mlDeltaCode
+}
+
+func ofCode(offset uint32) uint8 {
+ // A valid offset will always be > 0.
+ return uint8(bits.Len32(offset) - 1)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/simple_go124.go b/vendor/github.com/klauspost/compress/zstd/simple_go124.go
new file mode 100644
index 00000000..2efc0497
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/simple_go124.go
@@ -0,0 +1,56 @@
+// Copyright 2025+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+//go:build go1.24
+
+package zstd
+
+import (
+ "errors"
+ "runtime"
+ "sync"
+ "weak"
+)
+
+var weakMu sync.Mutex
+var simpleEnc weak.Pointer[Encoder]
+var simpleDec weak.Pointer[Decoder]
+
+// EncodeTo appends the encoded data from src to dst.
+func EncodeTo(dst []byte, src []byte) []byte {
+ weakMu.Lock()
+ enc := simpleEnc.Value()
+ if enc == nil {
+ var err error
+ enc, err = NewWriter(nil, WithEncoderConcurrency(runtime.NumCPU()), WithWindowSize(1<<20), WithLowerEncoderMem(true), WithZeroFrames(true))
+ if err != nil {
+ panic("failed to create simple encoder: " + err.Error())
+ }
+ simpleEnc = weak.Make(enc)
+ }
+ weakMu.Unlock()
+
+ return enc.EncodeAll(src, dst)
+}
+
+// DecodeTo appends the decoded data from src to dst.
+// The maximum decoded size is 1GiB,
+// not including what may already be in dst.
+func DecodeTo(dst []byte, src []byte) ([]byte, error) {
+ weakMu.Lock()
+ dec := simpleDec.Value()
+ if dec == nil {
+ var err error
+ dec, err = NewReader(nil, WithDecoderConcurrency(runtime.NumCPU()), WithDecoderLowmem(true), WithDecoderMaxMemory(1<<30))
+ if err != nil {
+ weakMu.Unlock()
+ return nil, errors.New("failed to create simple decoder: " + err.Error())
+ }
+ runtime.SetFinalizer(dec, func(d *Decoder) {
+ d.Close()
+ })
+ simpleDec = weak.Make(dec)
+ }
+ weakMu.Unlock()
+ return dec.DecodeAll(src, dst)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/snappy.go b/vendor/github.com/klauspost/compress/zstd/snappy.go
new file mode 100644
index 00000000..336c2889
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/snappy.go
@@ -0,0 +1,434 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+// Based on work by Yann Collet, released under BSD License.
+
+package zstd
+
+import (
+ "encoding/binary"
+ "errors"
+ "hash/crc32"
+ "io"
+
+ "github.com/klauspost/compress/huff0"
+ snappy "github.com/klauspost/compress/internal/snapref"
+)
+
+const (
+ snappyTagLiteral = 0x00
+ snappyTagCopy1 = 0x01
+ snappyTagCopy2 = 0x02
+ snappyTagCopy4 = 0x03
+)
+
+const (
+ snappyChecksumSize = 4
+ snappyMagicBody = "sNaPpY"
+
+ // snappyMaxBlockSize is the maximum size of the input to encodeBlock. It is not
+ // part of the wire format per se, but some parts of the encoder assume
+ // that an offset fits into a uint16.
+ //
+ // Also, for the framing format (Writer type instead of Encode function),
+ // https://github.com/google/snappy/blob/master/framing_format.txt says
+ // that "the uncompressed data in a chunk must be no longer than 65536
+ // bytes".
+ snappyMaxBlockSize = 65536
+
+ // snappyMaxEncodedLenOfMaxBlockSize equals MaxEncodedLen(snappyMaxBlockSize), but is
+ // hard coded to be a const instead of a variable, so that obufLen can also
+ // be a const. Their equivalence is confirmed by
+ // TestMaxEncodedLenOfMaxBlockSize.
+ snappyMaxEncodedLenOfMaxBlockSize = 76490
+)
+
+const (
+ chunkTypeCompressedData = 0x00
+ chunkTypeUncompressedData = 0x01
+ chunkTypePadding = 0xfe
+ chunkTypeStreamIdentifier = 0xff
+)
+
+var (
+ // ErrSnappyCorrupt reports that the input is invalid.
+ ErrSnappyCorrupt = errors.New("snappy: corrupt input")
+ // ErrSnappyTooLarge reports that the uncompressed length is too large.
+ ErrSnappyTooLarge = errors.New("snappy: decoded block is too large")
+ // ErrSnappyUnsupported reports that the input isn't supported.
+ ErrSnappyUnsupported = errors.New("snappy: unsupported input")
+
+ errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length")
+)
+
+// SnappyConverter can read SnappyConverter-compressed streams and convert them to zstd.
+// Conversion is done by converting the stream directly from Snappy without intermediate
+// full decoding.
+// Therefore the compression ratio is much less than what can be done by a full decompression
+// and compression, and a faulty Snappy stream may lead to a faulty Zstandard stream without
+// any errors being generated.
+// No CRC value is being generated and not all CRC values of the Snappy stream are checked.
+// However, it provides really fast recompression of Snappy streams.
+// The converter can be reused to avoid allocations, even after errors.
+type SnappyConverter struct {
+ r io.Reader
+ err error
+ buf []byte
+ block *blockEnc
+}
+
+// Convert the Snappy stream supplied in 'in' and write the zStandard stream to 'w'.
+// If any error is detected on the Snappy stream it is returned.
+// The number of bytes written is returned.
+func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
+ initPredefined()
+ r.err = nil
+ r.r = in
+ if r.block == nil {
+ r.block = &blockEnc{}
+ r.block.init()
+ }
+ r.block.initNewEncode()
+ if len(r.buf) != snappyMaxEncodedLenOfMaxBlockSize+snappyChecksumSize {
+ r.buf = make([]byte, snappyMaxEncodedLenOfMaxBlockSize+snappyChecksumSize)
+ }
+ r.block.litEnc.Reuse = huff0.ReusePolicyNone
+ var written int64
+ var readHeader bool
+ {
+ header := frameHeader{WindowSize: snappyMaxBlockSize}.appendTo(r.buf[:0])
+
+ var n int
+ n, r.err = w.Write(header)
+ if r.err != nil {
+ return written, r.err
+ }
+ written += int64(n)
+ }
+
+ for {
+ if !r.readFull(r.buf[:4], true) {
+ // Add empty last block
+ r.block.reset(nil)
+ r.block.last = true
+ err := r.block.encodeLits(r.block.literals, false)
+ if err != nil {
+ return written, err
+ }
+ n, err := w.Write(r.block.output)
+ if err != nil {
+ return written, err
+ }
+ written += int64(n)
+
+ return written, r.err
+ }
+ chunkType := r.buf[0]
+ if !readHeader {
+ if chunkType != chunkTypeStreamIdentifier {
+ println("chunkType != chunkTypeStreamIdentifier", chunkType)
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ readHeader = true
+ }
+ chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16
+ if chunkLen > len(r.buf) {
+ println("chunkLen > len(r.buf)", chunkType)
+ r.err = ErrSnappyUnsupported
+ return written, r.err
+ }
+
+ // The chunk types are specified at
+ // https://github.com/google/snappy/blob/master/framing_format.txt
+ switch chunkType {
+ case chunkTypeCompressedData:
+ // Section 4.2. Compressed data (chunk type 0x00).
+ if chunkLen < snappyChecksumSize {
+ println("chunkLen < snappyChecksumSize", chunkLen, snappyChecksumSize)
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ buf := r.buf[:chunkLen]
+ if !r.readFull(buf, false) {
+ return written, r.err
+ }
+ //checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ buf = buf[snappyChecksumSize:]
+
+ n, hdr, err := snappyDecodedLen(buf)
+ if err != nil {
+ r.err = err
+ return written, r.err
+ }
+ buf = buf[hdr:]
+ if n > snappyMaxBlockSize {
+ println("n > snappyMaxBlockSize", n, snappyMaxBlockSize)
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ r.block.reset(nil)
+ r.block.pushOffsets()
+ if err := decodeSnappy(r.block, buf); err != nil {
+ r.err = err
+ return written, r.err
+ }
+ if r.block.size+r.block.extraLits != n {
+ printf("invalid size, want %d, got %d\n", n, r.block.size+r.block.extraLits)
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ err = r.block.encode(nil, false, false)
+ switch err {
+ case errIncompressible:
+ r.block.popOffsets()
+ r.block.reset(nil)
+ r.block.literals, err = snappy.Decode(r.block.literals[:n], r.buf[snappyChecksumSize:chunkLen])
+ if err != nil {
+ return written, err
+ }
+ err = r.block.encodeLits(r.block.literals, false)
+ if err != nil {
+ return written, err
+ }
+ case nil:
+ default:
+ return written, err
+ }
+
+ n, r.err = w.Write(r.block.output)
+ if r.err != nil {
+ return written, r.err
+ }
+ written += int64(n)
+ continue
+ case chunkTypeUncompressedData:
+ if debugEncoder {
+ println("Uncompressed, chunklen", chunkLen)
+ }
+ // Section 4.3. Uncompressed data (chunk type 0x01).
+ if chunkLen < snappyChecksumSize {
+ println("chunkLen < snappyChecksumSize", chunkLen, snappyChecksumSize)
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ r.block.reset(nil)
+ buf := r.buf[:snappyChecksumSize]
+ if !r.readFull(buf, false) {
+ return written, r.err
+ }
+ checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24
+ // Read directly into r.decoded instead of via r.buf.
+ n := chunkLen - snappyChecksumSize
+ if n > snappyMaxBlockSize {
+ println("n > snappyMaxBlockSize", n, snappyMaxBlockSize)
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ r.block.literals = r.block.literals[:n]
+ if !r.readFull(r.block.literals, false) {
+ return written, r.err
+ }
+ if snappyCRC(r.block.literals) != checksum {
+ println("literals crc mismatch")
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ err := r.block.encodeLits(r.block.literals, false)
+ if err != nil {
+ return written, err
+ }
+ n, r.err = w.Write(r.block.output)
+ if r.err != nil {
+ return written, r.err
+ }
+ written += int64(n)
+ continue
+
+ case chunkTypeStreamIdentifier:
+ if debugEncoder {
+ println("stream id", chunkLen, len(snappyMagicBody))
+ }
+ // Section 4.1. Stream identifier (chunk type 0xff).
+ if chunkLen != len(snappyMagicBody) {
+ println("chunkLen != len(snappyMagicBody)", chunkLen, len(snappyMagicBody))
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ if !r.readFull(r.buf[:len(snappyMagicBody)], false) {
+ return written, r.err
+ }
+ for i := range len(snappyMagicBody) {
+ if r.buf[i] != snappyMagicBody[i] {
+ println("r.buf[i] != snappyMagicBody[i]", r.buf[i], snappyMagicBody[i], i)
+ r.err = ErrSnappyCorrupt
+ return written, r.err
+ }
+ }
+ continue
+ }
+
+ if chunkType <= 0x7f {
+ // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f).
+ println("chunkType <= 0x7f")
+ r.err = ErrSnappyUnsupported
+ return written, r.err
+ }
+ // Section 4.4 Padding (chunk type 0xfe).
+ // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd).
+ if !r.readFull(r.buf[:chunkLen], false) {
+ return written, r.err
+ }
+ }
+}
+
+// decodeSnappy writes the decoding of src to dst. It assumes that the varint-encoded
+// length of the decompressed bytes has already been read.
+func decodeSnappy(blk *blockEnc, src []byte) error {
+ //decodeRef(make([]byte, snappyMaxBlockSize), src)
+ var s, length int
+ lits := blk.extraLits
+ var offset uint32
+ for s < len(src) {
+ switch src[s] & 0x03 {
+ case snappyTagLiteral:
+ x := uint32(src[s] >> 2)
+ switch {
+ case x < 60:
+ s++
+ case x == 60:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ println("uint(s) > uint(len(src)", s, src)
+ return ErrSnappyCorrupt
+ }
+ x = uint32(src[s-1])
+ case x == 61:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ println("uint(s) > uint(len(src)", s, src)
+ return ErrSnappyCorrupt
+ }
+ x = uint32(src[s-2]) | uint32(src[s-1])<<8
+ case x == 62:
+ s += 4
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ println("uint(s) > uint(len(src)", s, src)
+ return ErrSnappyCorrupt
+ }
+ x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16
+ case x == 63:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ println("uint(s) > uint(len(src)", s, src)
+ return ErrSnappyCorrupt
+ }
+ x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ }
+ if x > snappyMaxBlockSize {
+ println("x > snappyMaxBlockSize", x, snappyMaxBlockSize)
+ return ErrSnappyCorrupt
+ }
+ length = int(x) + 1
+ if length <= 0 {
+ println("length <= 0 ", length)
+
+ return errUnsupportedLiteralLength
+ }
+ //if length > snappyMaxBlockSize-d || uint32(length) > len(src)-s {
+ // return ErrSnappyCorrupt
+ //}
+
+ blk.literals = append(blk.literals, src[s:s+length]...)
+ //println(length, "litLen")
+ lits += length
+ s += length
+ continue
+
+ case snappyTagCopy1:
+ s += 2
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ println("uint(s) > uint(len(src)", s, len(src))
+ return ErrSnappyCorrupt
+ }
+ length = 4 + int(src[s-2])>>2&0x7
+ offset = uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])
+
+ case snappyTagCopy2:
+ s += 3
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ println("uint(s) > uint(len(src)", s, len(src))
+ return ErrSnappyCorrupt
+ }
+ length = 1 + int(src[s-3])>>2
+ offset = uint32(src[s-2]) | uint32(src[s-1])<<8
+
+ case snappyTagCopy4:
+ s += 5
+ if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line.
+ println("uint(s) > uint(len(src)", s, len(src))
+ return ErrSnappyCorrupt
+ }
+ length = 1 + int(src[s-5])>>2
+ offset = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
+ }
+
+ if offset <= 0 || blk.size+lits < int(offset) /*|| length > len(blk)-d */ {
+ println("offset <= 0 || blk.size+lits < int(offset)", offset, blk.size+lits, int(offset), blk.size, lits)
+
+ return ErrSnappyCorrupt
+ }
+
+ // Check if offset is one of the recent offsets.
+ // Adjusts the output offset accordingly.
+ // Gives a tiny bit of compression, typically around 1%.
+ if false {
+ offset = blk.matchOffset(offset, uint32(lits))
+ } else {
+ offset += 3
+ }
+
+ blk.sequences = append(blk.sequences, seq{
+ litLen: uint32(lits),
+ offset: offset,
+ matchLen: uint32(length) - zstdMinMatch,
+ })
+ blk.size += length + lits
+ lits = 0
+ }
+ blk.extraLits = lits
+ return nil
+}
+
+func (r *SnappyConverter) readFull(p []byte, allowEOF bool) (ok bool) {
+ if _, r.err = io.ReadFull(r.r, p); r.err != nil {
+ if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) {
+ r.err = ErrSnappyCorrupt
+ }
+ return false
+ }
+ return true
+}
+
+var crcTable = crc32.MakeTable(crc32.Castagnoli)
+
+// crc implements the checksum specified in section 3 of
+// https://github.com/google/snappy/blob/master/framing_format.txt
+func snappyCRC(b []byte) uint32 {
+ c := crc32.Update(0, crcTable, b)
+ return c>>15 | c<<17 + 0xa282ead8
+}
+
+// snappyDecodedLen returns the length of the decoded block and the number of bytes
+// that the length header occupied.
+func snappyDecodedLen(src []byte) (blockLen, headerLen int, err error) {
+ v, n := binary.Uvarint(src)
+ if n <= 0 || v > 0xffffffff {
+ return 0, 0, ErrSnappyCorrupt
+ }
+
+ const wordSize = 32 << (^uint(0) >> 32 & 1)
+ if wordSize == 32 && v > 0x7fffffff {
+ return 0, 0, ErrSnappyTooLarge
+ }
+ return int(v), n, nil
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/zip.go b/vendor/github.com/klauspost/compress/zstd/zip.go
new file mode 100644
index 00000000..3198d718
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/zip.go
@@ -0,0 +1,141 @@
+// Copyright 2019+ Klaus Post. All rights reserved.
+// License information can be found in the LICENSE file.
+
+package zstd
+
+import (
+ "errors"
+ "io"
+ "sync"
+)
+
+// ZipMethodWinZip is the method for Zstandard compressed data inside Zip files for WinZip.
+// See https://www.winzip.com/win/en/comp_info.html
+const ZipMethodWinZip = 93
+
+// ZipMethodPKWare is the original method number used by PKWARE to indicate Zstandard compression.
+// Deprecated: This has been deprecated by PKWARE, use ZipMethodWinZip instead for compression.
+// See https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT
+const ZipMethodPKWare = 20
+
+// zipReaderPool is the default reader pool.
+var zipReaderPool = sync.Pool{New: func() any {
+ z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1))
+ if err != nil {
+ panic(err)
+ }
+ return z
+}}
+
+// newZipReader creates a pooled zip decompressor.
+func newZipReader(opts ...DOption) func(r io.Reader) io.ReadCloser {
+ pool := &zipReaderPool
+ if len(opts) > 0 {
+ opts = append([]DOption{WithDecoderLowmem(true), WithDecoderMaxWindow(128 << 20)}, opts...)
+ // Force concurrency 1
+ opts = append(opts, WithDecoderConcurrency(1))
+ // Create our own pool
+ pool = &sync.Pool{}
+ }
+ return func(r io.Reader) io.ReadCloser {
+ dec, ok := pool.Get().(*Decoder)
+ if ok {
+ dec.Reset(r)
+ } else {
+ d, err := NewReader(r, opts...)
+ if err != nil {
+ panic(err)
+ }
+ dec = d
+ }
+ return &pooledZipReader{dec: dec, pool: pool}
+ }
+}
+
+type pooledZipReader struct {
+ mu sync.Mutex // guards Close and Read
+ pool *sync.Pool
+ dec *Decoder
+}
+
+func (r *pooledZipReader) Read(p []byte) (n int, err error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.dec == nil {
+ return 0, errors.New("read after close or EOF")
+ }
+ dec, err := r.dec.Read(p)
+ if err == io.EOF {
+ r.dec.Reset(nil)
+ r.pool.Put(r.dec)
+ r.dec = nil
+ }
+ return dec, err
+}
+
+func (r *pooledZipReader) Close() error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ var err error
+ if r.dec != nil {
+ err = r.dec.Reset(nil)
+ r.pool.Put(r.dec)
+ r.dec = nil
+ }
+ return err
+}
+
+type pooledZipWriter struct {
+ mu sync.Mutex // guards Close and Read
+ enc *Encoder
+ pool *sync.Pool
+}
+
+func (w *pooledZipWriter) Write(p []byte) (n int, err error) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ if w.enc == nil {
+ return 0, errors.New("Write after Close")
+ }
+ return w.enc.Write(p)
+}
+
+func (w *pooledZipWriter) Close() error {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ var err error
+ if w.enc != nil {
+ err = w.enc.Close()
+ w.pool.Put(w.enc)
+ w.enc = nil
+ }
+ return err
+}
+
+// ZipCompressor returns a compressor that can be registered with zip libraries.
+// The provided encoder options will be used on all encodes.
+func ZipCompressor(opts ...EOption) func(w io.Writer) (io.WriteCloser, error) {
+ var pool sync.Pool
+ return func(w io.Writer) (io.WriteCloser, error) {
+ enc, ok := pool.Get().(*Encoder)
+ if ok {
+ enc.Reset(w)
+ } else {
+ var err error
+ enc, err = NewWriter(w, opts...)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return &pooledZipWriter{enc: enc, pool: &pool}, nil
+ }
+}
+
+// ZipDecompressor returns a decompressor that can be registered with zip libraries.
+// See ZipCompressor for example.
+// Options can be specified. WithDecoderConcurrency(1) is forced,
+// and by default a 128MB maximum decompression window is specified.
+// The window size can be overridden if required.
+func ZipDecompressor(opts ...DOption) func(r io.Reader) io.ReadCloser {
+ return newZipReader(opts...)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/zstd.go b/vendor/github.com/klauspost/compress/zstd/zstd.go
new file mode 100644
index 00000000..1a869710
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/zstd.go
@@ -0,0 +1,126 @@
+// Package zstd provides decompression of zstandard files.
+//
+// For advanced usage and examples, go to the README: https://github.com/klauspost/compress/tree/master/zstd#zstd
+package zstd
+
+import (
+ "bytes"
+ "errors"
+ "log"
+ "math"
+
+ "github.com/klauspost/compress/internal/le"
+)
+
+// enable debug printing
+const debug = false
+
+// enable encoding debug printing
+const debugEncoder = debug
+
+// enable decoding debug printing
+const debugDecoder = debug
+
+// Enable extra assertions.
+const debugAsserts = debug || false
+
+// print sequence details
+const debugSequences = false
+
+// print detailed matching information
+const debugMatches = false
+
+// force encoder to use predefined tables.
+const forcePreDef = false
+
+// zstdMinMatch is the minimum zstd match length.
+const zstdMinMatch = 3
+
+// fcsUnknown is used for unknown frame content size.
+const fcsUnknown = math.MaxUint64
+
+var (
+ // ErrReservedBlockType is returned when a reserved block type is found.
+ // Typically this indicates wrong or corrupted input.
+ ErrReservedBlockType = errors.New("invalid input: reserved block type encountered")
+
+ // ErrCompressedSizeTooBig is returned when a block is bigger than allowed.
+ // Typically this indicates wrong or corrupted input.
+ ErrCompressedSizeTooBig = errors.New("invalid input: compressed size too big")
+
+ // ErrBlockTooSmall is returned when a block is too small to be decoded.
+ // Typically returned on invalid input.
+ ErrBlockTooSmall = errors.New("block too small")
+
+ // ErrUnexpectedBlockSize is returned when a block has unexpected size.
+ // Typically returned on invalid input.
+ ErrUnexpectedBlockSize = errors.New("unexpected block size")
+
+ // ErrMagicMismatch is returned when a "magic" number isn't what is expected.
+ // Typically this indicates wrong or corrupted input.
+ ErrMagicMismatch = errors.New("invalid input: magic number mismatch")
+
+ // ErrWindowSizeExceeded is returned when a reference exceeds the valid window size.
+ // Typically this indicates wrong or corrupted input.
+ ErrWindowSizeExceeded = errors.New("window size exceeded")
+
+ // ErrWindowSizeTooSmall is returned when no window size is specified.
+ // Typically this indicates wrong or corrupted input.
+ ErrWindowSizeTooSmall = errors.New("invalid input: window size was too small")
+
+ // ErrDecoderSizeExceeded is returned if decompressed size exceeds the configured limit.
+ ErrDecoderSizeExceeded = errors.New("decompressed size exceeds configured limit")
+
+ // ErrUnknownDictionary is returned if the dictionary ID is unknown.
+ ErrUnknownDictionary = errors.New("unknown dictionary")
+
+ // ErrFrameSizeExceeded is returned if the stated frame size is exceeded.
+ // This is only returned if SingleSegment is specified on the frame.
+ ErrFrameSizeExceeded = errors.New("frame size exceeded")
+
+ // ErrFrameSizeMismatch is returned if the stated frame size does not match the expected size.
+ // This is only returned if SingleSegment is specified on the frame.
+ ErrFrameSizeMismatch = errors.New("frame size does not match size on stream")
+
+ // ErrCRCMismatch is returned if CRC mismatches.
+ ErrCRCMismatch = errors.New("CRC check failed")
+
+ // ErrDecoderClosed will be returned if the Decoder was used after
+ // Close has been called.
+ ErrDecoderClosed = errors.New("decoder used after Close")
+
+ // ErrEncoderClosed will be returned if the Encoder was used after
+ // Close has been called.
+ ErrEncoderClosed = errors.New("encoder used after Close")
+
+ // ErrDecoderNilInput is returned when a nil Reader was provided
+ // and an operation other than Reset/DecodeAll/Close was attempted.
+ ErrDecoderNilInput = errors.New("nil input provided as reader")
+)
+
+func println(a ...any) {
+ if debug || debugDecoder || debugEncoder {
+ log.Println(a...)
+ }
+}
+
+func printf(format string, a ...any) {
+ if debug || debugDecoder || debugEncoder {
+ log.Printf(format, a...)
+ }
+}
+
+func load3232(b []byte, i int32) uint32 {
+ return le.Load32(b, i)
+}
+
+func load6432(b []byte, i int32) uint64 {
+ return le.Load64(b, i)
+}
+
+type byter interface {
+ Bytes() []byte
+ Len() int
+}
+
+var _ byter = &bytes.Buffer{}
diff --git a/vendor/github.com/quic-go/qpack/.codecov.yml b/vendor/github.com/quic-go/qpack/.codecov.yml
new file mode 100644
index 00000000..00064af3
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/.codecov.yml
@@ -0,0 +1,7 @@
+coverage:
+ round: nearest
+ status:
+ project:
+ default:
+ threshold: 1
+ patch: false
diff --git a/vendor/github.com/quic-go/qpack/.gitignore b/vendor/github.com/quic-go/qpack/.gitignore
new file mode 100644
index 00000000..66c189a0
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/.gitignore
@@ -0,0 +1,6 @@
+fuzzing/*.zip
+fuzzing/coverprofile
+fuzzing/crashers
+fuzzing/sonarprofile
+fuzzing/suppressions
+fuzzing/corpus/
diff --git a/vendor/github.com/quic-go/qpack/.gitmodules b/vendor/github.com/quic-go/qpack/.gitmodules
new file mode 100644
index 00000000..47b62862
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "interop/qifs"]
+ path = interop/qifs
+ url = https://github.com/qpackers/qifs.git
diff --git a/vendor/github.com/quic-go/qpack/.golangci.yml b/vendor/github.com/quic-go/qpack/.golangci.yml
new file mode 100644
index 00000000..2b48866b
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/.golangci.yml
@@ -0,0 +1,22 @@
+version: "2"
+linters:
+ default: none
+ enable:
+ - asciicheck
+ - copyloopvar
+ - exhaustive
+ - govet
+ - ineffassign
+ - misspell
+ - nolintlint
+ - prealloc
+ - staticcheck
+ - unconvert
+ - unparam
+ - unused
+ - usetesting
+formatters:
+ enable:
+ - gofmt
+ - gofumpt
+ - goimports
diff --git a/vendor/github.com/quic-go/qpack/LICENSE.md b/vendor/github.com/quic-go/qpack/LICENSE.md
new file mode 100644
index 00000000..1ac5a2d9
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/LICENSE.md
@@ -0,0 +1,7 @@
+Copyright 2019 Marten Seemann
+
+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/quic-go/qpack/README.md b/vendor/github.com/quic-go/qpack/README.md
new file mode 100644
index 00000000..df116490
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/README.md
@@ -0,0 +1,21 @@
+# QPACK
+
+[](https://pkg.go.dev/github.com/quic-go/qpack)
+[](https://codecov.io/gh/quic-go/qpack)
+[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:quic-go)
+
+This is a minimal QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)) implementation in Go. It reuses the Huffman encoder / decoder code from the [HPACK implementation in the Go standard library](https://github.com/golang/net/tree/master/http2/hpack).
+
+It is fully interoperable with other QPACK implementations (both encoders and decoders). However, it does not support the dynamic table and relies solely on the static table and string literals (including Huffman encoding), which limits compression efficiency. If you're interested in dynamic table support, please comment on [issue #33](https://github.com/quic-go/qpack/issues/33).
+
+## Running the Interop Tests
+
+Install the [QPACK interop files](https://github.com/qpackers/qifs/) by running
+```bash
+git submodule update --init --recursive
+```
+
+Then run the tests:
+```bash
+go test -v ./interop
+```
diff --git a/vendor/github.com/quic-go/qpack/decoder.go b/vendor/github.com/quic-go/qpack/decoder.go
new file mode 100644
index 00000000..af8bbb59
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/decoder.go
@@ -0,0 +1,183 @@
+package qpack
+
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "golang.org/x/net/http2/hpack"
+)
+
+// An invalidIndexError is returned when decoding encounters an invalid index
+// (e.g., an index that is out of bounds for the static table).
+type invalidIndexError int
+
+func (e invalidIndexError) Error() string {
+ return fmt.Sprintf("invalid indexed representation index %d", int(e))
+}
+
+var errNoDynamicTable = errors.New("no dynamic table")
+
+// A Decoder decodes QPACK header blocks.
+// A Decoder can be reused to decode multiple header blocks on different streams
+// on the same connection (e.g., headers then trailers).
+// This will be useful when dynamic table support is added.
+type Decoder struct{}
+
+// DecodeFunc is a function that decodes the next header field from a header block.
+// It should be called repeatedly until it returns io.EOF.
+// It returns io.EOF when all header fields have been decoded.
+// Any error other than io.EOF indicates a decoding error.
+type DecodeFunc func() (HeaderField, error)
+
+// NewDecoder returns a new Decoder.
+func NewDecoder() *Decoder {
+ return &Decoder{}
+}
+
+// Decode returns a function that decodes header fields from the given header block.
+// It does not copy the slice; the caller must ensure it remains valid during decoding.
+func (d *Decoder) Decode(p []byte) DecodeFunc {
+ var readRequiredInsertCount bool
+ var readDeltaBase bool
+
+ return func() (HeaderField, error) {
+ if !readRequiredInsertCount {
+ requiredInsertCount, rest, err := readVarInt(8, p)
+ if err != nil {
+ return HeaderField{}, err
+ }
+ p = rest
+ readRequiredInsertCount = true
+ if requiredInsertCount != 0 {
+ return HeaderField{}, errors.New("expected Required Insert Count to be zero")
+ }
+ }
+
+ if !readDeltaBase {
+ base, rest, err := readVarInt(7, p)
+ if err != nil {
+ return HeaderField{}, err
+ }
+ p = rest
+ readDeltaBase = true
+ if base != 0 {
+ return HeaderField{}, errors.New("expected Base to be zero")
+ }
+ }
+
+ if len(p) == 0 {
+ return HeaderField{}, io.EOF
+ }
+
+ b := p[0]
+ var hf HeaderField
+ var rest []byte
+ var err error
+ switch {
+ case (b & 0x80) > 0: // 1xxxxxxx
+ hf, rest, err = d.parseIndexedHeaderField(p)
+ case (b & 0xc0) == 0x40: // 01xxxxxx
+ hf, rest, err = d.parseLiteralHeaderField(p)
+ case (b & 0xe0) == 0x20: // 001xxxxx
+ hf, rest, err = d.parseLiteralHeaderFieldWithoutNameReference(p)
+ default:
+ err = fmt.Errorf("unexpected type byte: %#x", b)
+ }
+ p = rest
+ if err != nil {
+ return HeaderField{}, err
+ }
+ return hf, nil
+ }
+}
+
+func (d *Decoder) parseIndexedHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
+ if buf[0]&0x40 == 0 {
+ return HeaderField{}, buf, errNoDynamicTable
+ }
+ index, rest, err := readVarInt(6, buf)
+ if err != nil {
+ return HeaderField{}, buf, err
+ }
+ hf, ok := d.at(index)
+ if !ok {
+ return HeaderField{}, buf, invalidIndexError(index)
+ }
+ return hf, rest, nil
+}
+
+func (d *Decoder) parseLiteralHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
+ if buf[0]&0x10 == 0 {
+ return HeaderField{}, buf, errNoDynamicTable
+ }
+ // We don't need to check the value of the N-bit here.
+ // It's only relevant when re-encoding header fields,
+ // and determines whether the header field can be added to the dynamic table.
+ // Since we don't support the dynamic table, we can ignore it.
+ index, rest, err := readVarInt(4, buf)
+ if err != nil {
+ return HeaderField{}, buf, err
+ }
+ hf, ok := d.at(index)
+ if !ok {
+ return HeaderField{}, buf, invalidIndexError(index)
+ }
+ buf = rest
+ if len(buf) == 0 {
+ return HeaderField{}, buf, io.ErrUnexpectedEOF
+ }
+ usesHuffman := buf[0]&0x80 > 0
+ val, rest, err := d.readString(rest, 7, usesHuffman)
+ if err != nil {
+ return HeaderField{}, rest, err
+ }
+ hf.Value = val
+ return hf, rest, nil
+}
+
+func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference(buf []byte) (_ HeaderField, rest []byte, _ error) {
+ usesHuffmanForName := buf[0]&0x8 > 0
+ name, rest, err := d.readString(buf, 3, usesHuffmanForName)
+ if err != nil {
+ return HeaderField{}, rest, err
+ }
+ buf = rest
+ if len(buf) == 0 {
+ return HeaderField{}, rest, io.ErrUnexpectedEOF
+ }
+ usesHuffmanForVal := buf[0]&0x80 > 0
+ val, rest, err := d.readString(buf, 7, usesHuffmanForVal)
+ if err != nil {
+ return HeaderField{}, rest, err
+ }
+ return HeaderField{Name: name, Value: val}, rest, nil
+}
+
+func (d *Decoder) readString(buf []byte, n uint8, usesHuffman bool) (string, []byte, error) {
+ l, buf, err := readVarInt(n, buf)
+ if err != nil {
+ return "", nil, err
+ }
+ if uint64(len(buf)) < l {
+ return "", nil, io.ErrUnexpectedEOF
+ }
+ var val string
+ if usesHuffman {
+ val, err = hpack.HuffmanDecodeToString(buf[:l])
+ if err != nil {
+ return "", nil, err
+ }
+ } else {
+ val = string(buf[:l])
+ }
+ buf = buf[l:]
+ return val, buf, nil
+}
+
+func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
+ if i >= uint64(len(staticTableEntries)) {
+ return
+ }
+ return staticTableEntries[i], true
+}
diff --git a/vendor/github.com/quic-go/qpack/encoder.go b/vendor/github.com/quic-go/qpack/encoder.go
new file mode 100644
index 00000000..ad695353
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/encoder.go
@@ -0,0 +1,95 @@
+package qpack
+
+import (
+ "io"
+
+ "golang.org/x/net/http2/hpack"
+)
+
+// An Encoder performs QPACK encoding.
+type Encoder struct {
+ wrotePrefix bool
+
+ w io.Writer
+ buf []byte
+}
+
+// NewEncoder returns a new Encoder which performs QPACK encoding. An
+// encoded data is written to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{w: w}
+}
+
+// WriteField encodes f into a single Write to e's underlying Writer.
+// This function may also produce bytes for the Header Block Prefix
+// if necessary. If produced, it is done before encoding f.
+func (e *Encoder) WriteField(f HeaderField) error {
+ // write the Header Block Prefix
+ if !e.wrotePrefix {
+ e.buf = appendVarInt(e.buf, 8, 0)
+ e.buf = appendVarInt(e.buf, 7, 0)
+ e.wrotePrefix = true
+ }
+
+ idxAndVals, nameFound := encoderMap[f.Name]
+ if nameFound {
+ if idxAndVals.values == nil {
+ if len(f.Value) == 0 {
+ e.writeIndexedField(idxAndVals.idx)
+ } else {
+ e.writeLiteralFieldWithNameReference(&f, idxAndVals.idx)
+ }
+ } else {
+ valIdx, valueFound := idxAndVals.values[f.Value]
+ if valueFound {
+ e.writeIndexedField(valIdx)
+ } else {
+ e.writeLiteralFieldWithNameReference(&f, idxAndVals.idx)
+ }
+ }
+ } else {
+ e.writeLiteralFieldWithoutNameReference(f)
+ }
+
+ _, err := e.w.Write(e.buf)
+ e.buf = e.buf[:0]
+ return err
+}
+
+// Close declares that the encoding is complete and resets the Encoder
+// to be reused again for a new header block.
+func (e *Encoder) Close() error {
+ e.wrotePrefix = false
+ return nil
+}
+
+func (e *Encoder) writeLiteralFieldWithoutNameReference(f HeaderField) {
+ offset := len(e.buf)
+ e.buf = appendVarInt(e.buf, 3, hpack.HuffmanEncodeLength(f.Name))
+ e.buf[offset] ^= 0x20 ^ 0x8
+ e.buf = hpack.AppendHuffmanString(e.buf, f.Name)
+ offset = len(e.buf)
+ e.buf = appendVarInt(e.buf, 7, hpack.HuffmanEncodeLength(f.Value))
+ e.buf[offset] ^= 0x80
+ e.buf = hpack.AppendHuffmanString(e.buf, f.Value)
+}
+
+// Encodes a header field whose name is present in one of the tables.
+func (e *Encoder) writeLiteralFieldWithNameReference(f *HeaderField, id uint8) {
+ offset := len(e.buf)
+ e.buf = appendVarInt(e.buf, 4, uint64(id))
+ // Set the 01NTxxxx pattern, forcing N to 0 and T to 1
+ e.buf[offset] ^= 0x50
+ offset = len(e.buf)
+ e.buf = appendVarInt(e.buf, 7, hpack.HuffmanEncodeLength(f.Value))
+ e.buf[offset] ^= 0x80
+ e.buf = hpack.AppendHuffmanString(e.buf, f.Value)
+}
+
+// Encodes an indexed field, meaning it's entirely defined in one of the tables.
+func (e *Encoder) writeIndexedField(id uint8) {
+ offset := len(e.buf)
+ e.buf = appendVarInt(e.buf, 6, uint64(id))
+ // Set the 1Txxxxxx pattern, forcing T to 1
+ e.buf[offset] ^= 0xc0
+}
diff --git a/vendor/github.com/quic-go/qpack/header_field.go b/vendor/github.com/quic-go/qpack/header_field.go
new file mode 100644
index 00000000..4c043a99
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/header_field.go
@@ -0,0 +1,16 @@
+package qpack
+
+// A HeaderField is a name-value pair. Both the name and value are
+// treated as opaque sequences of octets.
+type HeaderField struct {
+ Name string
+ Value string
+}
+
+// IsPseudo reports whether the header field is an HTTP3 pseudo header.
+// That is, it reports whether it starts with a colon.
+// It is not otherwise guaranteed to be a valid pseudo header field,
+// though.
+func (hf HeaderField) IsPseudo() bool {
+ return len(hf.Name) != 0 && hf.Name[0] == ':'
+}
diff --git a/vendor/github.com/quic-go/qpack/static_table.go b/vendor/github.com/quic-go/qpack/static_table.go
new file mode 100644
index 00000000..93eca275
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/static_table.go
@@ -0,0 +1,255 @@
+package qpack
+
+var staticTableEntries = [...]HeaderField{
+ {Name: ":authority"},
+ {Name: ":path", Value: "/"},
+ {Name: "age", Value: "0"},
+ {Name: "content-disposition"},
+ {Name: "content-length", Value: "0"},
+ {Name: "cookie"},
+ {Name: "date"},
+ {Name: "etag"},
+ {Name: "if-modified-since"},
+ {Name: "if-none-match"},
+ {Name: "last-modified"},
+ {Name: "link"},
+ {Name: "location"},
+ {Name: "referer"},
+ {Name: "set-cookie"},
+ {Name: ":method", Value: "CONNECT"},
+ {Name: ":method", Value: "DELETE"},
+ {Name: ":method", Value: "GET"},
+ {Name: ":method", Value: "HEAD"},
+ {Name: ":method", Value: "OPTIONS"},
+ {Name: ":method", Value: "POST"},
+ {Name: ":method", Value: "PUT"},
+ {Name: ":scheme", Value: "http"},
+ {Name: ":scheme", Value: "https"},
+ {Name: ":status", Value: "103"},
+ {Name: ":status", Value: "200"},
+ {Name: ":status", Value: "304"},
+ {Name: ":status", Value: "404"},
+ {Name: ":status", Value: "503"},
+ {Name: "accept", Value: "*/*"},
+ {Name: "accept", Value: "application/dns-message"},
+ {Name: "accept-encoding", Value: "gzip, deflate, br"},
+ {Name: "accept-ranges", Value: "bytes"},
+ {Name: "access-control-allow-headers", Value: "cache-control"},
+ {Name: "access-control-allow-headers", Value: "content-type"},
+ {Name: "access-control-allow-origin", Value: "*"},
+ {Name: "cache-control", Value: "max-age=0"},
+ {Name: "cache-control", Value: "max-age=2592000"},
+ {Name: "cache-control", Value: "max-age=604800"},
+ {Name: "cache-control", Value: "no-cache"},
+ {Name: "cache-control", Value: "no-store"},
+ {Name: "cache-control", Value: "public, max-age=31536000"},
+ {Name: "content-encoding", Value: "br"},
+ {Name: "content-encoding", Value: "gzip"},
+ {Name: "content-type", Value: "application/dns-message"},
+ {Name: "content-type", Value: "application/javascript"},
+ {Name: "content-type", Value: "application/json"},
+ {Name: "content-type", Value: "application/x-www-form-urlencoded"},
+ {Name: "content-type", Value: "image/gif"},
+ {Name: "content-type", Value: "image/jpeg"},
+ {Name: "content-type", Value: "image/png"},
+ {Name: "content-type", Value: "text/css"},
+ {Name: "content-type", Value: "text/html; charset=utf-8"},
+ {Name: "content-type", Value: "text/plain"},
+ {Name: "content-type", Value: "text/plain;charset=utf-8"},
+ {Name: "range", Value: "bytes=0-"},
+ {Name: "strict-transport-security", Value: "max-age=31536000"},
+ {Name: "strict-transport-security", Value: "max-age=31536000; includesubdomains"},
+ {Name: "strict-transport-security", Value: "max-age=31536000; includesubdomains; preload"},
+ {Name: "vary", Value: "accept-encoding"},
+ {Name: "vary", Value: "origin"},
+ {Name: "x-content-type-options", Value: "nosniff"},
+ {Name: "x-xss-protection", Value: "1; mode=block"},
+ {Name: ":status", Value: "100"},
+ {Name: ":status", Value: "204"},
+ {Name: ":status", Value: "206"},
+ {Name: ":status", Value: "302"},
+ {Name: ":status", Value: "400"},
+ {Name: ":status", Value: "403"},
+ {Name: ":status", Value: "421"},
+ {Name: ":status", Value: "425"},
+ {Name: ":status", Value: "500"},
+ {Name: "accept-language"},
+ {Name: "access-control-allow-credentials", Value: "FALSE"},
+ {Name: "access-control-allow-credentials", Value: "TRUE"},
+ {Name: "access-control-allow-headers", Value: "*"},
+ {Name: "access-control-allow-methods", Value: "get"},
+ {Name: "access-control-allow-methods", Value: "get, post, options"},
+ {Name: "access-control-allow-methods", Value: "options"},
+ {Name: "access-control-expose-headers", Value: "content-length"},
+ {Name: "access-control-request-headers", Value: "content-type"},
+ {Name: "access-control-request-method", Value: "get"},
+ {Name: "access-control-request-method", Value: "post"},
+ {Name: "alt-svc", Value: "clear"},
+ {Name: "authorization"},
+ {Name: "content-security-policy", Value: "script-src 'none'; object-src 'none'; base-uri 'none'"},
+ {Name: "early-data", Value: "1"},
+ {Name: "expect-ct"},
+ {Name: "forwarded"},
+ {Name: "if-range"},
+ {Name: "origin"},
+ {Name: "purpose", Value: "prefetch"},
+ {Name: "server"},
+ {Name: "timing-allow-origin", Value: "*"},
+ {Name: "upgrade-insecure-requests", Value: "1"},
+ {Name: "user-agent"},
+ {Name: "x-forwarded-for"},
+ {Name: "x-frame-options", Value: "deny"},
+ {Name: "x-frame-options", Value: "sameorigin"},
+}
+
+// Only needed for tests.
+// use go:linkname to retrieve the static table.
+//
+//nolint:unused
+func getStaticTable() []HeaderField {
+ return staticTableEntries[:]
+}
+
+type indexAndValues struct {
+ idx uint8
+ values map[string]uint8
+}
+
+// A map of the header names from the static table to their index in the table.
+// This is used by the encoder to quickly find if a header is in the static table
+// and what value should be used to encode it.
+// There's a second level of mapping for the headers that have some predefined
+// values in the static table.
+var encoderMap = map[string]indexAndValues{
+ ":authority": {0, nil},
+ ":path": {1, map[string]uint8{"/": 1}},
+ "age": {2, map[string]uint8{"0": 2}},
+ "content-disposition": {3, nil},
+ "content-length": {4, map[string]uint8{"0": 4}},
+ "cookie": {5, nil},
+ "date": {6, nil},
+ "etag": {7, nil},
+ "if-modified-since": {8, nil},
+ "if-none-match": {9, nil},
+ "last-modified": {10, nil},
+ "link": {11, nil},
+ "location": {12, nil},
+ "referer": {13, nil},
+ "set-cookie": {14, nil},
+ ":method": {15, map[string]uint8{
+ "CONNECT": 15,
+ "DELETE": 16,
+ "GET": 17,
+ "HEAD": 18,
+ "OPTIONS": 19,
+ "POST": 20,
+ "PUT": 21,
+ }},
+ ":scheme": {22, map[string]uint8{
+ "http": 22,
+ "https": 23,
+ }},
+ ":status": {24, map[string]uint8{
+ "103": 24,
+ "200": 25,
+ "304": 26,
+ "404": 27,
+ "503": 28,
+ "100": 63,
+ "204": 64,
+ "206": 65,
+ "302": 66,
+ "400": 67,
+ "403": 68,
+ "421": 69,
+ "425": 70,
+ "500": 71,
+ }},
+ "accept": {29, map[string]uint8{
+ "*/*": 29,
+ "application/dns-message": 30,
+ }},
+ "accept-encoding": {31, map[string]uint8{"gzip, deflate, br": 31}},
+ "accept-ranges": {32, map[string]uint8{"bytes": 32}},
+ "access-control-allow-headers": {33, map[string]uint8{
+ "cache-control": 33,
+ "content-type": 34,
+ "*": 75,
+ }},
+ "access-control-allow-origin": {35, map[string]uint8{"*": 35}},
+ "cache-control": {36, map[string]uint8{
+ "max-age=0": 36,
+ "max-age=2592000": 37,
+ "max-age=604800": 38,
+ "no-cache": 39,
+ "no-store": 40,
+ "public, max-age=31536000": 41,
+ }},
+ "content-encoding": {42, map[string]uint8{
+ "br": 42,
+ "gzip": 43,
+ }},
+ "content-type": {44, map[string]uint8{
+ "application/dns-message": 44,
+ "application/javascript": 45,
+ "application/json": 46,
+ "application/x-www-form-urlencoded": 47,
+ "image/gif": 48,
+ "image/jpeg": 49,
+ "image/png": 50,
+ "text/css": 51,
+ "text/html; charset=utf-8": 52,
+ "text/plain": 53,
+ "text/plain;charset=utf-8": 54,
+ }},
+ "range": {55, map[string]uint8{"bytes=0-": 55}},
+ "strict-transport-security": {56, map[string]uint8{
+ "max-age=31536000": 56,
+ "max-age=31536000; includesubdomains": 57,
+ "max-age=31536000; includesubdomains; preload": 58,
+ }},
+ "vary": {59, map[string]uint8{
+ "accept-encoding": 59,
+ "origin": 60,
+ }},
+ "x-content-type-options": {61, map[string]uint8{"nosniff": 61}},
+ "x-xss-protection": {62, map[string]uint8{"1; mode=block": 62}},
+ // ":status" is duplicated and takes index 63 to 71
+ "accept-language": {72, nil},
+ "access-control-allow-credentials": {73, map[string]uint8{
+ "FALSE": 73,
+ "TRUE": 74,
+ }},
+ // "access-control-allow-headers" is duplicated and takes index 75
+ "access-control-allow-methods": {76, map[string]uint8{
+ "get": 76,
+ "get, post, options": 77,
+ "options": 78,
+ }},
+ "access-control-expose-headers": {79, map[string]uint8{"content-length": 79}},
+ "access-control-request-headers": {80, map[string]uint8{"content-type": 80}},
+ "access-control-request-method": {81, map[string]uint8{
+ "get": 81,
+ "post": 82,
+ }},
+ "alt-svc": {83, map[string]uint8{"clear": 83}},
+ "authorization": {84, nil},
+ "content-security-policy": {85, map[string]uint8{
+ "script-src 'none'; object-src 'none'; base-uri 'none'": 85,
+ }},
+ "early-data": {86, map[string]uint8{"1": 86}},
+ "expect-ct": {87, nil},
+ "forwarded": {88, nil},
+ "if-range": {89, nil},
+ "origin": {90, nil},
+ "purpose": {91, map[string]uint8{"prefetch": 91}},
+ "server": {92, nil},
+ "timing-allow-origin": {93, map[string]uint8{"*": 93}},
+ "upgrade-insecure-requests": {94, map[string]uint8{"1": 94}},
+ "user-agent": {95, nil},
+ "x-forwarded-for": {96, nil},
+ "x-frame-options": {97, map[string]uint8{
+ "deny": 97,
+ "sameorigin": 98,
+ }},
+}
diff --git a/vendor/github.com/quic-go/qpack/varint.go b/vendor/github.com/quic-go/qpack/varint.go
new file mode 100644
index 00000000..30ff0932
--- /dev/null
+++ b/vendor/github.com/quic-go/qpack/varint.go
@@ -0,0 +1,69 @@
+package qpack
+
+// copied from the Go standard library HPACK implementation
+
+import (
+ "errors"
+ "io"
+)
+
+var errVarintOverflow = errors.New("varint integer overflow")
+
+// appendVarInt appends i, as encoded in variable integer form using n
+// bit prefix, to dst and returns the extended buffer.
+//
+// See
+// http://http2.github.io/http2-spec/compression.html#integer.representation
+func appendVarInt(dst []byte, n byte, i uint64) []byte {
+ k := uint64((1 << n) - 1)
+ if i < k {
+ return append(dst, byte(i))
+ }
+ dst = append(dst, byte(k))
+ i -= k
+ for ; i >= 128; i >>= 7 {
+ dst = append(dst, byte(0x80|(i&0x7f)))
+ }
+ return append(dst, byte(i))
+}
+
+// readVarInt reads an unsigned variable length integer off the
+// beginning of p. n is the parameter as described in
+// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
+//
+// n must always be between 1 and 8.
+//
+// The returned remain buffer is either a smaller suffix of p, or err != nil.
+// The error is io.ErrUnexpectedEOF if p doesn't contain a complete integer.
+func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
+ if n < 1 || n > 8 {
+ panic("bad n")
+ }
+ if len(p) == 0 {
+ return 0, p, io.ErrUnexpectedEOF
+ }
+ i = uint64(p[0])
+ if n < 8 {
+ i &= (1 << uint64(n)) - 1
+ }
+ if i < (1< 0 {
+ b := p[0]
+ p = p[1:]
+ i += uint64(b&127) << m
+ if b&128 == 0 {
+ return i, p, nil
+ }
+ m += 7
+ if m >= 63 { // TODO: proper overflow check. making this up.
+ return 0, origP, errVarintOverflow
+ }
+ }
+ return 0, origP, io.ErrUnexpectedEOF
+}
diff --git a/vendor/github.com/quic-go/quic-go/.gitignore b/vendor/github.com/quic-go/quic-go/.gitignore
new file mode 100644
index 00000000..60571ed0
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/.gitignore
@@ -0,0 +1,20 @@
+debug
+debug.test
+main
+mockgen_tmp.go
+*.qtr
+*.qlog
+*.sqlog
+*.txt
+race.[0-9]*
+
+fuzzing/*/*.zip
+fuzzing/*/coverprofile
+fuzzing/*/crashers
+fuzzing/*/sonarprofile
+fuzzing/*/suppressions
+fuzzing/*/corpus/
+
+**/testdata/fuzz/
+
+gomock_reflect_*/
diff --git a/vendor/github.com/quic-go/quic-go/.golangci.yml b/vendor/github.com/quic-go/quic-go/.golangci.yml
new file mode 100644
index 00000000..82bf4fc9
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/.golangci.yml
@@ -0,0 +1,99 @@
+version: "2"
+linters:
+ default: none
+ enable:
+ - asciicheck
+ - copyloopvar
+ - depguard
+ - exhaustive
+ - govet
+ - ineffassign
+ - misspell
+ - nolintlint
+ - prealloc
+ - staticcheck
+ - unconvert
+ - unparam
+ - unused
+ - usetesting
+ settings:
+ depguard:
+ rules:
+ random:
+ deny:
+ - pkg: "math/rand$"
+ desc: use math/rand/v2
+ - pkg: "golang.org/x/exp/rand"
+ desc: use math/rand/v2
+ quicvarint:
+ list-mode: strict
+ files:
+ - '**/github.com/quic-go/quic-go/quicvarint/*'
+ - '!$test'
+ allow:
+ - $gostd
+ rsa:
+ list-mode: original
+ deny:
+ - pkg: crypto/rsa
+ desc: "use crypto/ed25519 instead"
+ ginkgo:
+ list-mode: original
+ deny:
+ - pkg: github.com/onsi/ginkgo
+ desc: "use standard Go tests"
+ - pkg: github.com/onsi/ginkgo/v2
+ desc: "use standard Go tests"
+ - pkg: github.com/onsi/gomega
+ desc: "use standard Go tests"
+ http3-internal:
+ list-mode: lax
+ files:
+ - '**/http3/**'
+ deny:
+ - pkg: 'github.com/quic-go/quic-go/internal'
+ desc: 'no dependency on quic-go/internal'
+ misspell:
+ ignore-rules:
+ - ect
+ # see https://github.com/ldez/usetesting/issues/10
+ usetesting:
+ context-background: false
+ context-todo: false
+ exclusions:
+ generated: lax
+ presets:
+ - comments
+ - common-false-positives
+ - legacy
+ - std-error-handling
+ rules:
+ - linters:
+ - depguard
+ path: internal/qtls
+ - linters:
+ - exhaustive
+ - prealloc
+ - unparam
+ path: _test\.go
+ - linters:
+ - staticcheck
+ path: _test\.go
+ text: 'SA1029:' # inappropriate key in call to context.WithValue
+ paths:
+ - internal/handshake/cipher_suite.go
+ - third_party$
+ - builtin$
+ - examples$
+formatters:
+ enable:
+ - gofmt
+ - gofumpt
+ - goimports
+ exclusions:
+ generated: lax
+ paths:
+ - internal/handshake/cipher_suite.go
+ - third_party$
+ - builtin$
+ - examples$
diff --git a/vendor/github.com/quic-go/quic-go/FIPS140.md b/vendor/github.com/quic-go/quic-go/FIPS140.md
new file mode 100644
index 00000000..7d7d92e8
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/FIPS140.md
@@ -0,0 +1,37 @@
+# FIPS 140-3
+
+quic-go relies on the Go standard library for cryptography, including the Go Cryptographic Module described in [The FIPS 140-3 Go Cryptographic Module](https://go.dev/blog/fips140). quic-go does not seek separate FIPS 140-3 validation as a cryptographic module. This document explains how quic-go uses Go standard library cryptography for QUIC operations relevant to FIPS 140-3.
+
+Starting with quic-go v0.60, the behavior described here applies when built with Go 1.26 or newer. With older Go versions, quic-go still builds and runs as usual, without any attempt to meet FIPS 140 requirements.
+
+## QUIC operations relevant to FIPS 140-3
+
+quic-go delegates the TLS 1.3 handshake, certificate handling, cipher suite selection, session tickets, and the TLS key schedule to `crypto/tls`. When Go's FIPS 140-3 mode is active, `crypto/tls` restricts the algorithms it negotiates.
+
+### Packet protection AEADs
+
+The main quic-go-specific FIPS-relevant operations are the AEADs protecting Handshake, 0-RTT, and 1-RTT packets.
+
+AES-GCM packet protection AEADs are constructed through the Go standard library's TLS 1.3 AES-GCM implementation. Today this uses `go:linkname` to call the unexported `crypto/tls.aeadAESGCMTLS13`, because the standard library does not yet expose a QUIC-specific constructor; see [golang/go#79219](https://github.com/golang/go/issues/79219).
+
+ChaCha20-Poly1305 is not used in Go's FIPS 140-3 mode. `crypto/tls` avoids that cipher suite during negotiation, and quic-go additionally guards its internal ChaCha20-Poly1305 path when FIPS 140-3 mode is enabled.
+
+### Header protection
+
+For Handshake, 0-RTT, and 1-RTT packets protected with AES cipher suites, header protection keys are derived with `crypto/hkdf` and the AES block operation uses `crypto/aes`. ChaCha20 header protection is tied to the ChaCha20-Poly1305 cipher suite and is not reachable in FIPS 140-3 mode.
+
+### Address validation tokens
+
+quic-go encrypts the address validation tokens it sends in Retry packets and NEW_TOKEN frames. These are not TLS session tickets (those are handled by `crypto/tls`); they carry server-defined state such as the client address, timestamp, RTT information, and Retry connection IDs.
+
+Token-protection keys are derived with `crypto/hkdf`, AES is used via `crypto/aes`, and the token AEAD is constructed with `cipher.NewGCMWithRandomNonce`, keeping token encryption on standard library primitives.
+
+## QUIC operations not relevant to FIPS 140-3
+
+### Initial packet protection
+
+Initial packet protection (including Initial header protection) is not treated as FIPS 140-relevant confidentiality protection: the Initial secrets are derived from constants in RFC 9001 and the packet's destination connection ID, so any observer can derive the same keys. quic-go therefore disables strict FIPS 140 enforcement around Initial packet construction in Go 1.26 FIPS 140-3 mode. See the IETF QUIC mailing list discussion at .
+
+### Retry packet integrity tag
+
+RFC 9001 defines the Retry packet integrity tag using fixed keys and nonces. It guards against accidental corruption and casual injection but does not encrypt packet contents. quic-go treats it as outside the FIPS 140 scope and disables strict FIPS 140 enforcement for that AEAD construction in Go 1.26 FIPS 140-3 mode.
diff --git a/vendor/github.com/quic-go/quic-go/FUZZING.md b/vendor/github.com/quic-go/quic-go/FUZZING.md
new file mode 100644
index 00000000..2662a193
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/FUZZING.md
@@ -0,0 +1,59 @@
+# Fuzzing
+
+[](https://introspector.oss-fuzz.com/project-profile?project=quic-go)
+[](https://app.codecov.io/gh/quic-go/quic-go?flags%5B0%5D=clusterfuzz)
+[](https://app.codecov.io/gh/quic-go/quic-go?flags%5B0%5D=clusterfuzz-lite-batch)
+
+Run the commands below from a local [`google/oss-fuzz`](https://github.com/google/oss-fuzz) checkout.
+Fuzz target names match the binary names listed in `oss-fuzz.sh` (for example, `frame_fuzzer_v2`).
+
+Update the base images:
+```sh
+python3 infra/helper.py pull_images
+```
+
+## Running fuzzers locally
+
+The following steps run a single fuzz target and then open its line-by-line coverage in `go tool cover`.
+
+```sh
+export DOCKER_DEFAULT_PLATFORM=linux/amd64
+export FUZZ_TARGET=
+export CORPUS_DIR=corpus/$FUZZ_TARGET
+
+mkdir -p "$CORPUS_DIR"
+
+python3 infra/helper.py build_image --no-pull quic-go
+python3 infra/helper.py build_fuzzers --sanitizer address quic-go
+python3 infra/helper.py run_fuzzer --corpus-dir="$CORPUS_DIR" quic-go "$FUZZ_TARGET"
+```
+
+Leave `run_fuzzer` running for a while to build up a corpus. It unpacks the seed corpus zip into the corpus directory and appends new entries as it discovers them.
+
+```sh
+python3 infra/helper.py build_fuzzers --sanitizer coverage quic-go
+python3 infra/helper.py coverage --no-serve --fuzz-target "$FUZZ_TARGET" --corpus-dir="$CORPUS_DIR" quic-go
+sed "s#^/out/#$(pwd)/build/out/quic-go/#" build/out/quic-go/fuzz.cov > "/tmp/quic-go-$FUZZ_TARGET.coverprofile"
+go tool cover -html="/tmp/quic-go-$FUZZ_TARGET.coverprofile"
+```
+
+The `sed` command rewrites the container paths in `fuzz.cov` so that `go tool cover` can locate the source files in the local checkout.
+
+To produce a coverage report against a modified local source tree, mount the local checkout when building the coverage fuzzers, the same way you would for reproducers:
+
+```sh
+python3 infra/helper.py build_fuzzers --sanitizer coverage --mount_path /root/go/src/github.com/quic-go/quic-go quic-go
+```
+
+## Reproducing an OSS-Fuzz testcase
+
+Download the reproducer file from the OSS-Fuzz report. To test a local fix, rebuild the fuzzers with the modified quic-go checkout mounted at the path expected by `oss-fuzz.sh`:
+
+```sh
+export DOCKER_DEFAULT_PLATFORM=linux/amd64
+export FUZZ_TARGET=
+
+python3 infra/helper.py build_image --no-pull quic-go
+python3 infra/helper.py build_fuzzers --sanitizer address --mount_path /root/go/src/github.com/quic-go/quic-go quic-go
+python3 infra/helper.py reproduce quic-go "$FUZZ_TARGET"
+```
diff --git a/vendor/github.com/quic-go/quic-go/LICENSE b/vendor/github.com/quic-go/quic-go/LICENSE
new file mode 100644
index 00000000..51378bef
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016 the quic-go authors & Google, Inc.
+
+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/quic-go/quic-go/README.md b/vendor/github.com/quic-go/quic-go/README.md
new file mode 100644
index 00000000..3f36f424
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/README.md
@@ -0,0 +1,65 @@
+
+
+
+
+# A QUIC implementation in pure Go
+
+
+[](https://quic-go.net/docs/)
+[](https://pkg.go.dev/github.com/quic-go/quic-go)
+[](https://codecov.io/gh/quic-go/quic-go/)
+[](https://issues.oss-fuzz.com/issues?q=quic-go)
+
+quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go. It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)) and HTTP Datagrams ([RFC 9297](https://datatracker.ietf.org/doc/html/rfc9297)).
+
+In addition to these base RFCs, it also implements the following RFCs:
+
+* Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221))
+* Datagram Packetization Layer Path MTU Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899))
+* QUIC Version 2 ([RFC 9369](https://datatracker.ietf.org/doc/html/rfc9369))
+* QUIC Event Logging using qlog ([draft-ietf-quic-qlog-main-schema](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/) and [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/))
+* QUIC Stream Resets with Partial Delivery ([draft-ietf-quic-reliable-stream-reset](https://datatracker.ietf.org/doc/html/draft-ietf-quic-reliable-stream-reset-07))
+
+Support for WebTransport over HTTP/3 ([draft-ietf-webtrans-http3](https://datatracker.ietf.org/doc/draft-ietf-webtrans-http3/)) is implemented in [webtransport-go](https://github.com/quic-go/webtransport-go).
+
+Detailed documentation can be found on [quic-go.net](https://quic-go.net/docs/).
+
+## FIPS 140-3
+
+Starting with v0.60, quic-go supports use in FIPS 140-3 environments when built with Go 1.26 or newer, using Go standard library cryptography for the QUIC code paths relevant in FIPS mode; see [FIPS140.md](FIPS140.md) for details.
+
+## Projects using quic-go
+
+| Project | Description | Stars |
+| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
+| [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) | Free and open source, powerful network-wide ads & trackers blocking DNS server. |  |
+| [algernon](https://github.com/xyproto/algernon) | Small self-contained pure-Go web server with Lua, Markdown, HTTP/2, QUIC, Redis and PostgreSQL support |  |
+| [caddy](https://github.com/caddyserver/caddy/) | Fast, multi-platform web server with automatic HTTPS |  |
+| [cloudflared](https://github.com/cloudflare/cloudflared) | A tunneling daemon that proxies traffic from the Cloudflare network to your origins |  |
+| [frp](https://github.com/fatedier/frp) | A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet |  |
+| [go-libp2p](https://github.com/libp2p/go-libp2p) | libp2p implementation in Go, powering [Kubo](https://github.com/ipfs/kubo) (IPFS) and [Lotus](https://github.com/filecoin-project/lotus) (Filecoin), among others |  |
+| [gost](https://github.com/go-gost/gost) | A simple security tunnel written in Go |  |
+| [Hysteria](https://github.com/apernet/hysteria) | A powerful, lightning fast and censorship resistant proxy |  |
+| [Mercure](https://github.com/dunglas/mercure) | An open, easy, fast, reliable and battery-efficient solution for real-time communications |  |
+| [nodepass](https://github.com/NodePassProject/nodepass) | A secure, efficient TCP/UDP tunneling solution that delivers fast, reliable access across network restrictions using pre-established TCP/QUIC/WebSocket or HTTP/2 connections. |  |
+| [OONI Probe](https://github.com/ooni/probe-cli) | Next generation OONI Probe. Library and CLI tool. |  |
+| [reverst](https://github.com/flipt-io/reverst) | Reverse Tunnels in Go over HTTP/3 and QUIC |  |
+| [RoadRunner](https://github.com/roadrunner-server/roadrunner) | High-performance PHP application server, process manager written in Go and powered with plugins |  |
+| [syncthing](https://github.com/syncthing/syncthing/) | Open Source Continuous File Synchronization |  |
+| [traefik](https://github.com/traefik/traefik) | The Cloud Native Application Proxy |  |
+| [v2ray-core](https://github.com/v2fly/v2ray-core) | A platform for building proxies to bypass network restrictions |  |
+| [YoMo](https://github.com/yomorun/yomo) | Streaming Serverless Framework for Geo-distributed System |  |
+
+If you'd like to see your project added to this list, please send us a PR.
+
+## Release Policy
+
+quic-go always aims to support the latest two Go releases.
+
+## Contributing
+
+We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [help wanted](https://github.com/quic-go/quic-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). If you have any questions, please feel free to reach out by opening an issue or leaving a comment.
+
+## License
+
+The code is licensed under the MIT license. The logo and brand assets are excluded from the MIT license. See [assets/LICENSE.md](https://github.com/quic-go/quic-go/tree/master/assets/LICENSE.md) for the full usage policy and details.
diff --git a/vendor/github.com/quic-go/quic-go/SECURITY.md b/vendor/github.com/quic-go/quic-go/SECURITY.md
new file mode 100644
index 00000000..79fe1f56
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/SECURITY.md
@@ -0,0 +1,14 @@
+# Security Policy
+
+quic-go is an implementation of the QUIC protocol and related standards. No software is perfect, and we take reports of potential security issues very seriously.
+
+## Reporting a Vulnerability
+
+If you discover a vulnerability that could affect production deployments (e.g., a remotely exploitable issue), please report it [**privately**](https://github.com/quic-go/quic-go/security/advisories/new).
+Please **DO NOT file a public issue** for exploitable vulnerabilities.
+
+If the issue is theoretical, non-exploitable, or related to an experimental feature, you may discuss it openly by filing a regular issue.
+
+## Reporting a non-security bug
+
+For bugs, feature requests, or other non-security concerns, please open a GitHub [issue](https://github.com/quic-go/quic-go/issues/new).
diff --git a/vendor/github.com/quic-go/quic-go/buffer_pool.go b/vendor/github.com/quic-go/quic-go/buffer_pool.go
new file mode 100644
index 00000000..48589e12
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/buffer_pool.go
@@ -0,0 +1,92 @@
+package quic
+
+import (
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+type packetBuffer struct {
+ Data []byte
+
+ // refCount counts how many packets Data is used in.
+ // It doesn't support concurrent use.
+ // It is > 1 when used for coalesced packet.
+ refCount int
+}
+
+// Split increases the refCount.
+// It must be called when a packet buffer is used for more than one packet,
+// e.g. when splitting coalesced packets.
+func (b *packetBuffer) Split() {
+ b.refCount++
+}
+
+// Decrement decrements the reference counter.
+// It doesn't put the buffer back into the pool.
+func (b *packetBuffer) Decrement() {
+ b.refCount--
+ if b.refCount < 0 {
+ panic("negative packetBuffer refCount")
+ }
+}
+
+// MaybeRelease puts the packet buffer back into the pool,
+// if the reference counter already reached 0.
+func (b *packetBuffer) MaybeRelease() {
+ // only put the packetBuffer back if it's not used any more
+ if b.refCount == 0 {
+ b.putBack()
+ }
+}
+
+// Release puts back the packet buffer into the pool.
+// It should be called when processing is definitely finished.
+func (b *packetBuffer) Release() {
+ b.Decrement()
+ if b.refCount != 0 {
+ panic("packetBuffer refCount not zero")
+ }
+ b.putBack()
+}
+
+// Len returns the length of Data
+func (b *packetBuffer) Len() protocol.ByteCount { return protocol.ByteCount(len(b.Data)) }
+func (b *packetBuffer) Cap() protocol.ByteCount { return protocol.ByteCount(cap(b.Data)) }
+
+func (b *packetBuffer) putBack() {
+ if cap(b.Data) == protocol.MaxPacketBufferSize {
+ bufferPool.Put(b)
+ return
+ }
+ if cap(b.Data) == protocol.MaxLargePacketBufferSize {
+ largeBufferPool.Put(b)
+ return
+ }
+ panic("putPacketBuffer called with packet of wrong size!")
+}
+
+var bufferPool, largeBufferPool sync.Pool
+
+func getPacketBuffer() *packetBuffer {
+ buf := bufferPool.Get().(*packetBuffer)
+ buf.refCount = 1
+ buf.Data = buf.Data[:0]
+ return buf
+}
+
+func getLargePacketBuffer() *packetBuffer {
+ buf := largeBufferPool.Get().(*packetBuffer)
+ buf.refCount = 1
+ buf.Data = buf.Data[:0]
+ return buf
+}
+
+func init() {
+ bufferPool.New = func() any {
+ return &packetBuffer{Data: make([]byte, 0, protocol.MaxPacketBufferSize)}
+ }
+ largeBufferPool.New = func() any {
+ return &packetBuffer{Data: make([]byte, 0, protocol.MaxLargePacketBufferSize)}
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/client.go b/vendor/github.com/quic-go/quic-go/client.go
new file mode 100644
index 00000000..63132f2d
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/client.go
@@ -0,0 +1,109 @@
+package quic
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "net"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// make it possible to mock connection ID for initial generation in the tests
+var generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial
+
+// DialAddr establishes a new QUIC connection to a server.
+// It resolves the address, and then creates a new UDP connection to dial the QUIC server.
+// When the QUIC connection is closed, this UDP connection is closed.
+// See [Dial] for more details.
+func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (*Conn, error) {
+ udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
+ if err != nil {
+ return nil, err
+ }
+ udpAddr, err := net.ResolveUDPAddr("udp", addr)
+ if err != nil {
+ return nil, err
+ }
+ tr, err := setupTransport(udpConn, tlsConf, true)
+ if err != nil {
+ return nil, err
+ }
+ conn, err := tr.dial(ctx, udpAddr, addr, tlsConf, conf, false)
+ if err != nil {
+ tr.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// DialAddrEarly establishes a new 0-RTT QUIC connection to a server.
+// See [DialAddr] for more details.
+func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (*Conn, error) {
+ udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
+ if err != nil {
+ return nil, err
+ }
+ udpAddr, err := net.ResolveUDPAddr("udp", addr)
+ if err != nil {
+ return nil, err
+ }
+ tr, err := setupTransport(udpConn, tlsConf, true)
+ if err != nil {
+ return nil, err
+ }
+ conn, err := tr.dial(ctx, udpAddr, addr, tlsConf, conf, true)
+ if err != nil {
+ tr.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn.
+// See [Dial] for more details.
+func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) {
+ dl, err := setupTransport(c, tlsConf, false)
+ if err != nil {
+ return nil, err
+ }
+ conn, err := dl.DialEarly(ctx, addr, tlsConf, conf)
+ if err != nil {
+ dl.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// Dial establishes a new QUIC connection to a server using a net.PacketConn.
+// If the PacketConn satisfies the [OOBCapablePacketConn] interface (as a [net.UDPConn] does),
+// ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP
+// will be used instead of ReadFrom and WriteTo to read/write packets.
+// The [tls.Config] must define an application protocol (using tls.Config.NextProtos).
+//
+// This is a convenience function. More advanced use cases should instantiate a [Transport],
+// which offers configuration options for a more fine-grained control of the connection establishment,
+// including reusing the underlying UDP socket for multiple QUIC connections.
+func Dial(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) {
+ dl, err := setupTransport(c, tlsConf, false)
+ if err != nil {
+ return nil, err
+ }
+ conn, err := dl.Dial(ctx, addr, tlsConf, conf)
+ if err != nil {
+ dl.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+func setupTransport(c net.PacketConn, tlsConf *tls.Config, createdPacketConn bool) (*Transport, error) {
+ if tlsConf == nil {
+ return nil, errors.New("quic: tls.Config not set")
+ }
+ return &Transport{
+ Conn: c,
+ createdConn: createdPacketConn,
+ isSingleUse: true,
+ }, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/closed_conn.go b/vendor/github.com/quic-go/quic-go/closed_conn.go
new file mode 100644
index 00000000..6486ea65
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/closed_conn.go
@@ -0,0 +1,58 @@
+package quic
+
+import (
+ "math/bits"
+ "net"
+ "sync/atomic"
+
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+// A closedLocalConn is a connection that we closed locally.
+// When receiving packets for such a connection, we need to retransmit the packet containing the CONNECTION_CLOSE frame,
+// with an exponential backoff.
+type closedLocalConn struct {
+ counter atomic.Uint32
+ logger utils.Logger
+
+ sendPacket func(net.Addr, packetInfo)
+}
+
+var _ packetHandler = &closedLocalConn{}
+
+// newClosedLocalConn creates a new closedLocalConn and runs it.
+func newClosedLocalConn(sendPacket func(net.Addr, packetInfo), logger utils.Logger) packetHandler {
+ return &closedLocalConn{
+ sendPacket: sendPacket,
+ logger: logger,
+ }
+}
+
+func (c *closedLocalConn) handlePacket(p receivedPacket) {
+ n := c.counter.Add(1)
+ // exponential backoff
+ // only send a CONNECTION_CLOSE for the 1st, 2nd, 4th, 8th, 16th, ... packet arriving
+ if bits.OnesCount32(n) != 1 {
+ return
+ }
+ c.logger.Debugf("Received %d packets after sending CONNECTION_CLOSE. Retransmitting.", n)
+ c.sendPacket(p.remoteAddr, p.info)
+}
+
+func (c *closedLocalConn) destroy(error) {}
+func (c *closedLocalConn) closeWithTransportError(TransportErrorCode) {}
+
+// A closedRemoteConn is a connection that was closed remotely.
+// For such a connection, we might receive reordered packets that were sent before the CONNECTION_CLOSE.
+// We can just ignore those packets.
+type closedRemoteConn struct{}
+
+var _ packetHandler = &closedRemoteConn{}
+
+func newClosedRemoteConn() packetHandler {
+ return &closedRemoteConn{}
+}
+
+func (c *closedRemoteConn) handlePacket(receivedPacket) {}
+func (c *closedRemoteConn) destroy(error) {}
+func (c *closedRemoteConn) closeWithTransportError(TransportErrorCode) {}
diff --git a/vendor/github.com/quic-go/quic-go/codecov.yml b/vendor/github.com/quic-go/quic-go/codecov.yml
new file mode 100644
index 00000000..55d8a35e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/codecov.yml
@@ -0,0 +1,23 @@
+coverage:
+ round: nearest
+ ignore:
+ - http3/gzip_reader.go
+ - example/
+ - interop/
+ - internal/handshake/cipher_suite.go
+ - internal/mocks/
+ - internal/utils/linkedlist/linkedlist.go
+ - internal/testdata
+ - testutils/
+ - fuzzing/
+ - metrics/
+ status:
+ project:
+ default:
+ threshold: 0.5
+ patch: false
+flags:
+ clusterfuzz-lite-batch:
+ joined: false
+ clusterfuzz:
+ joined: false
diff --git a/vendor/github.com/quic-go/quic-go/config.go b/vendor/github.com/quic-go/quic-go/config.go
new file mode 100644
index 00000000..74c2054e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/config.go
@@ -0,0 +1,129 @@
+package quic
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// Clone clones a Config.
+func (c *Config) Clone() *Config {
+ copy := *c
+ return ©
+}
+
+func (c *Config) handshakeTimeout() time.Duration {
+ return 2 * c.HandshakeIdleTimeout
+}
+
+func (c *Config) maxRetryTokenAge() time.Duration {
+ return c.handshakeTimeout()
+}
+
+func validateConfig(config *Config) error {
+ if config == nil {
+ return nil
+ }
+ const maxStreams = 1 << 60
+ if config.MaxIncomingStreams > maxStreams {
+ config.MaxIncomingStreams = maxStreams
+ }
+ if config.MaxIncomingUniStreams > maxStreams {
+ config.MaxIncomingUniStreams = maxStreams
+ }
+ if config.MaxStreamReceiveWindow > quicvarint.Max {
+ config.MaxStreamReceiveWindow = quicvarint.Max
+ }
+ if config.MaxConnectionReceiveWindow > quicvarint.Max {
+ config.MaxConnectionReceiveWindow = quicvarint.Max
+ }
+ if config.InitialPacketSize > 0 && config.InitialPacketSize < protocol.MinInitialPacketSize {
+ config.InitialPacketSize = protocol.MinInitialPacketSize
+ }
+ if config.InitialPacketSize > protocol.MaxPacketBufferSize {
+ config.InitialPacketSize = protocol.MaxPacketBufferSize
+ }
+ // check that all QUIC versions are actually supported
+ for _, v := range config.Versions {
+ if !protocol.IsValidVersion(v) {
+ return fmt.Errorf("invalid QUIC version: %s", v)
+ }
+ }
+ return nil
+}
+
+// populateConfig populates fields in the quic.Config with their default values, if none are set
+// it may be called with nil
+func populateConfig(config *Config) *Config {
+ if config == nil {
+ config = &Config{}
+ }
+ versions := config.Versions
+ if len(versions) == 0 {
+ versions = protocol.SupportedVersions
+ }
+ handshakeIdleTimeout := protocol.DefaultHandshakeIdleTimeout
+ if config.HandshakeIdleTimeout != 0 {
+ handshakeIdleTimeout = config.HandshakeIdleTimeout
+ }
+ idleTimeout := protocol.DefaultIdleTimeout
+ if config.MaxIdleTimeout != 0 {
+ idleTimeout = config.MaxIdleTimeout
+ }
+ initialStreamReceiveWindow := config.InitialStreamReceiveWindow
+ if initialStreamReceiveWindow == 0 {
+ initialStreamReceiveWindow = protocol.DefaultInitialMaxStreamData
+ }
+ maxStreamReceiveWindow := config.MaxStreamReceiveWindow
+ if maxStreamReceiveWindow == 0 {
+ maxStreamReceiveWindow = protocol.DefaultMaxReceiveStreamFlowControlWindow
+ }
+ initialConnectionReceiveWindow := config.InitialConnectionReceiveWindow
+ if initialConnectionReceiveWindow == 0 {
+ initialConnectionReceiveWindow = protocol.DefaultInitialMaxData
+ }
+ maxConnectionReceiveWindow := config.MaxConnectionReceiveWindow
+ if maxConnectionReceiveWindow == 0 {
+ maxConnectionReceiveWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindow
+ }
+ maxIncomingStreams := config.MaxIncomingStreams
+ if maxIncomingStreams == 0 {
+ maxIncomingStreams = protocol.DefaultMaxIncomingStreams
+ } else if maxIncomingStreams < 0 {
+ maxIncomingStreams = 0
+ }
+ maxIncomingUniStreams := config.MaxIncomingUniStreams
+ if maxIncomingUniStreams == 0 {
+ maxIncomingUniStreams = protocol.DefaultMaxIncomingUniStreams
+ } else if maxIncomingUniStreams < 0 {
+ maxIncomingUniStreams = 0
+ }
+ initialPacketSize := config.InitialPacketSize
+ if initialPacketSize == 0 {
+ initialPacketSize = protocol.InitialPacketSize
+ }
+
+ return &Config{
+ GetConfigForClient: config.GetConfigForClient,
+ Versions: versions,
+ HandshakeIdleTimeout: handshakeIdleTimeout,
+ MaxIdleTimeout: idleTimeout,
+ KeepAlivePeriod: config.KeepAlivePeriod,
+ InitialStreamReceiveWindow: initialStreamReceiveWindow,
+ MaxStreamReceiveWindow: maxStreamReceiveWindow,
+ InitialConnectionReceiveWindow: initialConnectionReceiveWindow,
+ MaxConnectionReceiveWindow: maxConnectionReceiveWindow,
+ AllowConnectionWindowIncrease: config.AllowConnectionWindowIncrease,
+ MaxIncomingStreams: maxIncomingStreams,
+ MaxIncomingUniStreams: maxIncomingUniStreams,
+ TokenStore: config.TokenStore,
+ EnableDatagrams: config.EnableDatagrams,
+ InitialPacketSize: initialPacketSize,
+ DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
+ EnableStreamResetPartialDelivery: config.EnableStreamResetPartialDelivery,
+ Allow0RTT: config.Allow0RTT,
+ Tracer: config.Tracer,
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/conn_id_generator.go b/vendor/github.com/quic-go/quic-go/conn_id_generator.go
new file mode 100644
index 00000000..133932a6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/conn_id_generator.go
@@ -0,0 +1,212 @@
+package quic
+
+import (
+ "fmt"
+ "slices"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type connRunnerCallbacks struct {
+ AddConnectionID func(protocol.ConnectionID)
+ RemoveConnectionID func(protocol.ConnectionID)
+ ReplaceWithClosed func([]protocol.ConnectionID, []byte, time.Duration)
+}
+
+// The memory address of the Transport is used as the key.
+type connRunners map[connRunner]connRunnerCallbacks
+
+func (cr connRunners) AddConnectionID(id protocol.ConnectionID) {
+ for _, c := range cr {
+ c.AddConnectionID(id)
+ }
+}
+
+func (cr connRunners) RemoveConnectionID(id protocol.ConnectionID) {
+ for _, c := range cr {
+ c.RemoveConnectionID(id)
+ }
+}
+
+func (cr connRunners) ReplaceWithClosed(ids []protocol.ConnectionID, b []byte, expiry time.Duration) {
+ for _, c := range cr {
+ c.ReplaceWithClosed(ids, b, expiry)
+ }
+}
+
+type connIDToRetire struct {
+ t monotime.Time
+ connID protocol.ConnectionID
+}
+
+type connIDGenerator struct {
+ generator ConnectionIDGenerator
+ highestSeq uint64
+ connRunners connRunners
+
+ activeSrcConnIDs map[uint64]protocol.ConnectionID
+ connIDsToRetire []connIDToRetire // sorted by t
+ initialClientDestConnID *protocol.ConnectionID // nil for the client
+
+ statelessResetter *statelessResetter
+
+ queueControlFrame func(wire.Frame)
+}
+
+func newConnIDGenerator(
+ runner connRunner,
+ initialConnectionID protocol.ConnectionID,
+ initialClientDestConnID *protocol.ConnectionID, // nil for the client
+ statelessResetter *statelessResetter,
+ callbacks connRunnerCallbacks,
+ queueControlFrame func(wire.Frame),
+ generator ConnectionIDGenerator,
+) *connIDGenerator {
+ m := &connIDGenerator{
+ generator: generator,
+ activeSrcConnIDs: make(map[uint64]protocol.ConnectionID),
+ statelessResetter: statelessResetter,
+ connRunners: map[connRunner]connRunnerCallbacks{runner: callbacks},
+ queueControlFrame: queueControlFrame,
+ }
+ m.activeSrcConnIDs[0] = initialConnectionID
+ m.initialClientDestConnID = initialClientDestConnID
+ return m
+}
+
+func (m *connIDGenerator) SetMaxActiveConnIDs(limit uint64) error {
+ if m.generator.ConnectionIDLen() == 0 {
+ return nil
+ }
+ // The active_connection_id_limit transport parameter is the number of
+ // connection IDs the peer will store. This limit includes the connection ID
+ // used during the handshake, and the one sent in the preferred_address
+ // transport parameter.
+ // We currently don't send the preferred_address transport parameter,
+ // so we can issue (limit - 1) connection IDs.
+ for i := uint64(len(m.activeSrcConnIDs)); i < min(limit, protocol.MaxIssuedConnectionIDs); i++ {
+ if err := m.issueNewConnID(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (m *connIDGenerator) Retire(seq uint64, sentWithDestConnID protocol.ConnectionID, expiry monotime.Time) error {
+ if seq > m.highestSeq {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: fmt.Sprintf("retired connection ID %d (highest issued: %d)", seq, m.highestSeq),
+ }
+ }
+ connID, ok := m.activeSrcConnIDs[seq]
+ // We might already have deleted this connection ID, if this is a duplicate frame.
+ if !ok {
+ return nil
+ }
+ if connID == sentWithDestConnID {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: fmt.Sprintf("retired connection ID %d (%s), which was used as the Destination Connection ID on this packet", seq, connID),
+ }
+ }
+ m.queueConnIDForRetiring(connID, expiry)
+
+ delete(m.activeSrcConnIDs, seq)
+ // Don't issue a replacement for the initial connection ID.
+ if seq == 0 {
+ return nil
+ }
+ return m.issueNewConnID()
+}
+
+func (m *connIDGenerator) queueConnIDForRetiring(connID protocol.ConnectionID, expiry monotime.Time) {
+ idx := slices.IndexFunc(m.connIDsToRetire, func(c connIDToRetire) bool {
+ return c.t.After(expiry)
+ })
+ if idx == -1 {
+ idx = len(m.connIDsToRetire)
+ }
+ m.connIDsToRetire = slices.Insert(m.connIDsToRetire, idx, connIDToRetire{t: expiry, connID: connID})
+}
+
+func (m *connIDGenerator) issueNewConnID() error {
+ connID, err := m.generator.GenerateConnectionID()
+ if err != nil {
+ return err
+ }
+ m.activeSrcConnIDs[m.highestSeq+1] = connID
+ m.connRunners.AddConnectionID(connID)
+ m.queueControlFrame(&wire.NewConnectionIDFrame{
+ SequenceNumber: m.highestSeq + 1,
+ ConnectionID: connID,
+ StatelessResetToken: m.statelessResetter.GetStatelessResetToken(connID),
+ })
+ m.highestSeq++
+ return nil
+}
+
+func (m *connIDGenerator) SetHandshakeComplete(connIDExpiry monotime.Time) {
+ if m.initialClientDestConnID != nil {
+ m.queueConnIDForRetiring(*m.initialClientDestConnID, connIDExpiry)
+ m.initialClientDestConnID = nil
+ }
+}
+
+func (m *connIDGenerator) RemoveRetiredConnIDs(now monotime.Time) {
+ if len(m.connIDsToRetire) == 0 {
+ return
+ }
+ for _, c := range m.connIDsToRetire {
+ if c.t.After(now) {
+ break
+ }
+ m.connRunners.RemoveConnectionID(c.connID)
+ m.connIDsToRetire = m.connIDsToRetire[1:]
+ }
+}
+
+func (m *connIDGenerator) RemoveAll() {
+ if m.initialClientDestConnID != nil {
+ m.connRunners.RemoveConnectionID(*m.initialClientDestConnID)
+ }
+ for _, connID := range m.activeSrcConnIDs {
+ m.connRunners.RemoveConnectionID(connID)
+ }
+ for _, c := range m.connIDsToRetire {
+ m.connRunners.RemoveConnectionID(c.connID)
+ }
+}
+
+func (m *connIDGenerator) ReplaceWithClosed(connClose []byte, expiry time.Duration) {
+ connIDs := make([]protocol.ConnectionID, 0, len(m.activeSrcConnIDs)+len(m.connIDsToRetire)+1)
+ if m.initialClientDestConnID != nil {
+ connIDs = append(connIDs, *m.initialClientDestConnID)
+ }
+ for _, connID := range m.activeSrcConnIDs {
+ connIDs = append(connIDs, connID)
+ }
+ for _, c := range m.connIDsToRetire {
+ connIDs = append(connIDs, c.connID)
+ }
+ m.connRunners.ReplaceWithClosed(connIDs, connClose, expiry)
+}
+
+func (m *connIDGenerator) AddConnRunner(runner connRunner, r connRunnerCallbacks) {
+ // The transport might have already been added earlier.
+ // This happens if the application migrates back to and old path.
+ if _, ok := m.connRunners[runner]; ok {
+ return
+ }
+ m.connRunners[runner] = r
+ if m.initialClientDestConnID != nil {
+ r.AddConnectionID(*m.initialClientDestConnID)
+ }
+ for _, connID := range m.activeSrcConnIDs {
+ r.AddConnectionID(connID)
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/conn_id_manager.go b/vendor/github.com/quic-go/quic-go/conn_id_manager.go
new file mode 100644
index 00000000..5513b645
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/conn_id_manager.go
@@ -0,0 +1,321 @@
+package quic
+
+import (
+ "fmt"
+ "slices"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type newConnID struct {
+ SequenceNumber uint64
+ ConnectionID protocol.ConnectionID
+ StatelessResetToken protocol.StatelessResetToken
+}
+
+type connIDManager struct {
+ queue []newConnID
+
+ highestProbingID uint64
+ pathProbing map[pathID]newConnID // initialized lazily
+
+ handshakeComplete bool
+ activeSequenceNumber uint64
+ highestRetired uint64
+ activeConnectionID protocol.ConnectionID
+ activeStatelessResetToken *protocol.StatelessResetToken
+
+ // We change the connection ID after sending on average
+ // protocol.PacketsPerConnectionID packets. The actual value is randomized
+ // hide the packet loss rate from on-path observers.
+ rand utils.Rand
+ packetsSinceLastChange uint32
+ packetsPerConnectionID uint32
+
+ addStatelessResetToken func(protocol.StatelessResetToken)
+ removeStatelessResetToken func(protocol.StatelessResetToken)
+ queueControlFrame func(wire.Frame)
+
+ closed bool
+}
+
+func newConnIDManager(
+ initialDestConnID protocol.ConnectionID,
+ addStatelessResetToken func(protocol.StatelessResetToken),
+ removeStatelessResetToken func(protocol.StatelessResetToken),
+ queueControlFrame func(wire.Frame),
+) *connIDManager {
+ return &connIDManager{
+ activeConnectionID: initialDestConnID,
+ addStatelessResetToken: addStatelessResetToken,
+ removeStatelessResetToken: removeStatelessResetToken,
+ queueControlFrame: queueControlFrame,
+ queue: make([]newConnID, 0, protocol.MaxActiveConnectionIDs),
+ }
+}
+
+func (h *connIDManager) AddFromPreferredAddress(connID protocol.ConnectionID, resetToken protocol.StatelessResetToken) error {
+ return h.addConnectionID(1, connID, resetToken)
+}
+
+func (h *connIDManager) Add(f *wire.NewConnectionIDFrame) error {
+ if err := h.add(f); err != nil {
+ return err
+ }
+ if len(h.queue) >= protocol.MaxActiveConnectionIDs {
+ return &qerr.TransportError{ErrorCode: qerr.ConnectionIDLimitError}
+ }
+ return nil
+}
+
+func (h *connIDManager) add(f *wire.NewConnectionIDFrame) error {
+ if h.activeConnectionID.Len() == 0 {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "received NEW_CONNECTION_ID frame but zero-length connection IDs are in use",
+ }
+ }
+ // If the NEW_CONNECTION_ID frame is reordered, such that its sequence number is smaller than the currently active
+ // connection ID or if it was already retired, send the RETIRE_CONNECTION_ID frame immediately.
+ if f.SequenceNumber < max(h.activeSequenceNumber, h.highestProbingID) || f.SequenceNumber < h.highestRetired {
+ h.queueControlFrame(&wire.RetireConnectionIDFrame{
+ SequenceNumber: f.SequenceNumber,
+ })
+ return nil
+ }
+
+ if f.RetirePriorTo != 0 && h.pathProbing != nil {
+ for id, entry := range h.pathProbing {
+ if entry.SequenceNumber < f.RetirePriorTo {
+ h.queueControlFrame(&wire.RetireConnectionIDFrame{
+ SequenceNumber: entry.SequenceNumber,
+ })
+ h.removeStatelessResetToken(entry.StatelessResetToken)
+ delete(h.pathProbing, id)
+ }
+ }
+ }
+ // Retire elements in the queue.
+ // Doesn't retire the active connection ID.
+ if f.RetirePriorTo > h.highestRetired {
+ var newQueue []newConnID
+ for _, entry := range h.queue {
+ if entry.SequenceNumber >= f.RetirePriorTo {
+ newQueue = append(newQueue, entry)
+ } else {
+ h.queueControlFrame(&wire.RetireConnectionIDFrame{SequenceNumber: entry.SequenceNumber})
+ }
+ }
+ h.queue = newQueue
+ h.highestRetired = f.RetirePriorTo
+ }
+
+ if f.SequenceNumber == h.activeSequenceNumber {
+ return nil
+ }
+
+ if err := h.addConnectionID(f.SequenceNumber, f.ConnectionID, f.StatelessResetToken); err != nil {
+ return err
+ }
+
+ // Retire the active connection ID, if necessary.
+ if h.activeSequenceNumber < f.RetirePriorTo {
+ // The queue is guaranteed to have at least one element at this point.
+ h.updateConnectionID()
+ }
+ return nil
+}
+
+func (h *connIDManager) addConnectionID(seq uint64, connID protocol.ConnectionID, resetToken protocol.StatelessResetToken) error {
+ // fast path: add to the end of the queue
+ if len(h.queue) == 0 || h.queue[len(h.queue)-1].SequenceNumber < seq {
+ h.queue = append(h.queue, newConnID{
+ SequenceNumber: seq,
+ ConnectionID: connID,
+ StatelessResetToken: resetToken,
+ })
+ return nil
+ }
+
+ // slow path: insert in the middle
+ for i, entry := range h.queue {
+ if entry.SequenceNumber == seq {
+ if entry.ConnectionID != connID {
+ return fmt.Errorf("received conflicting connection IDs for sequence number %d", seq)
+ }
+ if entry.StatelessResetToken != resetToken {
+ return fmt.Errorf("received conflicting stateless reset tokens for sequence number %d", seq)
+ }
+ return nil
+ }
+
+ // insert at the correct position to maintain sorted order
+ if entry.SequenceNumber > seq {
+ h.queue = slices.Insert(h.queue, i, newConnID{
+ SequenceNumber: seq,
+ ConnectionID: connID,
+ StatelessResetToken: resetToken,
+ })
+ return nil
+ }
+ }
+ return nil // unreachable
+}
+
+func (h *connIDManager) updateConnectionID() {
+ h.assertNotClosed()
+ h.queueControlFrame(&wire.RetireConnectionIDFrame{
+ SequenceNumber: h.activeSequenceNumber,
+ })
+ h.highestRetired = max(h.highestRetired, h.activeSequenceNumber)
+ if h.activeStatelessResetToken != nil {
+ h.removeStatelessResetToken(*h.activeStatelessResetToken)
+ }
+
+ front := h.queue[0]
+ h.queue = h.queue[1:]
+ h.activeSequenceNumber = front.SequenceNumber
+ h.activeConnectionID = front.ConnectionID
+ h.activeStatelessResetToken = &front.StatelessResetToken
+ h.packetsSinceLastChange = 0
+ h.packetsPerConnectionID = protocol.PacketsPerConnectionID/2 + uint32(h.rand.Int31n(protocol.PacketsPerConnectionID))
+ h.addStatelessResetToken(*h.activeStatelessResetToken)
+}
+
+func (h *connIDManager) Close() {
+ h.closed = true
+ if h.activeStatelessResetToken != nil {
+ h.removeStatelessResetToken(*h.activeStatelessResetToken)
+ }
+ if h.pathProbing != nil {
+ for _, entry := range h.pathProbing {
+ h.removeStatelessResetToken(entry.StatelessResetToken)
+ }
+ }
+}
+
+// is called when the server performs a Retry
+// and when the server changes the connection ID in the first Initial sent
+func (h *connIDManager) ChangeInitialConnID(newConnID protocol.ConnectionID) {
+ if h.activeSequenceNumber != 0 {
+ panic("expected first connection ID to have sequence number 0")
+ }
+ h.activeConnectionID = newConnID
+}
+
+// is called when the server provides a stateless reset token in the transport parameters
+func (h *connIDManager) SetStatelessResetToken(token protocol.StatelessResetToken) {
+ h.assertNotClosed()
+ if h.activeSequenceNumber != 0 {
+ panic("expected first connection ID to have sequence number 0")
+ }
+ h.activeStatelessResetToken = &token
+ h.addStatelessResetToken(token)
+}
+
+func (h *connIDManager) SentPacket() {
+ h.packetsSinceLastChange++
+}
+
+func (h *connIDManager) shouldUpdateConnID() bool {
+ if !h.handshakeComplete {
+ return false
+ }
+ // initiate the first change as early as possible (after handshake completion)
+ if len(h.queue) > 0 && h.activeSequenceNumber == 0 {
+ return true
+ }
+ // For later changes, only change if
+ // 1. The queue of connection IDs is filled more than 50%.
+ // 2. We sent at least PacketsPerConnectionID packets
+ return 2*len(h.queue) >= protocol.MaxActiveConnectionIDs &&
+ h.packetsSinceLastChange >= h.packetsPerConnectionID
+}
+
+func (h *connIDManager) Get() protocol.ConnectionID {
+ h.assertNotClosed()
+ if h.shouldUpdateConnID() {
+ h.updateConnectionID()
+ }
+ return h.activeConnectionID
+}
+
+func (h *connIDManager) SetHandshakeComplete() {
+ h.handshakeComplete = true
+}
+
+// GetConnIDForPath retrieves a connection ID for a new path (i.e. not the active one).
+// Once a connection ID is allocated for a path, it cannot be used for a different path.
+// When called with the same pathID, it will return the same connection ID,
+// unless the peer requested that this connection ID be retired.
+func (h *connIDManager) GetConnIDForPath(id pathID) (protocol.ConnectionID, bool) {
+ h.assertNotClosed()
+ // if we're using zero-length connection IDs, we don't need to change the connection ID
+ if h.activeConnectionID.Len() == 0 {
+ return protocol.ConnectionID{}, true
+ }
+
+ if h.pathProbing == nil {
+ h.pathProbing = make(map[pathID]newConnID)
+ }
+ entry, ok := h.pathProbing[id]
+ if ok {
+ return entry.ConnectionID, true
+ }
+ if len(h.queue) == 0 {
+ return protocol.ConnectionID{}, false
+ }
+ front := h.queue[0]
+ h.queue = h.queue[1:]
+ h.pathProbing[id] = front
+ h.highestProbingID = front.SequenceNumber
+ h.addStatelessResetToken(front.StatelessResetToken)
+ return front.ConnectionID, true
+}
+
+func (h *connIDManager) RetireConnIDForPath(pathID pathID) {
+ h.assertNotClosed()
+ // if we're using zero-length connection IDs, we don't need to change the connection ID
+ if h.activeConnectionID.Len() == 0 {
+ return
+ }
+
+ entry, ok := h.pathProbing[pathID]
+ if !ok {
+ return
+ }
+ h.queueControlFrame(&wire.RetireConnectionIDFrame{
+ SequenceNumber: entry.SequenceNumber,
+ })
+ h.removeStatelessResetToken(entry.StatelessResetToken)
+ delete(h.pathProbing, pathID)
+}
+
+func (h *connIDManager) IsActiveStatelessResetToken(token protocol.StatelessResetToken) bool {
+ if h.activeStatelessResetToken != nil {
+ if *h.activeStatelessResetToken == token {
+ return true
+ }
+ }
+ if h.pathProbing != nil {
+ for _, entry := range h.pathProbing {
+ if entry.StatelessResetToken == token {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// Using the connIDManager after it has been closed can have disastrous effects:
+// If the connection ID is rotated, a new entry would be inserted into the packet handler map,
+// leading to a memory leak of the connection struct.
+// See https://github.com/quic-go/quic-go/pull/4852 for more details.
+func (h *connIDManager) assertNotClosed() {
+ if h.closed {
+ panic("connection ID manager is closed")
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/connection.go b/vendor/github.com/quic-go/quic-go/connection.go
new file mode 100644
index 00000000..d1569388
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/connection.go
@@ -0,0 +1,3149 @@
+package quic
+
+import (
+ "bytes"
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "reflect"
+ "slices"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/flowcontrol"
+ "github.com/quic-go/quic-go/internal/handshake"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/utils/ringbuffer"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+type unpacker interface {
+ UnpackLongHeader(hdr *wire.Header, data []byte) (*unpackedPacket, error)
+ UnpackShortHeader(rcvTime monotime.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error)
+}
+
+type cryptoStreamHandler interface {
+ StartHandshake(context.Context) error
+ ChangeConnectionID(protocol.ConnectionID)
+ SetLargest1RTTAcked(protocol.PacketNumber) error
+ SetHandshakeConfirmed()
+ GetSessionTicket() ([]byte, error)
+ NextEvent() handshake.Event
+ DiscardInitialKeys()
+ HandleMessage([]byte, protocol.EncryptionLevel) error
+ io.Closer
+ ConnectionState() handshake.ConnectionState
+}
+
+type receivedPacket struct {
+ buffer *packetBuffer
+
+ remoteAddr net.Addr
+ rcvTime monotime.Time
+ data []byte
+
+ ecn protocol.ECN
+
+ info packetInfo // only valid if the contained IP address is valid
+}
+
+type receivedPacketWithDatagramID struct {
+ receivedPacket
+ datagramID qlog.DatagramID
+}
+
+func (p *receivedPacket) Size() protocol.ByteCount { return protocol.ByteCount(len(p.data)) }
+
+func (p *receivedPacket) Clone() *receivedPacket {
+ return &receivedPacket{
+ remoteAddr: p.remoteAddr,
+ rcvTime: p.rcvTime,
+ data: p.data,
+ buffer: p.buffer,
+ ecn: p.ecn,
+ info: p.info,
+ }
+}
+
+type connRunner interface {
+ Add(protocol.ConnectionID, packetHandler) bool
+ Remove(protocol.ConnectionID)
+ ReplaceWithClosed([]protocol.ConnectionID, []byte, time.Duration)
+ AddResetToken(protocol.StatelessResetToken, packetHandler)
+ RemoveResetToken(protocol.StatelessResetToken)
+}
+
+type closeError struct {
+ err error
+ immediate bool
+}
+
+type errCloseForRecreating struct {
+ nextPacketNumber protocol.PacketNumber
+ nextVersion protocol.Version
+}
+
+func (e *errCloseForRecreating) Error() string {
+ return "closing connection in order to recreate it"
+}
+
+var deadlineSendImmediately = monotime.Time(42 * time.Millisecond) // any value > time.Time{} and before time.Now() is fine
+
+type blockMode uint8
+
+const (
+ // blockModeNone means that the connection is not blocked.
+ blockModeNone blockMode = iota
+ // blockModeCongestionLimited means that the connection is congestion limited.
+ // In that case, we can still send acknowledgments and PTO probe packets.
+ blockModeCongestionLimited
+ // blockModeHardBlocked means that no packet can be sent, under no circumstances. This can happen when:
+ // * the send queue is full
+ // * the SentPacketHandler returns SendNone, e.g. when we are tracking the maximum number of packets
+ // In that case, the timer will be set to the idle timeout.
+ blockModeHardBlocked
+)
+
+// A Conn is a QUIC connection between two peers.
+// Calls to the connection (and to streams) can return the following types of errors:
+// - [ApplicationError]: for errors triggered by the application running on top of QUIC
+// - [TransportError]: for errors triggered by the QUIC transport (in many cases a misbehaving peer)
+// - [IdleTimeoutError]: when the peer goes away unexpectedly (this is a [net.Error] timeout error)
+// - [HandshakeTimeoutError]: when the cryptographic handshake takes too long (this is a [net.Error] timeout error)
+// - [StatelessResetError]: when we receive a stateless reset
+// - [VersionNegotiationError]: returned by the client, when there's no version overlap between the peers
+type Conn struct {
+ // Destination connection ID used during the handshake.
+ // Used to check source connection ID on incoming packets.
+ handshakeDestConnID protocol.ConnectionID
+ // Set for the client. Destination connection ID used on the first Initial sent.
+ origDestConnID protocol.ConnectionID
+ retrySrcConnID *protocol.ConnectionID // only set for the client (and if a Retry was performed)
+
+ srcConnIDLen int
+
+ perspective protocol.Perspective
+ version protocol.Version
+ config *Config
+
+ conn sendConn
+ sendQueue sender
+
+ // lazily initialzed: most connections never migrate
+ pathManager *pathManager
+ largestRcvdAppData protocol.PacketNumber
+ pathManagerOutgoing atomic.Pointer[pathManagerOutgoing]
+
+ streamsMap *streamsMap
+ connIDManager *connIDManager
+ connIDGenerator *connIDGenerator
+
+ rttStats *utils.RTTStats
+ connStats utils.ConnectionStats
+
+ cryptoStreamManager *cryptoStreamManager
+ sentPacketHandler ackhandler.SentPacketHandler
+ receivedPacketHandler ackhandler.ReceivedPacketHandler
+ retransmissionQueue *retransmissionQueue
+ framer *framer
+ connFlowController flowcontrol.ConnectionFlowController
+ tokenStoreKey string // only set for the client
+ tokenGenerator *handshake.TokenGenerator // only set for the server
+
+ unpacker unpacker
+ frameParser wire.FrameParser
+ packer packer
+ mtuDiscoverer mtuDiscoverer // initialized when the transport parameters are received
+
+ maxPayloadSizeEstimate atomic.Uint32
+
+ initialStream *initialCryptoStream
+ handshakeStream *cryptoStream
+ oneRTTStream *cryptoStream // only set for the server
+ cryptoStreamHandler cryptoStreamHandler
+
+ notifyReceivedPacket chan struct{}
+ sendingScheduled chan struct{}
+ receivedPacketMx sync.Mutex
+ receivedPackets ringbuffer.RingBuffer[receivedPacket]
+
+ // closeChan is used to notify the run loop that it should terminate
+ closeChan chan struct{}
+ closeErr atomic.Pointer[closeError]
+
+ ctx context.Context
+ ctxCancel context.CancelCauseFunc
+ handshakeCompleteChan chan struct{}
+
+ undecryptablePackets []receivedPacketWithDatagramID // undecryptable packets, waiting for a change in encryption level
+ undecryptablePacketsToProcess []receivedPacketWithDatagramID
+
+ earlyConnReadyChan chan struct{}
+ sentFirstPacket bool
+ droppedInitialKeys bool
+ handshakeComplete bool
+ handshakeConfirmed bool
+
+ receivedRetry bool
+ versionNegotiated bool
+ receivedFirstPacket bool
+
+ blocked blockMode
+
+ // the minimum of the max_idle_timeout values advertised by both endpoints
+ idleTimeout time.Duration
+ creationTime monotime.Time
+ // The idle timeout is set based on the max of the time we received the last packet...
+ lastPacketReceivedTime monotime.Time
+ // ... and the time we sent a new ack-eliciting packet after receiving a packet.
+ firstAckElicitingPacketAfterIdleSentTime monotime.Time
+ // pacingDeadline is the time when the next packet should be sent
+ pacingDeadline monotime.Time
+
+ peerParams *wire.TransportParameters
+
+ timer *time.Timer
+ // keepAlivePingSent stores whether a keep alive PING is in flight.
+ // It is reset as soon as we receive a packet from the peer.
+ keepAlivePingSent bool
+ keepAliveInterval time.Duration
+
+ datagramQueue *datagramQueue
+
+ connStateMutex sync.Mutex
+ connState ConnectionState
+
+ logID string
+ qlogTrace qlogwriter.Trace
+ qlogger qlogwriter.Recorder
+ logger utils.Logger
+}
+
+var _ streamSender = &Conn{}
+
+type connTestHooks struct {
+ run func() error
+ earlyConnReady func() <-chan struct{}
+ context func() context.Context
+ handshakeComplete func() <-chan struct{}
+ closeWithTransportError func(TransportErrorCode)
+ destroy func(error)
+ handlePacket func(receivedPacket)
+}
+
+type wrappedConn struct {
+ testHooks *connTestHooks
+ *Conn
+}
+
+var newConnection = func(
+ ctx context.Context,
+ ctxCancel context.CancelCauseFunc,
+ conn sendConn,
+ runner connRunner,
+ origDestConnID protocol.ConnectionID,
+ retrySrcConnID *protocol.ConnectionID,
+ clientDestConnID protocol.ConnectionID,
+ destConnID protocol.ConnectionID,
+ srcConnID protocol.ConnectionID,
+ connIDGenerator ConnectionIDGenerator,
+ statelessResetter *statelessResetter,
+ conf *Config,
+ tlsConf *tls.Config,
+ tokenGenerator *handshake.TokenGenerator,
+ clientAddressValidated bool,
+ rtt time.Duration,
+ qlogTrace qlogwriter.Trace,
+ logger utils.Logger,
+ v protocol.Version,
+) *wrappedConn {
+ s := &Conn{
+ ctx: ctx,
+ ctxCancel: ctxCancel,
+ conn: conn,
+ config: conf,
+ handshakeDestConnID: destConnID,
+ srcConnIDLen: srcConnID.Len(),
+ tokenGenerator: tokenGenerator,
+ oneRTTStream: newCryptoStream(),
+ perspective: protocol.PerspectiveServer,
+ qlogTrace: qlogTrace,
+ logger: logger,
+ version: v,
+ }
+ if qlogTrace != nil {
+ s.qlogger = qlogTrace.AddProducer()
+ }
+ if origDestConnID.Len() > 0 {
+ s.logID = origDestConnID.String()
+ } else {
+ s.logID = destConnID.String()
+ }
+ s.connIDManager = newConnIDManager(
+ destConnID,
+ func(token protocol.StatelessResetToken) { runner.AddResetToken(token, s) },
+ runner.RemoveResetToken,
+ s.queueControlFrame,
+ )
+ s.connIDGenerator = newConnIDGenerator(
+ runner,
+ srcConnID,
+ &clientDestConnID,
+ statelessResetter,
+ connRunnerCallbacks{
+ AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, s) },
+ RemoveConnectionID: runner.Remove,
+ ReplaceWithClosed: runner.ReplaceWithClosed,
+ },
+ s.queueControlFrame,
+ connIDGenerator,
+ )
+ s.preSetup()
+ s.rttStats.SetInitialRTT(rtt)
+ s.sentPacketHandler = ackhandler.NewSentPacketHandler(
+ 0,
+ protocol.ByteCount(s.config.InitialPacketSize),
+ s.rttStats,
+ &s.connStats,
+ clientAddressValidated,
+ s.conn.capabilities().ECN,
+ s.receivedPacketHandler.IgnorePacketsBelow,
+ s.perspective,
+ s.qlogger,
+ s.logger,
+ )
+ s.maxPayloadSizeEstimate.Store(uint32(estimateMaxPayloadSize(protocol.ByteCount(s.config.InitialPacketSize))))
+ statelessResetToken := statelessResetter.GetStatelessResetToken(srcConnID)
+ params := &wire.TransportParameters{
+ InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
+ InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
+ InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
+ InitialMaxData: protocol.ByteCount(s.config.InitialConnectionReceiveWindow),
+ MaxIdleTimeout: s.config.MaxIdleTimeout,
+ MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams),
+ MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams),
+ MaxAckDelay: protocol.MaxAckDelayInclGranularity,
+ AckDelayExponent: protocol.AckDelayExponent,
+ MaxUDPPayloadSize: protocol.MaxPacketBufferSize,
+ StatelessResetToken: &statelessResetToken,
+ OriginalDestinationConnectionID: origDestConnID,
+ // For interoperability with quic-go versions before May 2023, this value must be set to a value
+ // different from protocol.DefaultActiveConnectionIDLimit.
+ // If set to the default value, it will be omitted from the transport parameters, which will make
+ // old quic-go versions interpret it as 0, instead of the default value of 2.
+ // See https://github.com/quic-go/quic-go/pull/3806.
+ ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
+ InitialSourceConnectionID: srcConnID,
+ RetrySourceConnectionID: retrySrcConnID,
+ EnableResetStreamAt: conf.EnableStreamResetPartialDelivery,
+ }
+ if s.config.EnableDatagrams {
+ params.MaxDatagramFrameSize = wire.MaxDatagramSize
+ } else {
+ params.MaxDatagramFrameSize = protocol.InvalidByteCount
+ }
+ if s.qlogger != nil {
+ s.qlogTransportParameters(params, protocol.PerspectiveServer, false)
+ }
+ cs := handshake.NewCryptoSetupServer(
+ clientDestConnID,
+ conn.LocalAddr(),
+ conn.RemoteAddr(),
+ params,
+ tlsConf,
+ conf.Allow0RTT,
+ s.rttStats,
+ s.qlogger,
+ logger,
+ s.version,
+ )
+ s.cryptoStreamHandler = cs
+ s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, s.initialStream, s.handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, &s.receivedPacketHandler, s.datagramQueue, s.perspective)
+ s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen)
+ s.cryptoStreamManager = newCryptoStreamManager(s.initialStream, s.handshakeStream, s.oneRTTStream)
+ return &wrappedConn{Conn: s}
+}
+
+// declare this as a variable, such that we can it mock it in the tests
+var newClientConnection = func(
+ ctx context.Context,
+ conn sendConn,
+ runner connRunner,
+ destConnID protocol.ConnectionID,
+ srcConnID protocol.ConnectionID,
+ connIDGenerator ConnectionIDGenerator,
+ statelessResetter *statelessResetter,
+ conf *Config,
+ tlsConf *tls.Config,
+ initialPacketNumber protocol.PacketNumber,
+ enable0RTT bool,
+ hasNegotiatedVersion bool,
+ qlogTrace qlogwriter.Trace,
+ logger utils.Logger,
+ v protocol.Version,
+) *wrappedConn {
+ s := &Conn{
+ conn: conn,
+ config: conf,
+ origDestConnID: destConnID,
+ handshakeDestConnID: destConnID,
+ srcConnIDLen: srcConnID.Len(),
+ perspective: protocol.PerspectiveClient,
+ logID: destConnID.String(),
+ logger: logger,
+ qlogTrace: qlogTrace,
+ versionNegotiated: hasNegotiatedVersion,
+ version: v,
+ }
+ if qlogTrace != nil {
+ s.qlogger = qlogTrace.AddProducer()
+ }
+ if s.qlogger != nil {
+ var srcAddr, destAddr *net.UDPAddr
+ if addr, ok := conn.LocalAddr().(*net.UDPAddr); ok {
+ srcAddr = addr
+ }
+ if addr, ok := conn.RemoteAddr().(*net.UDPAddr); ok {
+ destAddr = addr
+ }
+ s.qlogger.RecordEvent(startedConnectionEvent(srcAddr, destAddr))
+ }
+ s.connIDManager = newConnIDManager(
+ destConnID,
+ func(token protocol.StatelessResetToken) { runner.AddResetToken(token, s) },
+ runner.RemoveResetToken,
+ s.queueControlFrame,
+ )
+ s.connIDGenerator = newConnIDGenerator(
+ runner,
+ srcConnID,
+ nil,
+ statelessResetter,
+ connRunnerCallbacks{
+ AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, s) },
+ RemoveConnectionID: runner.Remove,
+ ReplaceWithClosed: runner.ReplaceWithClosed,
+ },
+ s.queueControlFrame,
+ connIDGenerator,
+ )
+ s.ctx, s.ctxCancel = context.WithCancelCause(ctx)
+ s.preSetup()
+ s.sentPacketHandler = ackhandler.NewSentPacketHandler(
+ initialPacketNumber,
+ protocol.ByteCount(s.config.InitialPacketSize),
+ s.rttStats,
+ &s.connStats,
+ false, // has no effect
+ s.conn.capabilities().ECN,
+ s.receivedPacketHandler.IgnorePacketsBelow,
+ s.perspective,
+ s.qlogger,
+ s.logger,
+ )
+ s.maxPayloadSizeEstimate.Store(uint32(estimateMaxPayloadSize(protocol.ByteCount(s.config.InitialPacketSize))))
+ oneRTTStream := newCryptoStream()
+ params := &wire.TransportParameters{
+ InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
+ InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
+ InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
+ InitialMaxData: protocol.ByteCount(s.config.InitialConnectionReceiveWindow),
+ MaxIdleTimeout: s.config.MaxIdleTimeout,
+ MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams),
+ MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams),
+ MaxAckDelay: protocol.MaxAckDelayInclGranularity,
+ MaxUDPPayloadSize: protocol.MaxPacketBufferSize,
+ AckDelayExponent: protocol.AckDelayExponent,
+ // For interoperability with quic-go versions before May 2023, this value must be set to a value
+ // different from protocol.DefaultActiveConnectionIDLimit.
+ // If set to the default value, it will be omitted from the transport parameters, which will make
+ // old quic-go versions interpret it as 0, instead of the default value of 2.
+ // See https://github.com/quic-go/quic-go/pull/3806.
+ ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
+ InitialSourceConnectionID: srcConnID,
+ EnableResetStreamAt: conf.EnableStreamResetPartialDelivery,
+ }
+ if s.config.EnableDatagrams {
+ params.MaxDatagramFrameSize = wire.MaxDatagramSize
+ } else {
+ params.MaxDatagramFrameSize = protocol.InvalidByteCount
+ }
+ if s.qlogger != nil {
+ s.qlogTransportParameters(params, protocol.PerspectiveClient, false)
+ }
+ cs := handshake.NewCryptoSetupClient(
+ destConnID,
+ params,
+ tlsConf,
+ enable0RTT,
+ s.rttStats,
+ s.qlogger,
+ logger,
+ s.version,
+ )
+ s.cryptoStreamHandler = cs
+ s.cryptoStreamManager = newCryptoStreamManager(s.initialStream, s.handshakeStream, oneRTTStream)
+ s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen)
+ s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, s.initialStream, s.handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, &s.receivedPacketHandler, s.datagramQueue, s.perspective)
+ if len(tlsConf.ServerName) > 0 {
+ s.tokenStoreKey = tlsConf.ServerName
+ } else {
+ s.tokenStoreKey = conn.RemoteAddr().String()
+ }
+ if s.config.TokenStore != nil {
+ if token := s.config.TokenStore.Pop(s.tokenStoreKey); token != nil {
+ s.packer.SetToken(token.data)
+ s.rttStats.SetInitialRTT(token.rtt)
+ }
+ }
+ return &wrappedConn{Conn: s}
+}
+
+func (c *Conn) preSetup() {
+ c.largestRcvdAppData = protocol.InvalidPacketNumber
+ c.initialStream = newInitialCryptoStream(c.perspective == protocol.PerspectiveClient)
+ c.handshakeStream = newCryptoStream()
+ c.sendQueue = newSendQueue(c.conn)
+ c.retransmissionQueue = newRetransmissionQueue()
+ c.frameParser = *wire.NewFrameParser(
+ c.config.EnableDatagrams,
+ c.config.EnableStreamResetPartialDelivery,
+ false, // ACK_FREQUENCY is not supported yet
+ )
+ c.rttStats = utils.NewRTTStats()
+ c.connFlowController = flowcontrol.NewConnectionFlowController(
+ protocol.ByteCount(c.config.InitialConnectionReceiveWindow),
+ protocol.ByteCount(c.config.MaxConnectionReceiveWindow),
+ func(size protocol.ByteCount) bool {
+ if c.config.AllowConnectionWindowIncrease == nil {
+ return true
+ }
+ return c.config.AllowConnectionWindowIncrease(c, uint64(size))
+ },
+ c.rttStats,
+ c.logger,
+ )
+ c.earlyConnReadyChan = make(chan struct{})
+ c.streamsMap = newStreamsMap(
+ c.ctx,
+ c,
+ c.queueControlFrame,
+ c.newFlowController,
+ uint64(c.config.MaxIncomingStreams),
+ uint64(c.config.MaxIncomingUniStreams),
+ c.perspective,
+ )
+ c.framer = newFramer(c.connFlowController)
+ c.receivedPackets.Init(8)
+ c.notifyReceivedPacket = make(chan struct{}, 1)
+ c.closeChan = make(chan struct{}, 1)
+ c.sendingScheduled = make(chan struct{}, 1)
+ c.handshakeCompleteChan = make(chan struct{})
+
+ now := monotime.Now()
+ c.lastPacketReceivedTime = now
+ c.creationTime = now
+
+ c.receivedPacketHandler = *ackhandler.NewReceivedPacketHandler(c.logger)
+
+ c.datagramQueue = newDatagramQueue(c.scheduleSending, c.logger)
+ c.connState.Version = c.version
+}
+
+// run the connection main loop
+func (c *Conn) run() (err error) {
+ defer func() { c.ctxCancel(err) }()
+
+ defer func() {
+ // drain queued packets that will never be processed
+ c.receivedPacketMx.Lock()
+ defer c.receivedPacketMx.Unlock()
+
+ for !c.receivedPackets.Empty() {
+ p := c.receivedPackets.PopFront()
+ p.buffer.Decrement()
+ p.buffer.MaybeRelease()
+ }
+ }()
+
+ c.timer = time.NewTimer(monotime.Until(c.idleTimeoutStartTime().Add(c.config.HandshakeIdleTimeout)))
+
+ if err := c.cryptoStreamHandler.StartHandshake(c.ctx); err != nil {
+ return err
+ }
+ if err := c.handleHandshakeEvents(monotime.Now()); err != nil {
+ return err
+ }
+ go func() {
+ if err := c.sendQueue.Run(); err != nil {
+ c.destroyImpl(err)
+ }
+ }()
+
+ if c.perspective == protocol.PerspectiveClient {
+ c.scheduleSending() // so the ClientHello actually gets sent
+ }
+
+ var sendQueueAvailable <-chan struct{}
+
+runLoop:
+ for {
+ if c.framer.QueuedTooManyControlFrames() {
+ c.setCloseError(&closeError{err: &qerr.TransportError{ErrorCode: InternalError}})
+ break runLoop
+ }
+ // Close immediately if requested
+ select {
+ case <-c.closeChan:
+ break runLoop
+ default:
+ }
+
+ // no need to set a timer if we can send packets immediately
+ if c.pacingDeadline != deadlineSendImmediately {
+ c.maybeResetTimer()
+ }
+
+ // 1st: handle undecryptable packets, if any.
+ // This can only occur before completion of the handshake.
+ if len(c.undecryptablePacketsToProcess) > 0 {
+ var processedUndecryptablePacket bool
+ queue := c.undecryptablePacketsToProcess
+ c.undecryptablePacketsToProcess = nil
+ for _, p := range queue {
+ processed, err := c.handleOnePacket(p.receivedPacket, p.datagramID)
+ if err != nil {
+ c.setCloseError(&closeError{err: err})
+ break runLoop
+ }
+ if processed {
+ processedUndecryptablePacket = true
+ }
+ }
+ if processedUndecryptablePacket {
+ // if we processed any undecryptable packets, jump to the resetting of the timers directly
+ continue
+ }
+ }
+
+ // 2nd: receive packets.
+ processed, err := c.handlePackets() // don't check receivedPackets.Len() in the run loop to avoid locking the mutex
+ if err != nil {
+ c.setCloseError(&closeError{err: err})
+ break runLoop
+ }
+
+ // We don't need to wait for new events if:
+ // * we processed packets: we probably need to send an ACK, and potentially more data
+ // * the pacer allows us to send more packets immediately
+ shouldProceedImmediately := sendQueueAvailable == nil && (processed || c.pacingDeadline.Equal(deadlineSendImmediately))
+ if !shouldProceedImmediately {
+ // 3rd: wait for something to happen:
+ // * closing of the connection
+ // * timer firing
+ // * sending scheduled
+ // * send queue available
+ // * received packets
+ select {
+ case <-c.closeChan:
+ break runLoop
+ case <-c.timer.C:
+ case <-c.sendingScheduled:
+ case <-sendQueueAvailable:
+ case <-c.notifyReceivedPacket:
+ wasProcessed, err := c.handlePackets()
+ if err != nil {
+ c.setCloseError(&closeError{err: err})
+ break runLoop
+ }
+ // if we processed any undecryptable packets, jump to the resetting of the timers directly
+ if !wasProcessed {
+ continue
+ }
+ }
+ }
+
+ // Check for loss detection timeout.
+ // This could cause packets to be declared lost, and retransmissions to be enqueued.
+ now := monotime.Now()
+ if timeout := c.sentPacketHandler.GetLossDetectionTimeout(); !timeout.IsZero() && !timeout.After(now) {
+ if err := c.sentPacketHandler.OnLossDetectionTimeout(now); err != nil {
+ c.setCloseError(&closeError{err: err})
+ break runLoop
+ }
+ }
+
+ if keepAliveTime := c.nextKeepAliveTime(); !keepAliveTime.IsZero() && !now.Before(keepAliveTime) {
+ // send a PING frame since there is no activity in the connection
+ c.logger.Debugf("Sending a keep-alive PING to keep the connection alive.")
+ c.framer.QueueControlFrame(&wire.PingFrame{})
+ c.keepAlivePingSent = true
+ } else if !c.handshakeComplete && now.Sub(c.creationTime) >= c.config.handshakeTimeout() {
+ c.destroyImpl(qerr.ErrHandshakeTimeout)
+ break runLoop
+ } else {
+ idleTimeoutStartTime := c.idleTimeoutStartTime()
+ if (!c.handshakeComplete && now.Sub(idleTimeoutStartTime) >= c.config.HandshakeIdleTimeout) ||
+ (c.handshakeComplete && !now.Before(c.nextIdleTimeoutTime())) {
+ c.destroyImpl(qerr.ErrIdleTimeout)
+ break runLoop
+ }
+ }
+
+ c.connIDGenerator.RemoveRetiredConnIDs(now)
+
+ if c.perspective == protocol.PerspectiveClient {
+ pm := c.pathManagerOutgoing.Load()
+ if pm != nil {
+ tr, ok := pm.ShouldSwitchPath()
+ if ok {
+ c.switchToNewPath(tr, now)
+ }
+ }
+ }
+
+ if c.sendQueue.WouldBlock() {
+ // The send queue is still busy sending out packets. Wait until there's space to enqueue new packets.
+ sendQueueAvailable = c.sendQueue.Available()
+ // Cancel the pacing timer, as we can't send any more packets until the send queue is available again.
+ c.pacingDeadline = 0
+ c.blocked = blockModeHardBlocked
+ continue
+ }
+
+ if c.closeErr.Load() != nil {
+ break runLoop
+ }
+
+ c.blocked = blockModeNone // sending might set it back to true if we're congestion limited
+ if err := c.triggerSending(now); err != nil {
+ c.setCloseError(&closeError{err: err})
+ break runLoop
+ }
+ if c.sendQueue.WouldBlock() {
+ // The send queue is still busy sending out packets. Wait until there's space to enqueue new packets.
+ sendQueueAvailable = c.sendQueue.Available()
+ // Cancel the pacing timer, as we can't send any more packets until the send queue is available again.
+ c.pacingDeadline = 0
+ c.blocked = blockModeHardBlocked
+ } else {
+ sendQueueAvailable = nil
+ }
+ }
+
+ closeErr := c.closeErr.Load()
+ c.cryptoStreamHandler.Close()
+ c.sendQueue.Close() // close the send queue before sending the CONNECTION_CLOSE
+ c.handleCloseError(closeErr)
+ if c.qlogger != nil {
+ if e := (&errCloseForRecreating{}); !errors.As(closeErr.err, &e) {
+ c.qlogger.Close()
+ }
+ }
+ c.logger.Infof("Connection %s closed.", c.logID)
+ c.timer.Stop()
+ return closeErr.err
+}
+
+// blocks until the early connection can be used
+func (c *Conn) earlyConnReady() <-chan struct{} {
+ return c.earlyConnReadyChan
+}
+
+// Context returns a context that is cancelled when the connection is closed.
+// The cancellation cause is set to the error that caused the connection to close.
+func (c *Conn) Context() context.Context {
+ return c.ctx
+}
+
+func (c *Conn) supportsDatagrams() bool {
+ return c.peerParams.MaxDatagramFrameSize > 0
+}
+
+// ConnectionState returns basic details about the QUIC connection.
+func (c *Conn) ConnectionState() ConnectionState {
+ c.connStateMutex.Lock()
+ defer c.connStateMutex.Unlock()
+
+ cs := c.cryptoStreamHandler.ConnectionState()
+ c.connState.TLS = cs.ConnectionState
+ c.connState.Used0RTT = cs.Used0RTT
+ if c.peerParams != nil {
+ c.connState.SupportsDatagrams.Remote = c.supportsDatagrams()
+ c.connState.SupportsStreamResetPartialDelivery.Remote = c.peerParams.EnableResetStreamAt
+ }
+ c.connState.SupportsDatagrams.Local = c.config.EnableDatagrams
+ c.connState.SupportsStreamResetPartialDelivery.Local = c.config.EnableStreamResetPartialDelivery
+ c.connState.GSO = c.conn.capabilities().GSO
+ return c.connState
+}
+
+// ConnectionStats contains statistics about the QUIC connection
+type ConnectionStats struct {
+ // MinRTT is the estimate of the minimum RTT observed on the active network
+ // path.
+ MinRTT time.Duration
+ // LatestRTT is the last RTT sample observed on the active network path.
+ LatestRTT time.Duration
+ // SmoothedRTT is an exponentially weighted moving average of an endpoint's
+ // RTT samples. See https://www.rfc-editor.org/rfc/rfc9002#section-5.3
+ SmoothedRTT time.Duration
+ // MeanDeviation estimates the variation in the RTT samples using a mean
+ // variation. See https://www.rfc-editor.org/rfc/rfc9002#section-5.3
+ MeanDeviation time.Duration
+
+ // BytesSent is the number of bytes sent on the underlying connection,
+ // including retransmissions. Does not include UDP or any other outer
+ // framing.
+ BytesSent uint64
+ // PacketsSent is the number of packets sent on the underlying connection,
+ // including those that are determined to have been lost.
+ PacketsSent uint64
+ // BytesReceived is the number of total bytes received on the underlying
+ // connection, including duplicate data for streams. Does not include UDP or
+ // any other outer framing.
+ BytesReceived uint64
+ // PacketsReceived is the number of total packets received on the underlying
+ // connection, including packets that were not processable.
+ PacketsReceived uint64
+ // BytesLost is the number of bytes lost on the underlying connection (does
+ // not monotonically increase, because packets that are declared lost can
+ // subsequently be received). Does not include UDP or any other outer
+ // framing.
+ BytesLost uint64
+ // PacketsLost is the number of packets lost on the underlying connection
+ // (does not monotonically increase, because packets that are declared lost
+ // can subsequently be received).
+ PacketsLost uint64
+}
+
+func (c *Conn) ConnectionStats() ConnectionStats {
+ return ConnectionStats{
+ MinRTT: c.rttStats.MinRTT(),
+ LatestRTT: c.rttStats.LatestRTT(),
+ SmoothedRTT: c.rttStats.SmoothedRTT(),
+ MeanDeviation: c.rttStats.MeanDeviation(),
+
+ BytesSent: c.connStats.BytesSent.Load(),
+ PacketsSent: c.connStats.PacketsSent.Load(),
+ BytesReceived: c.connStats.BytesReceived.Load(),
+ PacketsReceived: c.connStats.PacketsReceived.Load(),
+ BytesLost: c.connStats.BytesLost.Load(),
+ PacketsLost: c.connStats.PacketsLost.Load(),
+ }
+}
+
+// Time when the connection should time out
+func (c *Conn) nextIdleTimeoutTime() monotime.Time {
+ idleTimeout := max(c.idleTimeout, c.rttStats.PTO(true)*3)
+ return c.idleTimeoutStartTime().Add(idleTimeout)
+}
+
+// Time when the next keep-alive packet should be sent.
+// It returns a zero time if no keep-alive should be sent.
+func (c *Conn) nextKeepAliveTime() monotime.Time {
+ if c.config.KeepAlivePeriod == 0 || c.keepAlivePingSent {
+ return 0
+ }
+ keepAliveInterval := max(c.keepAliveInterval, c.rttStats.PTO(true)*3/2)
+ return c.lastPacketReceivedTime.Add(keepAliveInterval)
+}
+
+func (c *Conn) maybeResetTimer() {
+ var deadline monotime.Time
+ if !c.handshakeComplete {
+ deadline = c.creationTime.Add(c.config.handshakeTimeout())
+ if t := c.idleTimeoutStartTime().Add(c.config.HandshakeIdleTimeout); t.Before(deadline) {
+ deadline = t
+ }
+ } else {
+ // A keep-alive packet is ack-eliciting, so it can only be sent if the connection is
+ // neither congestion limited nor hard-blocked.
+ if c.blocked != blockModeNone {
+ deadline = c.nextIdleTimeoutTime()
+ } else {
+ if keepAliveTime := c.nextKeepAliveTime(); !keepAliveTime.IsZero() {
+ deadline = keepAliveTime
+ } else {
+ deadline = c.nextIdleTimeoutTime()
+ }
+ }
+ }
+ // If the connection is hard-blocked, we can't even send acknowledgments,
+ // nor can we send PTO probe packets.
+ if c.blocked == blockModeHardBlocked {
+ c.timer.Reset(monotime.Until(deadline))
+ return
+ }
+
+ if t := c.receivedPacketHandler.GetAlarmTimeout(); !t.IsZero() && t.Before(deadline) {
+ deadline = t
+ }
+ if t := c.sentPacketHandler.GetLossDetectionTimeout(); !t.IsZero() && t.Before(deadline) {
+ deadline = t
+ }
+ if c.blocked == blockModeCongestionLimited {
+ c.timer.Reset(monotime.Until(deadline))
+ return
+ }
+
+ if !c.pacingDeadline.IsZero() && c.pacingDeadline.Before(deadline) {
+ deadline = c.pacingDeadline
+ }
+ c.timer.Reset(monotime.Until(deadline))
+}
+
+func (c *Conn) idleTimeoutStartTime() monotime.Time {
+ startTime := c.lastPacketReceivedTime
+ if t := c.firstAckElicitingPacketAfterIdleSentTime; !t.IsZero() && t.After(startTime) {
+ startTime = t
+ }
+ return startTime
+}
+
+func (c *Conn) switchToNewPath(tr *Transport, now monotime.Time) {
+ initialPacketSize := protocol.ByteCount(c.config.InitialPacketSize)
+ c.sentPacketHandler.MigratedPath(now, initialPacketSize)
+ maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize)
+ if c.peerParams.MaxUDPPayloadSize > 0 && c.peerParams.MaxUDPPayloadSize < maxPacketSize {
+ maxPacketSize = c.peerParams.MaxUDPPayloadSize
+ }
+ c.mtuDiscoverer.Reset(now, initialPacketSize, maxPacketSize)
+ c.conn = newSendConn(tr.conn, c.conn.RemoteAddr(), packetInfo{}, utils.DefaultLogger) // TODO: find a better way
+ c.sendQueue.Close()
+ c.sendQueue = newSendQueue(c.conn)
+ go func() {
+ if err := c.sendQueue.Run(); err != nil {
+ c.destroyImpl(err)
+ }
+ }()
+}
+
+func (c *Conn) handleHandshakeComplete(now monotime.Time) error {
+ defer close(c.handshakeCompleteChan)
+ // Once the handshake completes, we have derived 1-RTT keys.
+ // There's no point in queueing undecryptable packets for later decryption anymore.
+ c.undecryptablePackets = nil
+
+ c.connIDManager.SetHandshakeComplete()
+ c.connIDGenerator.SetHandshakeComplete(now.Add(3 * c.rttStats.PTO(false)))
+
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.ALPNInformation{
+ ChosenALPN: c.cryptoStreamHandler.ConnectionState().NegotiatedProtocol,
+ })
+ }
+
+ // The server applies transport parameters right away, but the client side has to wait for handshake completion.
+ // During a 0-RTT connection, the client is only allowed to use the new transport parameters for 1-RTT packets.
+ if c.perspective == protocol.PerspectiveClient {
+ c.applyTransportParameters()
+ return nil
+ }
+
+ // All these only apply to the server side.
+ if err := c.handleHandshakeConfirmed(now); err != nil {
+ return err
+ }
+
+ ticket, err := c.cryptoStreamHandler.GetSessionTicket()
+ if err != nil {
+ return err
+ }
+ if ticket != nil { // may be nil if session tickets are disabled via tls.Config.SessionTicketsDisabled
+ c.oneRTTStream.Write(ticket)
+ for c.oneRTTStream.HasData() {
+ if cf := c.oneRTTStream.PopCryptoFrame(protocol.MaxPostHandshakeCryptoFrameSize); cf != nil {
+ c.queueControlFrame(cf)
+ }
+ }
+ }
+ token, err := c.tokenGenerator.NewToken(c.conn.RemoteAddr(), c.rttStats.SmoothedRTT())
+ if err != nil {
+ return err
+ }
+ c.queueControlFrame(&wire.NewTokenFrame{Token: token})
+ c.queueControlFrame(&wire.HandshakeDoneFrame{})
+ return nil
+}
+
+func (c *Conn) handleHandshakeConfirmed(now monotime.Time) error {
+ // Drop initial keys.
+ // On the client side, this should have happened when sending the first Handshake packet,
+ // but this is not guaranteed if the server misbehaves.
+ // See CVE-2025-59530 for more details.
+ if err := c.dropEncryptionLevel(protocol.EncryptionInitial, now); err != nil {
+ return err
+ }
+ if err := c.dropEncryptionLevel(protocol.EncryptionHandshake, now); err != nil {
+ return err
+ }
+
+ c.handshakeConfirmed = true
+ c.cryptoStreamHandler.SetHandshakeConfirmed()
+
+ if !c.config.DisablePathMTUDiscovery && c.conn.capabilities().DF {
+ c.mtuDiscoverer.Start(now)
+ }
+ return nil
+}
+
+const maxPacketsToProcess = 32
+
+func (c *Conn) handlePackets() (wasProcessed bool, _ error) {
+ // Process packets from the receivedPackets queue.
+ // Limit the number of packets to process to maxPacketsToProcess,
+ // so we eventually get a chance to send out an ACK when receiving a lot of packets.
+ c.receivedPacketMx.Lock()
+
+ if c.receivedPackets.Empty() {
+ c.receivedPacketMx.Unlock()
+ return false, nil
+ }
+
+ var hasMorePackets bool
+ for range maxPacketsToProcess {
+ p := c.receivedPackets.PopFront()
+ c.receivedPacketMx.Unlock()
+
+ var datagramID qlog.DatagramID
+ if c.qlogger != nil && wire.IsLongHeaderPacket(p.data[0]) {
+ datagramID = qlog.CalculateDatagramID(p.data)
+ }
+ processed, err := c.handleOnePacket(p, datagramID)
+ if err != nil {
+ return false, err
+ }
+ if processed {
+ wasProcessed = true
+ }
+ c.receivedPacketMx.Lock()
+ hasMorePackets = !c.receivedPackets.Empty()
+ if !hasMorePackets {
+ break
+ }
+ // Prioritize sending of new CRYPTO data.
+ // This is especially relevant when processing 0-RTT packets.
+ if !c.handshakeComplete && (c.initialStream.HasData() || c.handshakeStream.HasData()) {
+ break
+ }
+ }
+ c.receivedPacketMx.Unlock()
+
+ if hasMorePackets {
+ select {
+ case c.notifyReceivedPacket <- struct{}{}:
+ default:
+ }
+ }
+ return wasProcessed, nil
+}
+
+func (c *Conn) handleOnePacket(rp receivedPacket, datagramID qlog.DatagramID) (wasProcessed bool, _ error) {
+ c.sentPacketHandler.ReceivedBytes(rp.Size(), rp.rcvTime)
+
+ if wire.IsVersionNegotiationPacket(rp.data) {
+ return false, c.handleVersionNegotiationPacket(rp)
+ }
+
+ var counter uint8
+ var lastConnID protocol.ConnectionID
+ data := rp.data
+ p := rp
+ for len(data) > 0 {
+ if counter > 0 {
+ p = *(p.Clone())
+ p.data = data
+
+ destConnID, err := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ if err != nil {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ c.logger.Debugf("error parsing packet, couldn't parse connection ID: %s", err)
+ break
+ }
+ if destConnID != lastConnID {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{DestConnectionID: destConnID},
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnknownConnectionID,
+ })
+ }
+ c.logger.Debugf("coalesced packet has different destination connection ID: %s, expected %s", destConnID, lastConnID)
+ break
+ }
+ }
+
+ if wire.IsLongHeaderPacket(p.data[0]) {
+ hdr, packetData, rest, err := wire.ParsePacket(p.data)
+ if err != nil {
+ if c.qlogger != nil {
+ if err == wire.ErrUnsupportedVersion {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{Version: hdr.Version},
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnsupportedVersion,
+ })
+ } else {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ }
+ c.logger.Debugf("error parsing packet: %s", err)
+ break
+ }
+ lastConnID = hdr.DestConnectionID
+
+ if hdr.Version != c.version {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnexpectedVersion,
+ })
+ }
+ c.logger.Debugf("Dropping packet with version %x. Expected %x.", hdr.Version, c.version)
+ break
+ }
+
+ if counter > 0 {
+ p.buffer.Split()
+ }
+ counter++
+
+ // only log if this actually a coalesced packet
+ if c.logger.Debug() && (counter > 1 || len(rest) > 0) {
+ c.logger.Debugf("Parsed a coalesced packet. Part %d: %d bytes. Remaining: %d bytes.", counter, len(packetData), len(rest))
+ }
+
+ p.data = packetData
+
+ processed, err := c.handleLongHeaderPacket(p, hdr, datagramID)
+ if err != nil {
+ return false, err
+ }
+ if processed {
+ wasProcessed = true
+ }
+ data = rest
+ } else {
+ if counter > 0 {
+ p.buffer.Split()
+ }
+ processed, err := c.handleShortHeaderPacket(p, counter > 0, datagramID)
+ if err != nil {
+ return false, err
+ }
+ if processed {
+ wasProcessed = true
+ }
+ break
+ }
+ }
+
+ p.buffer.MaybeRelease()
+ c.blocked = blockModeNone
+ return wasProcessed, nil
+}
+
+func (c *Conn) handleShortHeaderPacket(
+ p receivedPacket,
+ isCoalesced bool,
+ datagramID qlog.DatagramID, // only for logging
+) (wasProcessed bool, _ error) {
+ var wasQueued bool
+
+ defer func() {
+ // Put back the packet buffer if the packet wasn't queued for later decryption.
+ if !wasQueued {
+ p.buffer.Decrement()
+ }
+ }()
+
+ destConnID, err := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ if err != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: len(p.data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ return false, nil
+ }
+ pn, pnLen, keyPhase, data, err := c.unpacker.UnpackShortHeader(p.rcvTime, p.data)
+ if err != nil {
+ // Stateless reset packets (see RFC 9000, section 10.3):
+ // * fill the entire UDP datagram (i.e. they cannot be part of a coalesced packet)
+ // * are short header packets (first bit is 0)
+ // * have the QUIC bit set (second bit is 1)
+ // * are at least 21 bytes long
+ if !isCoalesced && len(p.data) >= protocol.MinReceivedStatelessResetSize && p.data[0]&0b11000000 == 0b01000000 {
+ token := protocol.StatelessResetToken(p.data[len(p.data)-16:])
+ if c.connIDManager.IsActiveStatelessResetToken(token) {
+ return false, &StatelessResetError{}
+ }
+ }
+ wasQueued, err = c.handleUnpackError(err, p, qlog.PacketType1RTT, datagramID)
+ return false, err
+ }
+ c.largestRcvdAppData = max(c.largestRcvdAppData, pn)
+
+ if c.logger.Debug() {
+ c.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, 1-RTT", pn, p.Size(), destConnID)
+ wire.LogShortHeader(c.logger, destConnID, pn, pnLen, keyPhase)
+ }
+
+ if c.receivedPacketHandler.IsPotentiallyDuplicate(pn, protocol.Encryption1RTT) {
+ c.logger.Debugf("Dropping (potentially) duplicate packet.")
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
+ PacketNumber: pn,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDuplicate,
+ })
+ }
+ return false, nil
+ }
+
+ var log func([]qlog.Frame)
+ if c.qlogger != nil {
+ log = func(frames []qlog.Frame) {
+ c.qlogger.RecordEvent(qlog.PacketReceived{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
+ DestConnectionID: destConnID,
+ PacketNumber: pn,
+ KeyPhaseBit: keyPhase,
+ },
+ Raw: qlog.RawInfo{
+ Length: int(p.Size()),
+ PayloadLength: int(p.Size() - wire.ShortHeaderLen(destConnID, pnLen)),
+ },
+ DatagramID: datagramID,
+ Frames: frames,
+ ECN: toQlogECN(p.ecn),
+ })
+ }
+ }
+ isNonProbing, pathChallenge, err := c.handleUnpackedShortHeaderPacket(destConnID, pn, data, p.ecn, p.rcvTime, log)
+ if err != nil {
+ return false, err
+ }
+
+ // In RFC 9000, only the client can migrate between paths.
+ if c.perspective == protocol.PerspectiveClient {
+ return true, nil
+ }
+ if addrsEqual(p.remoteAddr, c.RemoteAddr()) {
+ return true, nil
+ }
+
+ var shouldSwitchPath bool
+ if c.pathManager == nil {
+ c.pathManager = newPathManager(
+ c.connIDManager.GetConnIDForPath,
+ c.connIDManager.RetireConnIDForPath,
+ c.logger,
+ )
+ }
+ destConnID, frames, shouldSwitchPath := c.pathManager.HandlePacket(p.remoteAddr, p.rcvTime, pathChallenge, isNonProbing)
+ if len(frames) > 0 {
+ probe, buf, err := c.packer.PackPathProbePacket(destConnID, frames, c.version)
+ if err != nil {
+ return true, err
+ }
+ c.logger.Debugf("sending path probe packet to %s", p.remoteAddr)
+ c.logShortHeaderPacketWithDatagramID(probe, protocol.ECNNon, buf.Len(), false, datagramID)
+ c.registerPackedShortHeaderPacket(probe, protocol.ECNNon, p.rcvTime)
+ c.sendQueue.SendProbe(buf, p.remoteAddr, p.info)
+ }
+ // We only switch paths in response to the highest-numbered non-probing packet,
+ // see section 9.3 of RFC 9000.
+ if !shouldSwitchPath || pn != c.largestRcvdAppData {
+ return true, nil
+ }
+ c.pathManager.SwitchToPath(p.remoteAddr)
+ c.sentPacketHandler.MigratedPath(p.rcvTime, protocol.ByteCount(c.config.InitialPacketSize))
+ maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize)
+ if c.peerParams.MaxUDPPayloadSize > 0 && c.peerParams.MaxUDPPayloadSize < maxPacketSize {
+ maxPacketSize = c.peerParams.MaxUDPPayloadSize
+ }
+ c.mtuDiscoverer.Reset(
+ p.rcvTime,
+ protocol.ByteCount(c.config.InitialPacketSize),
+ maxPacketSize,
+ )
+ c.conn.ChangeRemoteAddr(p.remoteAddr, p.info)
+ return true, nil
+}
+
+func (c *Conn) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header, datagramID qlog.DatagramID) (wasProcessed bool, _ error) {
+ var wasQueued bool
+
+ defer func() {
+ // Put back the packet buffer if the packet wasn't queued for later decryption.
+ if !wasQueued {
+ p.buffer.Decrement()
+ }
+ }()
+
+ if hdr.Type == protocol.PacketTypeRetry {
+ return c.handleRetryPacket(hdr, p.data, p.rcvTime), nil
+ }
+
+ // The server can change the source connection ID with the first Handshake packet.
+ // After this, all packets with a different source connection have to be ignored.
+ if c.receivedFirstPacket && hdr.Type == protocol.PacketTypeInitial && hdr.SrcConnectionID != c.handshakeDestConnID {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeInitial,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnknownConnectionID,
+ })
+ }
+ c.logger.Debugf("Dropping Initial packet (%d bytes) with unexpected source connection ID: %s (expected %s)", p.Size(), hdr.SrcConnectionID, c.handshakeDestConnID)
+ return false, nil
+ }
+ // drop 0-RTT packets, if we are a client
+ if c.perspective == protocol.PerspectiveClient && hdr.Type == protocol.PacketType0RTT {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType0RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return false, nil
+ }
+
+ packet, err := c.unpacker.UnpackLongHeader(hdr, p.data)
+ if err != nil {
+ wasQueued, err = c.handleUnpackError(err, p, toQlogPacketType(hdr.Type), datagramID)
+ return false, err
+ }
+
+ if c.logger.Debug() {
+ c.logger.Debugf("<- Reading packet %d (%d bytes) for connection %s, %s", packet.hdr.PacketNumber, p.Size(), hdr.DestConnectionID, packet.encryptionLevel)
+ packet.hdr.Log(c.logger)
+ }
+
+ if pn := packet.hdr.PacketNumber; c.receivedPacketHandler.IsPotentiallyDuplicate(pn, packet.encryptionLevel) {
+ c.logger.Debugf("Dropping (potentially) duplicate packet.")
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: toQlogPacketType(packet.hdr.Type),
+ DestConnectionID: hdr.DestConnectionID,
+ SrcConnectionID: hdr.SrcConnectionID,
+ PacketNumber: pn,
+ Version: packet.hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size()), PayloadLength: int(packet.hdr.Length)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDuplicate,
+ })
+ }
+ return false, nil
+ }
+
+ if err := c.handleUnpackedLongHeaderPacket(packet, p.ecn, p.rcvTime, datagramID, p.Size()); err != nil {
+ return false, err
+ }
+ return true, nil
+}
+
+func (c *Conn) handleUnpackError(err error, p receivedPacket, pt qlog.PacketType, datagramID qlog.DatagramID) (wasQueued bool, _ error) {
+ switch err {
+ case handshake.ErrKeysDropped:
+ if c.qlogger != nil {
+ connID, _ := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ DestConnectionID: connID,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropKeyUnavailable,
+ })
+ }
+ c.logger.Debugf("Dropping %s packet (%d bytes) because we already dropped the keys.", pt, p.Size())
+ return false, nil
+ case handshake.ErrKeysNotYetAvailable:
+ // Sealer for this encryption level not yet available.
+ // Try again later.
+ c.tryQueueingUndecryptablePacket(p, pt, datagramID)
+ return true, nil
+ case wire.ErrInvalidReservedBits:
+ return false, &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: err.Error(),
+ }
+ case handshake.ErrDecryptionFailed:
+ // This might be a packet injected by an attacker. Drop it.
+ if c.qlogger != nil {
+ connID, _ := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ DestConnectionID: connID,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropPayloadDecryptError,
+ })
+ }
+ c.logger.Debugf("Dropping %s packet (%d bytes) that could not be unpacked. Error: %s", pt, p.Size(), err)
+ return false, nil
+ default:
+ var headerErr *headerParseError
+ if errors.As(err, &headerErr) {
+ // This might be a packet injected by an attacker. Drop it.
+ if c.qlogger != nil {
+ connID, _ := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ DestConnectionID: connID,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ c.logger.Debugf("Dropping %s packet (%d bytes) for which we couldn't unpack the header. Error: %s", pt, p.Size(), err)
+ return false, nil
+ }
+ // This is an error returned by the AEAD (other than ErrDecryptionFailed).
+ // For example, a PROTOCOL_VIOLATION due to key updates.
+ return false, err
+ }
+}
+
+func (c *Conn) handleRetryPacket(hdr *wire.Header, data []byte, rcvTime monotime.Time) bool /* was this a valid Retry */ {
+ if c.perspective == protocol.PerspectiveServer {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ c.logger.Debugf("Ignoring Retry.")
+ return false
+ }
+ if c.receivedFirstPacket {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ c.logger.Debugf("Ignoring Retry, since we already received a packet.")
+ return false
+ }
+ destConnID := c.connIDManager.Get()
+ if hdr.SrcConnectionID == destConnID {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ c.logger.Debugf("Ignoring Retry, since the server didn't change the Source Connection ID.")
+ return false
+ }
+ // If a token is already set, this means that we already received a Retry from the server.
+ // Ignore this Retry packet.
+ if c.receivedRetry {
+ c.logger.Debugf("Ignoring Retry, since a Retry was already received.")
+ return false
+ }
+
+ tag := handshake.GetRetryIntegrityTag(data[:len(data)-16], destConnID, hdr.Version)
+ if !bytes.Equal(data[len(data)-16:], tag[:]) {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropPayloadDecryptError,
+ })
+ }
+ c.logger.Debugf("Ignoring spoofed Retry. Integrity Tag doesn't match.")
+ return false
+ }
+
+ newDestConnID := hdr.SrcConnectionID
+ c.receivedRetry = true
+ c.sentPacketHandler.ResetForRetry(rcvTime)
+ c.handshakeDestConnID = newDestConnID
+ c.retrySrcConnID = &newDestConnID
+ c.cryptoStreamHandler.ChangeConnectionID(newDestConnID)
+ c.packer.SetToken(hdr.Token)
+ c.connIDManager.ChangeInitialConnID(newDestConnID)
+
+ if c.logger.Debug() {
+ c.logger.Debugf("<- Received Retry:")
+ (&wire.ExtendedHeader{Header: *hdr}).Log(c.logger)
+ c.logger.Debugf("Switching destination connection ID to: %s", hdr.SrcConnectionID)
+ }
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketReceived{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ DestConnectionID: destConnID,
+ SrcConnectionID: newDestConnID,
+ Version: hdr.Version,
+ Token: &qlog.Token{Raw: hdr.Token},
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ })
+ }
+
+ c.scheduleSending()
+ return true
+}
+
+func (c *Conn) handleVersionNegotiationPacket(p receivedPacket) error {
+ if c.perspective == protocol.PerspectiveServer || // servers never receive version negotiation packets
+ c.receivedFirstPacket || c.versionNegotiated { // ignore delayed / duplicated version negotiation packets
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return nil
+ }
+
+ src, dest, supportedVersions, err := wire.ParseVersionNegotiationPacket(p.data)
+ if err != nil {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ c.logger.Debugf("Error parsing Version Negotiation packet: %s", err)
+ return nil
+ }
+
+ if slices.Contains(supportedVersions, c.version) {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedVersion,
+ })
+ }
+ // The Version Negotiation packet contains the version that we offered.
+ // This might be a packet sent by an attacker, or it was corrupted.
+ return nil
+ }
+
+ c.logger.Infof("Received a Version Negotiation packet. Supported Versions: %s", supportedVersions)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.VersionNegotiationReceived{
+ Header: qlog.PacketHeaderVersionNegotiation{
+ DestConnectionID: dest,
+ SrcConnectionID: src,
+ },
+ SupportedVersions: supportedVersions,
+ })
+ }
+ newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, supportedVersions)
+ if !ok {
+ c.destroyImpl(&VersionNegotiationError{
+ Ours: c.config.Versions,
+ Theirs: supportedVersions,
+ })
+ c.logger.Infof("No compatible QUIC version found.")
+ return nil
+ }
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.VersionInformation{
+ ChosenVersion: newVersion,
+ ClientVersions: c.config.Versions,
+ ServerVersions: supportedVersions,
+ })
+ }
+
+ c.logger.Infof("Switching to QUIC version %s.", newVersion)
+ nextPN, _ := c.sentPacketHandler.PeekPacketNumber(protocol.EncryptionInitial)
+ return &errCloseForRecreating{
+ nextPacketNumber: nextPN,
+ nextVersion: newVersion,
+ }
+}
+
+func (c *Conn) handleUnpackedLongHeaderPacket(
+ packet *unpackedPacket,
+ ecn protocol.ECN,
+ rcvTime monotime.Time,
+ datagramID qlog.DatagramID, // only for logging
+ packetSize protocol.ByteCount, // only for logging
+) error {
+ if !c.receivedFirstPacket {
+ c.receivedFirstPacket = true
+ if !c.versionNegotiated && c.qlogger != nil {
+ var clientVersions, serverVersions []Version
+ switch c.perspective {
+ case protocol.PerspectiveClient:
+ clientVersions = c.config.Versions
+ case protocol.PerspectiveServer:
+ serverVersions = c.config.Versions
+ }
+ c.qlogger.RecordEvent(qlog.VersionInformation{
+ ChosenVersion: c.version,
+ ClientVersions: clientVersions,
+ ServerVersions: serverVersions,
+ })
+ }
+ // The server can change the source connection ID with the first Handshake packet.
+ if c.perspective == protocol.PerspectiveClient && packet.hdr.SrcConnectionID != c.handshakeDestConnID {
+ cid := packet.hdr.SrcConnectionID
+ c.logger.Debugf("Received first packet. Switching destination connection ID to: %s", cid)
+ c.handshakeDestConnID = cid
+ c.connIDManager.ChangeInitialConnID(cid)
+ }
+ // We create the connection as soon as we receive the first packet from the client.
+ // We do that before authenticating the packet.
+ // That means that if the source connection ID was corrupted,
+ // we might have created a connection with an incorrect source connection ID.
+ // Once we authenticate the first packet, we need to update it.
+ if c.perspective == protocol.PerspectiveServer {
+ if packet.hdr.SrcConnectionID != c.handshakeDestConnID {
+ c.handshakeDestConnID = packet.hdr.SrcConnectionID
+ c.connIDManager.ChangeInitialConnID(packet.hdr.SrcConnectionID)
+ }
+ if c.qlogger != nil {
+ var srcAddr, destAddr *net.UDPAddr
+ if addr, ok := c.conn.LocalAddr().(*net.UDPAddr); ok {
+ srcAddr = addr
+ }
+ if addr, ok := c.conn.RemoteAddr().(*net.UDPAddr); ok {
+ destAddr = addr
+ }
+ c.qlogger.RecordEvent(startedConnectionEvent(srcAddr, destAddr))
+ }
+ }
+ }
+
+ if c.perspective == protocol.PerspectiveServer && packet.encryptionLevel == protocol.EncryptionHandshake &&
+ !c.droppedInitialKeys {
+ // On the server side, Initial keys are dropped as soon as the first Handshake packet is received.
+ // See Section 4.9.1 of RFC 9001.
+ if err := c.dropEncryptionLevel(protocol.EncryptionInitial, rcvTime); err != nil {
+ return err
+ }
+ }
+
+ c.lastPacketReceivedTime = rcvTime
+ c.firstAckElicitingPacketAfterIdleSentTime = 0
+ c.keepAlivePingSent = false
+
+ if packet.hdr.Type == protocol.PacketType0RTT {
+ c.largestRcvdAppData = max(c.largestRcvdAppData, packet.hdr.PacketNumber)
+ }
+
+ var log func([]qlog.Frame)
+ if c.qlogger != nil {
+ log = func(frames []qlog.Frame) {
+ var token *qlog.Token
+ if len(packet.hdr.Token) > 0 {
+ token = &qlog.Token{Raw: packet.hdr.Token}
+ }
+ c.qlogger.RecordEvent(qlog.PacketReceived{
+ Header: qlog.PacketHeader{
+ PacketType: toQlogPacketType(packet.hdr.Type),
+ DestConnectionID: packet.hdr.DestConnectionID,
+ SrcConnectionID: packet.hdr.SrcConnectionID,
+ PacketNumber: packet.hdr.PacketNumber,
+ Version: packet.hdr.Version,
+ Token: token,
+ },
+ Raw: qlog.RawInfo{
+ Length: int(packetSize),
+ PayloadLength: int(packet.hdr.Length),
+ },
+ DatagramID: datagramID,
+ Frames: frames,
+ ECN: toQlogECN(ecn),
+ })
+ }
+ }
+ isAckEliciting, _, _, err := c.handleFrames(packet.data, packet.hdr.DestConnectionID, packet.encryptionLevel, log, rcvTime)
+ if err != nil {
+ return err
+ }
+ c.sentPacketHandler.ReceivedPacket(packet.encryptionLevel, rcvTime)
+ return c.receivedPacketHandler.ReceivedPacket(packet.hdr.PacketNumber, ecn, packet.encryptionLevel, rcvTime, isAckEliciting)
+}
+
+func (c *Conn) handleUnpackedShortHeaderPacket(
+ destConnID protocol.ConnectionID,
+ pn protocol.PacketNumber,
+ data []byte,
+ ecn protocol.ECN,
+ rcvTime monotime.Time,
+ log func([]qlog.Frame),
+) (isNonProbing bool, pathChallenge *wire.PathChallengeFrame, _ error) {
+ c.lastPacketReceivedTime = rcvTime
+ c.firstAckElicitingPacketAfterIdleSentTime = 0
+ c.keepAlivePingSent = false
+
+ isAckEliciting, isNonProbing, pathChallenge, err := c.handleFrames(data, destConnID, protocol.Encryption1RTT, log, rcvTime)
+ if err != nil {
+ return false, nil, err
+ }
+ c.sentPacketHandler.ReceivedPacket(protocol.Encryption1RTT, rcvTime)
+ if err := c.receivedPacketHandler.ReceivedPacket(pn, ecn, protocol.Encryption1RTT, rcvTime, isAckEliciting); err != nil {
+ return false, nil, err
+ }
+ return isNonProbing, pathChallenge, nil
+}
+
+// handleFrames parses the frames, one after the other, and handles them.
+// It returns the last PATH_CHALLENGE frame contained in the packet, if any.
+func (c *Conn) handleFrames(
+ data []byte,
+ destConnID protocol.ConnectionID,
+ encLevel protocol.EncryptionLevel,
+ log func([]qlog.Frame),
+ rcvTime monotime.Time,
+) (isAckEliciting, isNonProbing bool, pathChallenge *wire.PathChallengeFrame, _ error) {
+ // Only used for tracing.
+ // If we're not tracing, this slice will always remain empty.
+ var frames []qlog.Frame
+ if log != nil {
+ frames = make([]qlog.Frame, 0, 4)
+ }
+ handshakeWasComplete := c.handshakeComplete
+ var handleErr error
+ var skipHandling bool
+
+ for len(data) > 0 {
+ frameType, l, err := c.frameParser.ParseType(data, encLevel)
+ if err != nil {
+ // The frame parser skips over PADDING frames, and returns an io.EOF if the PADDING
+ // frames were the last frames in this packet.
+ if err == io.EOF {
+ break
+ }
+ return false, false, nil, err
+ }
+ data = data[l:]
+
+ if ackhandler.IsFrameTypeAckEliciting(frameType) {
+ isAckEliciting = true
+ }
+ if !wire.IsProbingFrameType(frameType) {
+ isNonProbing = true
+ }
+
+ // We're inlining common cases, to avoid using interfaces
+ // Fast path: STREAM, DATAGRAM and ACK
+ if frameType.IsStreamFrameType() {
+ streamFrame, l, err := c.frameParser.ParseStreamFrame(frameType, data, c.version)
+ if err != nil {
+ return false, false, nil, err
+ }
+ data = data[l:]
+
+ if log != nil {
+ frames = append(frames, toQlogFrame(streamFrame))
+ }
+ // an error occurred handling a previous frame, don't handle the current frame
+ if skipHandling {
+ continue
+ }
+ wire.LogFrame(c.logger, streamFrame, false)
+ handleErr = c.streamsMap.HandleStreamFrame(streamFrame, rcvTime)
+ } else if frameType.IsAckFrameType() {
+ ackFrame, l, err := c.frameParser.ParseAckFrame(frameType, data, encLevel, c.version)
+ if err != nil {
+ return false, false, nil, err
+ }
+ data = data[l:]
+ if log != nil {
+ frames = append(frames, toQlogFrame(ackFrame))
+ }
+ // an error occurred handling a previous frame, don't handle the current frame
+ if skipHandling {
+ continue
+ }
+ wire.LogFrame(c.logger, ackFrame, false)
+ handleErr = c.handleAckFrame(ackFrame, encLevel, rcvTime)
+ } else if frameType.IsDatagramFrameType() {
+ datagramFrame, l, err := c.frameParser.ParseDatagramFrame(frameType, data, c.version)
+ if err != nil {
+ return false, false, nil, err
+ }
+ data = data[l:]
+
+ if log != nil {
+ frames = append(frames, toQlogFrame(datagramFrame))
+ }
+ // an error occurred handling a previous frame, don't handle the current frame
+ if skipHandling {
+ continue
+ }
+ wire.LogFrame(c.logger, datagramFrame, false)
+ handleErr = c.handleDatagramFrame(datagramFrame)
+ } else {
+ frame, l, err := c.frameParser.ParseLessCommonFrame(frameType, data, c.version)
+ if err != nil {
+ return false, false, nil, err
+ }
+ data = data[l:]
+
+ if log != nil {
+ frames = append(frames, toQlogFrame(frame))
+ }
+ // an error occurred handling a previous frame, don't handle the current frame
+ if skipHandling {
+ continue
+ }
+ pc, err := c.handleFrame(frame, encLevel, destConnID, rcvTime)
+ if pc != nil {
+ pathChallenge = pc
+ }
+ handleErr = err
+ }
+
+ if handleErr != nil {
+ // if we're logging, we need to keep parsing (but not handling) all frames
+ skipHandling = true
+ if log == nil {
+ return false, false, nil, handleErr
+ }
+ }
+ }
+
+ if log != nil {
+ log(frames)
+ if handleErr != nil {
+ return false, false, nil, handleErr
+ }
+ }
+
+ // Handle completion of the handshake after processing all the frames.
+ // This ensures that we correctly handle the following case on the server side:
+ // We receive a Handshake packet that contains the CRYPTO frame that allows us to complete the handshake,
+ // and an ACK serialized after that CRYPTO frame. In this case, we still want to process the ACK frame.
+ if !handshakeWasComplete && c.handshakeComplete {
+ if err := c.handleHandshakeComplete(rcvTime); err != nil {
+ return false, false, nil, err
+ }
+ }
+ return
+}
+
+func (c *Conn) handleFrame(
+ f wire.Frame,
+ encLevel protocol.EncryptionLevel,
+ destConnID protocol.ConnectionID,
+ rcvTime monotime.Time,
+) (pathChallenge *wire.PathChallengeFrame, _ error) {
+ var err error
+ wire.LogFrame(c.logger, f, false)
+ switch frame := f.(type) {
+ case *wire.CryptoFrame:
+ err = c.handleCryptoFrame(frame, encLevel, rcvTime)
+ case *wire.ConnectionCloseFrame:
+ err = c.handleConnectionCloseFrame(frame)
+ case *wire.ResetStreamFrame:
+ err = c.streamsMap.HandleResetStreamFrame(frame, rcvTime)
+ case *wire.MaxDataFrame:
+ c.connFlowController.UpdateSendWindow(frame.MaximumData)
+ case *wire.MaxStreamDataFrame:
+ err = c.streamsMap.HandleMaxStreamDataFrame(frame)
+ case *wire.MaxStreamsFrame:
+ c.streamsMap.HandleMaxStreamsFrame(frame)
+ case *wire.DataBlockedFrame:
+ case *wire.StreamDataBlockedFrame:
+ err = c.streamsMap.HandleStreamDataBlockedFrame(frame)
+ case *wire.StreamsBlockedFrame:
+ case *wire.StopSendingFrame:
+ err = c.streamsMap.HandleStopSendingFrame(frame)
+ case *wire.PingFrame:
+ case *wire.PathChallengeFrame:
+ c.handlePathChallengeFrame(frame)
+ pathChallenge = frame
+ case *wire.PathResponseFrame:
+ err = c.handlePathResponseFrame(frame)
+ case *wire.NewTokenFrame:
+ err = c.handleNewTokenFrame(frame)
+ case *wire.NewConnectionIDFrame:
+ err = c.connIDManager.Add(frame)
+ case *wire.RetireConnectionIDFrame:
+ err = c.connIDGenerator.Retire(frame.SequenceNumber, destConnID, rcvTime.Add(3*c.rttStats.PTO(false)))
+ case *wire.HandshakeDoneFrame:
+ err = c.handleHandshakeDoneFrame(rcvTime)
+ default:
+ err = fmt.Errorf("unexpected frame type: %s", reflect.ValueOf(&frame).Elem().Type().Name())
+ }
+ return pathChallenge, err
+}
+
+// handlePacket is called by the server with a new packet
+func (c *Conn) handlePacket(p receivedPacket) {
+ c.receivedPacketMx.Lock()
+ // Discard packets once the amount of queued packets is larger than
+ // the channel size, protocol.MaxConnUnprocessedPackets
+ if c.receivedPackets.Len() >= protocol.MaxConnUnprocessedPackets {
+ if c.qlogger != nil {
+ var datagramID qlog.DatagramID
+ if wire.IsLongHeaderPacket(p.data[0]) {
+ datagramID = qlog.CalculateDatagramID(p.data)
+ }
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
+ }
+ c.receivedPacketMx.Unlock()
+ return
+ }
+ c.receivedPackets.PushBack(p)
+ c.receivedPacketMx.Unlock()
+
+ select {
+ case c.notifyReceivedPacket <- struct{}{}:
+ default:
+ }
+}
+
+func (c *Conn) handleConnectionCloseFrame(frame *wire.ConnectionCloseFrame) error {
+ if frame.IsApplicationError {
+ return &qerr.ApplicationError{
+ Remote: true,
+ ErrorCode: qerr.ApplicationErrorCode(frame.ErrorCode),
+ ErrorMessage: frame.ReasonPhrase,
+ }
+ }
+ return &qerr.TransportError{
+ Remote: true,
+ ErrorCode: qerr.TransportErrorCode(frame.ErrorCode),
+ FrameType: frame.FrameType,
+ ErrorMessage: frame.ReasonPhrase,
+ }
+}
+
+func (c *Conn) handleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel, rcvTime monotime.Time) error {
+ if err := c.cryptoStreamManager.HandleCryptoFrame(frame, encLevel); err != nil {
+ return err
+ }
+ for {
+ data := c.cryptoStreamManager.GetCryptoData(encLevel)
+ if data == nil {
+ break
+ }
+ if err := c.cryptoStreamHandler.HandleMessage(data, encLevel); err != nil {
+ return err
+ }
+ }
+ return c.handleHandshakeEvents(rcvTime)
+}
+
+func (c *Conn) handleHandshakeEvents(now monotime.Time) error {
+ for {
+ ev := c.cryptoStreamHandler.NextEvent()
+ var err error
+ switch ev.Kind {
+ case handshake.EventNoEvent:
+ return nil
+ case handshake.EventHandshakeComplete:
+ // Don't call handleHandshakeComplete yet.
+ // It's advantageous to process ACK frames that might be serialized after the CRYPTO frame first.
+ c.handshakeComplete = true
+ case handshake.EventReceivedTransportParameters:
+ err = c.handleTransportParameters(ev.TransportParameters)
+ case handshake.EventRestoredTransportParameters:
+ c.restoreTransportParameters(ev.TransportParameters)
+ close(c.earlyConnReadyChan)
+ case handshake.EventReceivedReadKeys:
+ // queue all previously undecryptable packets
+ c.undecryptablePacketsToProcess = append(c.undecryptablePacketsToProcess, c.undecryptablePackets...)
+ c.undecryptablePackets = nil
+ case handshake.EventDiscard0RTTKeys:
+ err = c.dropEncryptionLevel(protocol.Encryption0RTT, now)
+ case handshake.EventWriteInitialData:
+ _, err = c.initialStream.Write(ev.Data)
+ case handshake.EventWriteHandshakeData:
+ _, err = c.handshakeStream.Write(ev.Data)
+ }
+ if err != nil {
+ return err
+ }
+ }
+}
+
+func (c *Conn) handlePathChallengeFrame(f *wire.PathChallengeFrame) {
+ if c.perspective == protocol.PerspectiveClient {
+ c.queueControlFrame(&wire.PathResponseFrame{Data: f.Data})
+ }
+}
+
+func (c *Conn) handlePathResponseFrame(f *wire.PathResponseFrame) error {
+ switch c.perspective {
+ case protocol.PerspectiveClient:
+ return c.handlePathResponseFrameClient(f)
+ case protocol.PerspectiveServer:
+ return c.handlePathResponseFrameServer(f)
+ default:
+ panic("unreachable")
+ }
+}
+
+func (c *Conn) handlePathResponseFrameClient(f *wire.PathResponseFrame) error {
+ pm := c.pathManagerOutgoing.Load()
+ if pm == nil {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "unexpected PATH_RESPONSE frame",
+ }
+ }
+ pm.HandlePathResponseFrame(f)
+ return nil
+}
+
+func (c *Conn) handlePathResponseFrameServer(f *wire.PathResponseFrame) error {
+ if c.pathManager == nil {
+ // since we didn't send PATH_CHALLENGEs yet, we don't expect PATH_RESPONSEs
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "unexpected PATH_RESPONSE frame",
+ }
+ }
+ c.pathManager.HandlePathResponseFrame(f)
+ return nil
+}
+
+func (c *Conn) handleNewTokenFrame(frame *wire.NewTokenFrame) error {
+ if c.perspective == protocol.PerspectiveServer {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "received NEW_TOKEN frame from the client",
+ }
+ }
+ if c.config.TokenStore != nil {
+ c.config.TokenStore.Put(c.tokenStoreKey, &ClientToken{data: frame.Token, rtt: c.rttStats.SmoothedRTT()})
+ }
+ return nil
+}
+
+func (c *Conn) handleHandshakeDoneFrame(rcvTime monotime.Time) error {
+ if c.perspective == protocol.PerspectiveServer {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "received a HANDSHAKE_DONE frame",
+ }
+ }
+ if !c.handshakeConfirmed {
+ return c.handleHandshakeConfirmed(rcvTime)
+ }
+ return nil
+}
+
+func (c *Conn) handleAckFrame(frame *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime monotime.Time) error {
+ acked1RTTPacket, err := c.sentPacketHandler.ReceivedAck(frame, encLevel, c.lastPacketReceivedTime)
+ if err != nil {
+ return err
+ }
+ if !acked1RTTPacket {
+ return nil
+ }
+ // On the client side: If the packet acknowledged a 1-RTT packet, this confirms the handshake.
+ // This is only possible if the ACK was sent in a 1-RTT packet.
+ // This is an optimization over simply waiting for a HANDSHAKE_DONE frame, see section 4.1.2 of RFC 9001.
+ if c.perspective == protocol.PerspectiveClient && !c.handshakeConfirmed {
+ if err := c.handleHandshakeConfirmed(rcvTime); err != nil {
+ return err
+ }
+ }
+ // If one of the acknowledged packets was a Path MTU probe packet, this might have increased the Path MTU estimate.
+ if c.mtuDiscoverer != nil {
+ mtu := c.mtuDiscoverer.CurrentSize()
+ maxPayloadSize := estimateMaxPayloadSize(mtu)
+ if maxPayloadSize > protocol.ByteCount(c.maxPayloadSizeEstimate.Load()) {
+ c.maxPayloadSizeEstimate.Store(uint32(maxPayloadSize))
+ c.sentPacketHandler.SetMaxDatagramSize(mtu)
+ }
+ }
+ return c.cryptoStreamHandler.SetLargest1RTTAcked(frame.LargestAcked())
+}
+
+func (c *Conn) handleDatagramFrame(f *wire.DatagramFrame) error {
+ if f.Length(c.version) > wire.MaxDatagramSize {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "DATAGRAM frame too large",
+ }
+ }
+ c.datagramQueue.HandleDatagramFrame(f)
+ return nil
+}
+
+func (c *Conn) setCloseError(e *closeError) {
+ c.closeErr.CompareAndSwap(nil, e)
+ select {
+ case c.closeChan <- struct{}{}:
+ default:
+ }
+}
+
+// closeLocal closes the connection and send a CONNECTION_CLOSE containing the error
+func (c *Conn) closeLocal(e error) {
+ c.setCloseError(&closeError{err: e, immediate: false})
+}
+
+// destroy closes the connection without sending the error on the wire
+func (c *Conn) destroy(e error) {
+ c.destroyImpl(e)
+ <-c.ctx.Done()
+}
+
+func (c *Conn) destroyImpl(e error) {
+ c.setCloseError(&closeError{err: e, immediate: true})
+}
+
+// CloseWithError closes the connection with an error.
+// The error string will be sent to the peer.
+func (c *Conn) CloseWithError(code ApplicationErrorCode, desc string) error {
+ c.closeLocal(&qerr.ApplicationError{
+ ErrorCode: code,
+ ErrorMessage: desc,
+ })
+ <-c.ctx.Done()
+ return nil
+}
+
+func (c *Conn) closeWithTransportError(code TransportErrorCode) {
+ c.closeLocal(&qerr.TransportError{ErrorCode: code})
+ <-c.ctx.Done()
+}
+
+func (c *Conn) handleCloseError(closeErr *closeError) {
+ if closeErr.immediate {
+ if nerr, ok := closeErr.err.(net.Error); ok && nerr.Timeout() {
+ c.logger.Errorf("Destroying connection: %s", closeErr.err)
+ } else {
+ c.logger.Errorf("Destroying connection with error: %s", closeErr.err)
+ }
+ } else {
+ if closeErr.err == nil {
+ c.logger.Infof("Closing connection.")
+ } else {
+ c.logger.Errorf("Closing connection with error: %s", closeErr.err)
+ }
+ }
+
+ e := closeErr.err
+ if e == nil {
+ e = &qerr.ApplicationError{}
+ } else {
+ defer func() { closeErr.err = e }()
+ }
+
+ var (
+ statelessResetErr *StatelessResetError
+ versionNegotiationErr *VersionNegotiationError
+ recreateErr *errCloseForRecreating
+ applicationErr *ApplicationError
+ transportErr *TransportError
+ )
+ var isRemoteClose bool
+ var trigger qlog.ConnectionCloseTrigger
+ var reason string
+ var transportErrorCode *qlog.TransportErrorCode
+ var applicationErrorCode *qlog.ApplicationErrorCode
+ switch {
+ case errors.Is(e, qerr.ErrIdleTimeout),
+ errors.Is(e, qerr.ErrHandshakeTimeout):
+ trigger = qlog.ConnectionCloseTriggerIdleTimeout
+ case errors.As(e, &statelessResetErr):
+ trigger = qlog.ConnectionCloseTriggerStatelessReset
+ case errors.As(e, &versionNegotiationErr):
+ trigger = qlog.ConnectionCloseTriggerVersionMismatch
+ case errors.As(e, &recreateErr):
+ case errors.As(e, &applicationErr):
+ isRemoteClose = applicationErr.Remote
+ reason = applicationErr.ErrorMessage
+ applicationErrorCode = &applicationErr.ErrorCode
+ case errors.As(e, &transportErr):
+ isRemoteClose = transportErr.Remote
+ reason = transportErr.ErrorMessage
+ transportErrorCode = &transportErr.ErrorCode
+ case closeErr.immediate:
+ e = closeErr.err
+ default:
+ te := &qerr.TransportError{
+ ErrorCode: qerr.InternalError,
+ ErrorMessage: e.Error(),
+ }
+ e = te
+ reason = te.ErrorMessage
+ code := te.ErrorCode
+ transportErrorCode = &code
+ }
+
+ c.streamsMap.CloseWithError(e)
+ if c.datagramQueue != nil {
+ c.datagramQueue.CloseWithError(e)
+ }
+
+ // In rare instances, the connection ID manager might switch to a new connection ID
+ // when sending the CONNECTION_CLOSE frame.
+ // The connection ID manager removes the active stateless reset token from the packet
+ // handler map when it is closed, so we need to make sure that this happens last.
+ defer c.connIDManager.Close()
+
+ if c.qlogger != nil && !errors.As(e, &recreateErr) {
+ initiator := qlog.InitiatorLocal
+ if isRemoteClose {
+ initiator = qlog.InitiatorRemote
+ }
+ c.qlogger.RecordEvent(qlog.ConnectionClosed{
+ Initiator: initiator,
+ ConnectionError: transportErrorCode,
+ ApplicationError: applicationErrorCode,
+ Trigger: trigger,
+ Reason: reason,
+ })
+ }
+
+ // If this is a remote close we're done here
+ if isRemoteClose {
+ c.connIDGenerator.ReplaceWithClosed(nil, 3*c.rttStats.PTO(false))
+ return
+ }
+ if closeErr.immediate {
+ c.connIDGenerator.RemoveAll()
+ return
+ }
+ // Don't send out any CONNECTION_CLOSE if this is an error that occurred
+ // before we even sent out the first packet.
+ if c.perspective == protocol.PerspectiveClient && !c.sentFirstPacket {
+ c.connIDGenerator.RemoveAll()
+ return
+ }
+ connClosePacket, err := c.sendConnectionClose(e)
+ if err != nil {
+ c.logger.Debugf("Error sending CONNECTION_CLOSE: %s", err)
+ }
+ c.connIDGenerator.ReplaceWithClosed(connClosePacket, 3*c.rttStats.PTO(false))
+}
+
+func (c *Conn) dropEncryptionLevel(encLevel protocol.EncryptionLevel, now monotime.Time) error {
+ c.sentPacketHandler.DropPackets(encLevel, now)
+ c.receivedPacketHandler.DropPackets(encLevel)
+ //nolint:exhaustive // only Initial and 0-RTT need special treatment
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ c.droppedInitialKeys = true
+ c.cryptoStreamHandler.DiscardInitialKeys()
+ case protocol.Encryption0RTT:
+ c.streamsMap.ResetFor0RTT()
+ c.framer.Handle0RTTRejection()
+ return c.connFlowController.Reset()
+ }
+ return c.cryptoStreamManager.Drop(encLevel)
+}
+
+// is called for the client, when restoring transport parameters saved for 0-RTT
+func (c *Conn) restoreTransportParameters(params *wire.TransportParameters) {
+ if c.logger.Debug() {
+ c.logger.Debugf("Restoring Transport Parameters: %s", params)
+ }
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.ParametersSet{
+ Restore: true,
+ Initiator: qlog.InitiatorRemote,
+ SentBy: c.perspective,
+ OriginalDestinationConnectionID: params.OriginalDestinationConnectionID,
+ InitialSourceConnectionID: params.InitialSourceConnectionID,
+ RetrySourceConnectionID: params.RetrySourceConnectionID,
+ StatelessResetToken: params.StatelessResetToken,
+ DisableActiveMigration: params.DisableActiveMigration,
+ MaxIdleTimeout: params.MaxIdleTimeout,
+ MaxUDPPayloadSize: params.MaxUDPPayloadSize,
+ AckDelayExponent: params.AckDelayExponent,
+ MaxAckDelay: params.MaxAckDelay,
+ ActiveConnectionIDLimit: params.ActiveConnectionIDLimit,
+ InitialMaxData: params.InitialMaxData,
+ InitialMaxStreamDataBidiLocal: params.InitialMaxStreamDataBidiLocal,
+ InitialMaxStreamDataBidiRemote: params.InitialMaxStreamDataBidiRemote,
+ InitialMaxStreamDataUni: params.InitialMaxStreamDataUni,
+ InitialMaxStreamsBidi: int64(params.MaxBidiStreamNum),
+ InitialMaxStreamsUni: int64(params.MaxUniStreamNum),
+ MaxDatagramFrameSize: params.MaxDatagramFrameSize,
+ EnableResetStreamAt: params.EnableResetStreamAt,
+ })
+ }
+
+ c.peerParams = params
+ c.connIDGenerator.SetMaxActiveConnIDs(params.ActiveConnectionIDLimit)
+ c.connFlowController.UpdateSendWindow(params.InitialMaxData)
+ c.streamsMap.HandleTransportParameters(params)
+}
+
+func (c *Conn) handleTransportParameters(params *wire.TransportParameters) error {
+ if c.qlogger != nil {
+ c.qlogTransportParameters(params, c.perspective.Opposite(), false)
+ }
+ if err := c.checkTransportParameters(params); err != nil {
+ return &qerr.TransportError{
+ ErrorCode: qerr.TransportParameterError,
+ ErrorMessage: err.Error(),
+ }
+ }
+
+ if c.perspective == protocol.PerspectiveClient && c.peerParams != nil && c.ConnectionState().Used0RTT && !params.ValidForUpdate(c.peerParams) {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "server sent reduced limits after accepting 0-RTT data",
+ }
+ }
+
+ c.peerParams = params
+ // On the client side we have to wait for handshake completion.
+ // During a 0-RTT connection, we are only allowed to use the new transport parameters for 1-RTT packets.
+ if c.perspective == protocol.PerspectiveServer {
+ c.applyTransportParameters()
+ // On the server side, the early connection is ready as soon as we processed
+ // the client's transport parameters.
+ close(c.earlyConnReadyChan)
+ }
+ return nil
+}
+
+func (c *Conn) checkTransportParameters(params *wire.TransportParameters) error {
+ if c.logger.Debug() {
+ c.logger.Debugf("Processed Transport Parameters: %s", params)
+ }
+
+ // check the initial_source_connection_id
+ if params.InitialSourceConnectionID != c.handshakeDestConnID {
+ return fmt.Errorf("expected initial_source_connection_id to equal %s, is %s", c.handshakeDestConnID, params.InitialSourceConnectionID)
+ }
+
+ if c.perspective == protocol.PerspectiveServer {
+ return nil
+ }
+ // check the original_destination_connection_id
+ if params.OriginalDestinationConnectionID != c.origDestConnID {
+ return fmt.Errorf("expected original_destination_connection_id to equal %s, is %s", c.origDestConnID, params.OriginalDestinationConnectionID)
+ }
+ if c.retrySrcConnID != nil { // a Retry was performed
+ if params.RetrySourceConnectionID == nil {
+ return errors.New("missing retry_source_connection_id")
+ }
+ if *params.RetrySourceConnectionID != *c.retrySrcConnID {
+ return fmt.Errorf("expected retry_source_connection_id to equal %s, is %s", c.retrySrcConnID, *params.RetrySourceConnectionID)
+ }
+ } else if params.RetrySourceConnectionID != nil {
+ return errors.New("received retry_source_connection_id, although no Retry was performed")
+ }
+ return nil
+}
+
+func (c *Conn) applyTransportParameters() {
+ params := c.peerParams
+ // Our local idle timeout will always be > 0.
+ c.idleTimeout = c.config.MaxIdleTimeout
+ // If the peer advertised an idle timeout, take the minimum of the values.
+ if params.MaxIdleTimeout > 0 {
+ c.idleTimeout = min(c.idleTimeout, params.MaxIdleTimeout)
+ }
+ c.keepAliveInterval = min(c.config.KeepAlivePeriod, c.idleTimeout/2)
+ c.streamsMap.HandleTransportParameters(params)
+ c.frameParser.SetAckDelayExponent(params.AckDelayExponent)
+ c.connFlowController.UpdateSendWindow(params.InitialMaxData)
+ c.rttStats.SetMaxAckDelay(params.MaxAckDelay)
+ c.connIDGenerator.SetMaxActiveConnIDs(params.ActiveConnectionIDLimit)
+ if params.StatelessResetToken != nil {
+ c.connIDManager.SetStatelessResetToken(*params.StatelessResetToken)
+ }
+ // We don't support connection migration yet, so we don't have any use for the preferred_address.
+ if params.PreferredAddress != nil {
+ // Retire the connection ID.
+ c.connIDManager.AddFromPreferredAddress(params.PreferredAddress.ConnectionID, params.PreferredAddress.StatelessResetToken)
+ }
+ maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize)
+ if params.MaxUDPPayloadSize > 0 && params.MaxUDPPayloadSize < maxPacketSize {
+ maxPacketSize = params.MaxUDPPayloadSize
+ }
+ c.mtuDiscoverer = newMTUDiscoverer(
+ c.rttStats,
+ protocol.ByteCount(c.config.InitialPacketSize),
+ maxPacketSize,
+ c.qlogger,
+ )
+}
+
+func (c *Conn) triggerSending(now monotime.Time) error {
+ c.pacingDeadline = 0
+
+ sendMode := c.sentPacketHandler.SendMode(now)
+ switch sendMode {
+ case ackhandler.SendAny:
+ return c.sendPackets(now)
+ case ackhandler.SendNone:
+ c.blocked = blockModeHardBlocked
+ return nil
+ case ackhandler.SendPacingLimited:
+ deadline := c.sentPacketHandler.TimeUntilSend()
+ if deadline.IsZero() {
+ deadline = deadlineSendImmediately
+ }
+ c.pacingDeadline = deadline
+ // Allow sending of an ACK if we're pacing limit.
+ // This makes sure that a peer that is mostly receiving data (and thus has an inaccurate cwnd estimate)
+ // sends enough ACKs to allow its peer to utilize the bandwidth.
+ return c.maybeSendAckOnlyPacket(now)
+ case ackhandler.SendAck:
+ // We can at most send a single ACK only packet.
+ // There will only be a new ACK after receiving new packets.
+ // SendAck is only returned when we're congestion limited, so we don't need to set the pacing timer.
+ c.blocked = blockModeCongestionLimited
+ return c.maybeSendAckOnlyPacket(now)
+ case ackhandler.SendPTOInitial, ackhandler.SendPTOHandshake, ackhandler.SendPTOAppData:
+ if err := c.sendProbePacket(sendMode, now); err != nil {
+ return err
+ }
+ if c.sendQueue.WouldBlock() {
+ c.scheduleSending()
+ return nil
+ }
+ return c.triggerSending(now)
+ default:
+ return fmt.Errorf("BUG: invalid send mode %d", sendMode)
+ }
+}
+
+func (c *Conn) sendPackets(now monotime.Time) error {
+ if c.perspective == protocol.PerspectiveClient && c.handshakeConfirmed {
+ if pm := c.pathManagerOutgoing.Load(); pm != nil {
+ connID, frame, tr, ok := pm.NextPathToProbe()
+ if ok {
+ probe, buf, err := c.packer.PackPathProbePacket(connID, []ackhandler.Frame{frame}, c.version)
+ if err != nil {
+ return err
+ }
+ c.logger.Debugf("sending path probe packet from %s", c.LocalAddr())
+ c.logShortHeaderPacket(probe, protocol.ECNNon, buf.Len())
+ c.registerPackedShortHeaderPacket(probe, protocol.ECNNon, now)
+ tr.WriteTo(buf.Data, c.conn.RemoteAddr())
+ // There's (likely) more data to send. Loop around again.
+ c.scheduleSending()
+ return nil
+ }
+ }
+ }
+
+ // Path MTU Discovery
+ // Can't use GSO, since we need to send a single packet that's larger than our current maximum size.
+ // Performance-wise, this doesn't matter, since we only send a very small (<10) number of
+ // MTU probe packets per connection.
+ if c.handshakeConfirmed && c.mtuDiscoverer != nil && c.mtuDiscoverer.ShouldSendProbe(now) {
+ ping, size := c.mtuDiscoverer.GetPing(now)
+ p, buf, err := c.packer.PackMTUProbePacket(ping, size, c.version)
+ if err != nil {
+ return err
+ }
+ ecn := c.sentPacketHandler.ECNMode(true)
+ c.logShortHeaderPacket(p, ecn, buf.Len())
+ c.registerPackedShortHeaderPacket(p, ecn, now)
+ c.sendQueue.Send(buf, 0, ecn)
+ // There's (likely) more data to send. Loop around again.
+ c.scheduleSending()
+ return nil
+ }
+
+ if offset := c.connFlowController.GetWindowUpdate(now); offset > 0 {
+ c.framer.QueueControlFrame(&wire.MaxDataFrame{MaximumData: offset})
+ }
+ if cf := c.cryptoStreamManager.GetPostHandshakeData(protocol.MaxPostHandshakeCryptoFrameSize); cf != nil {
+ c.queueControlFrame(cf)
+ }
+
+ if !c.handshakeConfirmed {
+ packet, err := c.packer.PackCoalescedPacket(false, c.maxPacketSize(), now, c.version)
+ if err != nil || packet == nil {
+ return err
+ }
+ c.sentFirstPacket = true
+ if err := c.sendPackedCoalescedPacket(packet, c.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now); err != nil {
+ return err
+ }
+ //nolint:exhaustive // only need to handle pacing-related events here
+ switch c.sentPacketHandler.SendMode(now) {
+ case ackhandler.SendPacingLimited:
+ c.resetPacingDeadline()
+ case ackhandler.SendAny:
+ c.pacingDeadline = deadlineSendImmediately
+ }
+ return nil
+ }
+
+ if c.conn.capabilities().GSO {
+ return c.sendPacketsWithGSO(now)
+ }
+ return c.sendPacketsWithoutGSO(now)
+}
+
+func (c *Conn) sendPacketsWithoutGSO(now monotime.Time) error {
+ for {
+ buf := getPacketBuffer()
+ ecn := c.sentPacketHandler.ECNMode(true)
+ if _, err := c.appendOneShortHeaderPacket(buf, c.maxPacketSize(), ecn, now); err != nil {
+ if err == errNothingToPack {
+ buf.Release()
+ return nil
+ }
+ return err
+ }
+
+ c.sendQueue.Send(buf, 0, ecn)
+
+ if c.sendQueue.WouldBlock() {
+ return nil
+ }
+ sendMode := c.sentPacketHandler.SendMode(now)
+ if sendMode == ackhandler.SendPacingLimited {
+ c.resetPacingDeadline()
+ return nil
+ }
+ if sendMode != ackhandler.SendAny {
+ return nil
+ }
+ // Prioritize receiving of packets over sending out more packets.
+ c.receivedPacketMx.Lock()
+ hasPackets := !c.receivedPackets.Empty()
+ c.receivedPacketMx.Unlock()
+ if hasPackets {
+ c.pacingDeadline = deadlineSendImmediately
+ return nil
+ }
+ }
+}
+
+func (c *Conn) sendPacketsWithGSO(now monotime.Time) error {
+ buf := getLargePacketBuffer()
+ maxSize := c.maxPacketSize()
+
+ ecn := c.sentPacketHandler.ECNMode(true)
+ for {
+ var dontSendMore bool
+ size, err := c.appendOneShortHeaderPacket(buf, maxSize, ecn, now)
+ if err != nil {
+ if err != errNothingToPack {
+ return err
+ }
+ if buf.Len() == 0 {
+ buf.Release()
+ return nil
+ }
+ dontSendMore = true
+ }
+
+ if !dontSendMore {
+ sendMode := c.sentPacketHandler.SendMode(now)
+ if sendMode == ackhandler.SendPacingLimited {
+ c.resetPacingDeadline()
+ }
+ if sendMode != ackhandler.SendAny {
+ dontSendMore = true
+ }
+ }
+
+ // Don't send more packets in this batch if they require a different ECN marking than the previous ones.
+ nextECN := c.sentPacketHandler.ECNMode(true)
+
+ // Append another packet if
+ // 1. The congestion controller and pacer allow sending more
+ // 2. The last packet appended was a full-size packet
+ // 3. The next packet will have the same ECN marking
+ // 4. We still have enough space for another full-size packet in the buffer
+ if !dontSendMore && size == maxSize && nextECN == ecn && buf.Len()+maxSize <= buf.Cap() {
+ continue
+ }
+
+ c.sendQueue.Send(buf, uint16(maxSize), ecn)
+
+ if dontSendMore {
+ return nil
+ }
+ if c.sendQueue.WouldBlock() {
+ return nil
+ }
+
+ // Prioritize receiving of packets over sending out more packets.
+ c.receivedPacketMx.Lock()
+ hasPackets := !c.receivedPackets.Empty()
+ c.receivedPacketMx.Unlock()
+ if hasPackets {
+ c.pacingDeadline = deadlineSendImmediately
+ return nil
+ }
+
+ ecn = nextECN
+ buf = getLargePacketBuffer()
+ }
+}
+
+func (c *Conn) resetPacingDeadline() {
+ deadline := c.sentPacketHandler.TimeUntilSend()
+ if deadline.IsZero() {
+ deadline = deadlineSendImmediately
+ }
+ c.pacingDeadline = deadline
+}
+
+func (c *Conn) maybeSendAckOnlyPacket(now monotime.Time) error {
+ if !c.handshakeConfirmed {
+ ecn := c.sentPacketHandler.ECNMode(false)
+ packet, err := c.packer.PackCoalescedPacket(true, c.maxPacketSize(), now, c.version)
+ if err != nil {
+ return err
+ }
+ if packet == nil {
+ return nil
+ }
+ return c.sendPackedCoalescedPacket(packet, ecn, now)
+ }
+
+ ecn := c.sentPacketHandler.ECNMode(true)
+ p, buf, err := c.packer.PackAckOnlyPacket(c.maxPacketSize(), now, c.version)
+ if err != nil {
+ if err == errNothingToPack {
+ return nil
+ }
+ return err
+ }
+ c.logShortHeaderPacket(p, ecn, buf.Len())
+ c.registerPackedShortHeaderPacket(p, ecn, now)
+ c.sendQueue.Send(buf, 0, ecn)
+ return nil
+}
+
+func (c *Conn) sendProbePacket(sendMode ackhandler.SendMode, now monotime.Time) error {
+ var encLevel protocol.EncryptionLevel
+ //nolint:exhaustive // We only need to handle the PTO send modes here.
+ switch sendMode {
+ case ackhandler.SendPTOInitial:
+ encLevel = protocol.EncryptionInitial
+ case ackhandler.SendPTOHandshake:
+ encLevel = protocol.EncryptionHandshake
+ case ackhandler.SendPTOAppData:
+ encLevel = protocol.Encryption1RTT
+ default:
+ return fmt.Errorf("connection BUG: unexpected send mode: %d", sendMode)
+ }
+ // Queue probe packets until we actually send out a packet,
+ // or until there are no more packets to queue.
+ var packet *coalescedPacket
+ for packet == nil {
+ if wasQueued := c.sentPacketHandler.QueueProbePacket(encLevel); !wasQueued {
+ break
+ }
+ var err error
+ packet, err = c.packer.PackPTOProbePacket(encLevel, c.maxPacketSize(), false, now, c.version)
+ if err != nil {
+ return err
+ }
+ }
+ if packet == nil {
+ var err error
+ packet, err = c.packer.PackPTOProbePacket(encLevel, c.maxPacketSize(), true, now, c.version)
+ if err != nil {
+ return err
+ }
+ }
+ if packet == nil || (len(packet.longHdrPackets) == 0 && packet.shortHdrPacket == nil) {
+ return fmt.Errorf("connection BUG: couldn't pack %s probe packet: %v", encLevel, packet)
+ }
+ return c.sendPackedCoalescedPacket(packet, c.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now)
+}
+
+// appendOneShortHeaderPacket appends a new packet to the given packetBuffer.
+// If there was nothing to pack, the returned size is 0.
+func (c *Conn) appendOneShortHeaderPacket(buf *packetBuffer, maxSize protocol.ByteCount, ecn protocol.ECN, now monotime.Time) (protocol.ByteCount, error) {
+ startLen := buf.Len()
+ p, err := c.packer.AppendPacket(buf, maxSize, now, c.version)
+ if err != nil {
+ return 0, err
+ }
+ size := buf.Len() - startLen
+ c.logShortHeaderPacket(p, ecn, size)
+ c.registerPackedShortHeaderPacket(p, ecn, now)
+ return size, nil
+}
+
+func (c *Conn) registerPackedShortHeaderPacket(p shortHeaderPacket, ecn protocol.ECN, now monotime.Time) {
+ if p.IsPathProbePacket {
+ c.sentPacketHandler.SentPacket(
+ now,
+ p.PacketNumber,
+ protocol.InvalidPacketNumber,
+ p.StreamFrames,
+ p.Frames,
+ protocol.Encryption1RTT,
+ ecn,
+ p.Length,
+ p.IsPathMTUProbePacket,
+ true,
+ )
+ return
+ }
+ if c.firstAckElicitingPacketAfterIdleSentTime.IsZero() && (len(p.StreamFrames) > 0 || ackhandler.HasAckElicitingFrames(p.Frames)) {
+ c.firstAckElicitingPacketAfterIdleSentTime = now
+ }
+
+ largestAcked := protocol.InvalidPacketNumber
+ if p.Ack != nil {
+ largestAcked = p.Ack.LargestAcked()
+ }
+ c.sentPacketHandler.SentPacket(
+ now,
+ p.PacketNumber,
+ largestAcked,
+ p.StreamFrames,
+ p.Frames,
+ protocol.Encryption1RTT,
+ ecn,
+ p.Length,
+ p.IsPathMTUProbePacket,
+ false,
+ )
+ c.connIDManager.SentPacket()
+}
+
+func (c *Conn) sendPackedCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN, now monotime.Time) error {
+ c.logCoalescedPacket(packet, ecn)
+ for _, p := range packet.longHdrPackets {
+ if c.firstAckElicitingPacketAfterIdleSentTime.IsZero() && p.IsAckEliciting() {
+ c.firstAckElicitingPacketAfterIdleSentTime = now
+ }
+ largestAcked := protocol.InvalidPacketNumber
+ if p.ack != nil {
+ largestAcked = p.ack.LargestAcked()
+ }
+ c.sentPacketHandler.SentPacket(
+ now,
+ p.header.PacketNumber,
+ largestAcked,
+ p.streamFrames,
+ p.frames,
+ p.EncryptionLevel(),
+ ecn,
+ p.length,
+ false,
+ false,
+ )
+ if c.perspective == protocol.PerspectiveClient && p.EncryptionLevel() == protocol.EncryptionHandshake &&
+ !c.droppedInitialKeys {
+ // On the client side, Initial keys are dropped as soon as the first Handshake packet is sent.
+ // See Section 4.9.1 of RFC 9001.
+ if err := c.dropEncryptionLevel(protocol.EncryptionInitial, now); err != nil {
+ return err
+ }
+ }
+ }
+ if p := packet.shortHdrPacket; p != nil {
+ if c.firstAckElicitingPacketAfterIdleSentTime.IsZero() && p.IsAckEliciting() {
+ c.firstAckElicitingPacketAfterIdleSentTime = now
+ }
+ largestAcked := protocol.InvalidPacketNumber
+ if p.Ack != nil {
+ largestAcked = p.Ack.LargestAcked()
+ }
+ c.sentPacketHandler.SentPacket(
+ now,
+ p.PacketNumber,
+ largestAcked,
+ p.StreamFrames,
+ p.Frames,
+ protocol.Encryption1RTT,
+ ecn,
+ p.Length,
+ p.IsPathMTUProbePacket,
+ false,
+ )
+ }
+ c.connIDManager.SentPacket()
+ c.sendQueue.Send(packet.buffer, 0, ecn)
+ return nil
+}
+
+func (c *Conn) sendConnectionClose(e error) ([]byte, error) {
+ var packet *coalescedPacket
+ var err error
+ var transportErr *qerr.TransportError
+ var applicationErr *qerr.ApplicationError
+ if errors.As(e, &transportErr) {
+ packet, err = c.packer.PackConnectionClose(transportErr, c.maxPacketSize(), c.version)
+ } else if errors.As(e, &applicationErr) {
+ packet, err = c.packer.PackApplicationClose(applicationErr, c.maxPacketSize(), c.version)
+ } else {
+ packet, err = c.packer.PackConnectionClose(&qerr.TransportError{
+ ErrorCode: qerr.InternalError,
+ ErrorMessage: fmt.Sprintf("connection BUG: unspecified error type (msg: %s)", e.Error()),
+ }, c.maxPacketSize(), c.version)
+ }
+ if err != nil {
+ return nil, err
+ }
+ ecn := c.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket())
+ c.logCoalescedPacket(packet, ecn)
+ return packet.buffer.Data, c.conn.Write(packet.buffer.Data, 0, ecn)
+}
+
+func (c *Conn) maxPacketSize() protocol.ByteCount {
+ if c.mtuDiscoverer == nil {
+ // Use the configured packet size on the client side.
+ // If the server sends a max_udp_payload_size that's smaller than this size, we can ignore this:
+ // Apparently the server still processed the (fully padded) Initial packet anyway.
+ if c.perspective == protocol.PerspectiveClient {
+ return protocol.ByteCount(c.config.InitialPacketSize)
+ }
+ // On the server side, there's no downside to using 1200 bytes until we received the client's transport
+ // parameters:
+ // * If the first packet didn't contain the entire ClientHello, all we can do is ACK that packet. We don't
+ // need a lot of bytes for that.
+ // * If it did, we will have processed the transport parameters and initialized the MTU discoverer.
+ return protocol.MinInitialPacketSize
+ }
+ return c.mtuDiscoverer.CurrentSize()
+}
+
+// AcceptStream returns the next stream opened by the peer, blocking until one is available.
+func (c *Conn) AcceptStream(ctx context.Context) (*Stream, error) {
+ return c.streamsMap.AcceptStream(ctx)
+}
+
+// AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available.
+func (c *Conn) AcceptUniStream(ctx context.Context) (*ReceiveStream, error) {
+ return c.streamsMap.AcceptUniStream(ctx)
+}
+
+// OpenStream opens a new bidirectional QUIC stream.
+// There is no signaling to the peer about new streams:
+// The peer can only accept the stream after data has been sent on the stream,
+// or the stream has been reset or closed.
+// When reaching the peer's stream limit, it is not possible to open a new stream until the
+// peer raises the stream limit. In that case, a [StreamLimitReachedError] is returned.
+func (c *Conn) OpenStream() (*Stream, error) {
+ return c.streamsMap.OpenStream()
+}
+
+// OpenStreamSync opens a new bidirectional QUIC stream.
+// It blocks until a new stream can be opened.
+// There is no signaling to the peer about new streams:
+// The peer can only accept the stream after data has been sent on the stream,
+// or the stream has been reset or closed.
+func (c *Conn) OpenStreamSync(ctx context.Context) (*Stream, error) {
+ return c.streamsMap.OpenStreamSync(ctx)
+}
+
+// OpenUniStream opens a new outgoing unidirectional QUIC stream.
+// There is no signaling to the peer about new streams:
+// The peer can only accept the stream after data has been sent on the stream,
+// or the stream has been reset or closed.
+// When reaching the peer's stream limit, it is not possible to open a new stream until the
+// peer raises the stream limit. In that case, a [StreamLimitReachedError] is returned.
+func (c *Conn) OpenUniStream() (*SendStream, error) {
+ return c.streamsMap.OpenUniStream()
+}
+
+// OpenUniStreamSync opens a new outgoing unidirectional QUIC stream.
+// It blocks until a new stream can be opened.
+// There is no signaling to the peer about new streams:
+// The peer can only accept the stream after data has been sent on the stream,
+// or the stream has been reset or closed.
+func (c *Conn) OpenUniStreamSync(ctx context.Context) (*SendStream, error) {
+ return c.streamsMap.OpenUniStreamSync(ctx)
+}
+
+func (c *Conn) newFlowController(id protocol.StreamID) flowcontrol.StreamFlowController {
+ initialSendWindow := c.peerParams.InitialMaxStreamDataUni
+ if id.Type() == protocol.StreamTypeBidi {
+ if id.InitiatedBy() == c.perspective {
+ initialSendWindow = c.peerParams.InitialMaxStreamDataBidiRemote
+ } else {
+ initialSendWindow = c.peerParams.InitialMaxStreamDataBidiLocal
+ }
+ }
+ return flowcontrol.NewStreamFlowController(
+ id,
+ c.connFlowController,
+ protocol.ByteCount(c.config.InitialStreamReceiveWindow),
+ protocol.ByteCount(c.config.MaxStreamReceiveWindow),
+ initialSendWindow,
+ c.rttStats,
+ c.logger,
+ )
+}
+
+// scheduleSending signals that we have data for sending
+func (c *Conn) scheduleSending() {
+ select {
+ case c.sendingScheduled <- struct{}{}:
+ default:
+ }
+}
+
+// tryQueueingUndecryptablePacket queues a packet for which we're missing the decryption keys.
+// The qlogevents.PacketType is only used for logging purposes.
+func (c *Conn) tryQueueingUndecryptablePacket(p receivedPacket, pt qlog.PacketType, datagramID qlog.DatagramID) {
+ if c.handshakeComplete {
+ panic("shouldn't queue undecryptable packets after handshake completion")
+ }
+ if len(c.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets {
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
+ }
+ c.logger.Infof("Dropping undecryptable packet (%d bytes). Undecryptable packet queue full.", p.Size())
+ return
+ }
+ c.logger.Infof("Queueing packet (%d bytes) for later decryption", p.Size())
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketBuffered{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ })
+ }
+ c.undecryptablePackets = append(c.undecryptablePackets, receivedPacketWithDatagramID{receivedPacket: p, datagramID: datagramID})
+}
+
+func (c *Conn) queueControlFrame(f wire.Frame) {
+ c.framer.QueueControlFrame(f)
+ c.scheduleSending()
+}
+
+func (c *Conn) onHasConnectionData() { c.scheduleSending() }
+
+func (c *Conn) onHasStreamData(id protocol.StreamID, str *SendStream) {
+ c.framer.AddActiveStream(id, str)
+ c.scheduleSending()
+}
+
+func (c *Conn) onHasStreamControlFrame(id protocol.StreamID, str streamControlFrameGetter) {
+ c.framer.AddStreamWithControlFrames(id, str)
+ c.scheduleSending()
+}
+
+func (c *Conn) onStreamCompleted(id protocol.StreamID) {
+ if err := c.streamsMap.DeleteStream(id); err != nil {
+ c.closeLocal(err)
+ }
+ c.framer.RemoveActiveStream(id)
+}
+
+// SendDatagram sends a message using a QUIC datagram, as specified in RFC 9221,
+// if the peer enabled datagram support.
+// There is no delivery guarantee for DATAGRAM frames, they are not retransmitted if lost.
+// The payload of the datagram needs to fit into a single QUIC packet.
+// In addition, a datagram may be dropped before being sent out if the available packet size suddenly decreases.
+// If the payload is too large to be sent at the current time, a DatagramTooLargeError is returned.
+func (c *Conn) SendDatagram(p []byte) error {
+ if !c.supportsDatagrams() {
+ return errors.New("datagram support disabled")
+ }
+
+ f := &wire.DatagramFrame{DataLenPresent: true}
+ // The payload size estimate is conservative.
+ // Under many circumstances we could send a few more bytes.
+ maxDataLen := min(
+ f.MaxDataLen(c.peerParams.MaxDatagramFrameSize, c.version),
+ protocol.ByteCount(c.maxPayloadSizeEstimate.Load()),
+ )
+ if protocol.ByteCount(len(p)) > maxDataLen {
+ return &DatagramTooLargeError{MaxDatagramPayloadSize: int64(maxDataLen)}
+ }
+ f.Data = make([]byte, len(p))
+ copy(f.Data, p)
+ return c.datagramQueue.Add(f)
+}
+
+// ReceiveDatagram gets a message received in a QUIC datagram, as specified in RFC 9221.
+func (c *Conn) ReceiveDatagram(ctx context.Context) ([]byte, error) {
+ if !c.config.EnableDatagrams {
+ return nil, errors.New("datagram support disabled")
+ }
+ return c.datagramQueue.Receive(ctx)
+}
+
+// LocalAddr returns the local address of the QUIC connection.
+func (c *Conn) LocalAddr() net.Addr { return c.conn.LocalAddr() }
+
+// RemoteAddr returns the remote address of the QUIC connection.
+func (c *Conn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() }
+
+// getPathManager lazily initializes the Conn's pathManagerOutgoing.
+// May create multiple pathManagerOutgoing objects if called concurrently.
+func (c *Conn) getPathManager() *pathManagerOutgoing {
+ old := c.pathManagerOutgoing.Load()
+ if old != nil {
+ // Path manager is already initialized
+ return old
+ }
+
+ // Initialize the path manager
+ new := newPathManagerOutgoing(
+ c.connIDManager.GetConnIDForPath,
+ c.connIDManager.RetireConnIDForPath,
+ c.scheduleSending,
+ )
+ if c.pathManagerOutgoing.CompareAndSwap(old, new) {
+ return new
+ }
+
+ // Swap failed. A concurrent writer wrote first, use their value.
+ return c.pathManagerOutgoing.Load()
+}
+
+func (c *Conn) AddPath(t *Transport) (*Path, error) {
+ if c.perspective == protocol.PerspectiveServer {
+ return nil, errors.New("server cannot initiate connection migration")
+ }
+ if c.peerParams.DisableActiveMigration {
+ return nil, errors.New("server disabled connection migration")
+ }
+ if err := t.init(false); err != nil {
+ return nil, err
+ }
+ return c.getPathManager().NewPath(
+ t,
+ 200*time.Millisecond, // initial RTT estimate
+ func() {
+ runner := (*packetHandlerMap)(t)
+ c.connIDGenerator.AddConnRunner(
+ runner,
+ connRunnerCallbacks{
+ AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, c) },
+ RemoveConnectionID: runner.Remove,
+ ReplaceWithClosed: runner.ReplaceWithClosed,
+ },
+ )
+ },
+ ), nil
+}
+
+// HandshakeComplete blocks until the handshake completes (or fails).
+// For the client, data sent before completion of the handshake is encrypted with 0-RTT keys.
+// For the server, data sent before completion of the handshake is encrypted with 1-RTT keys,
+// however the client's identity is only verified once the handshake completes.
+func (c *Conn) HandshakeComplete() <-chan struct{} {
+ return c.handshakeCompleteChan
+}
+
+// QlogTrace returns the qlog trace of the QUIC connection.
+// It is nil if qlog is not enabled.
+func (c *Conn) QlogTrace() qlogwriter.Trace {
+ return c.qlogTrace
+}
+
+// NextConnection transitions a connection to be usable after a 0-RTT rejection.
+// It waits for the handshake to complete and then enables the connection for normal use.
+// This should be called when the server rejects 0-RTT and the application receives
+// [Err0RTTRejected] errors.
+//
+// Note that 0-RTT rejection invalidates all data sent in 0-RTT packets. It is the
+// application's responsibility to handle this (for example by resending the data).
+func (c *Conn) NextConnection(ctx context.Context) (*Conn, error) {
+ // The handshake might fail after the server rejected 0-RTT.
+ // This could happen if the Finished message is malformed or never received.
+ select {
+ case <-ctx.Done():
+ return nil, context.Cause(ctx)
+ case <-c.Context().Done():
+ case <-c.HandshakeComplete():
+ c.streamsMap.UseResetMaps()
+ }
+ return c, nil
+}
+
+// estimateMaxPayloadSize estimates the maximum payload size for short header packets.
+// It is not very sophisticated: it just subtracts the size of header (assuming the maximum
+// connection ID length), and the size of the encryption tag.
+func estimateMaxPayloadSize(mtu protocol.ByteCount) protocol.ByteCount {
+ return mtu - 1 /* type byte */ - 20 /* maximum connection ID length */ - 16 /* tag size */
+}
diff --git a/vendor/github.com/quic-go/quic-go/connection_logging.go b/vendor/github.com/quic-go/quic-go/connection_logging.go
new file mode 100644
index 00000000..c828c8be
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/connection_logging.go
@@ -0,0 +1,315 @@
+package quic
+
+import (
+ "net"
+ "net/netip"
+ "slices"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlog"
+)
+
+// ConvertFrame converts a wire.Frame into a logging.Frame.
+// This makes it possible for external packages to access the frames.
+// Furthermore, it removes the data slices from CRYPTO and STREAM frames.
+func toQlogFrame(frame wire.Frame) qlog.Frame {
+ switch f := frame.(type) {
+ case *wire.AckFrame:
+ // We use a pool for ACK frames.
+ // Implementations of the tracer interface may hold on to frames, so we need to make a copy here.
+ return qlog.Frame{Frame: toQlogAckFrame(f)}
+ case *wire.CryptoFrame:
+ return qlog.Frame{
+ Frame: &qlog.CryptoFrame{
+ Offset: int64(f.Offset),
+ Length: int64(len(f.Data)),
+ },
+ }
+ case *wire.StreamFrame:
+ return qlog.Frame{
+ Frame: &qlog.StreamFrame{
+ StreamID: f.StreamID,
+ Offset: int64(f.Offset),
+ Length: int64(f.DataLen()),
+ Fin: f.Fin,
+ },
+ }
+ case *wire.DatagramFrame:
+ return qlog.Frame{
+ Frame: &qlog.DatagramFrame{
+ Length: int64(len(f.Data)),
+ },
+ }
+ default:
+ return qlog.Frame{Frame: frame}
+ }
+}
+
+func toQlogAckFrame(f *wire.AckFrame) *qlog.AckFrame {
+ ack := &qlog.AckFrame{
+ AckRanges: slices.Clone(f.AckRanges),
+ DelayTime: f.DelayTime,
+ ECNCE: f.ECNCE,
+ ECT0: f.ECT0,
+ ECT1: f.ECT1,
+ }
+ return ack
+}
+
+func (c *Conn) logLongHeaderPacket(p *longHeaderPacket, ecn protocol.ECN, datagramID qlog.DatagramID) {
+ // quic-go logging
+ if c.logger.Debug() {
+ p.header.Log(c.logger)
+ if p.ack != nil {
+ wire.LogFrame(c.logger, p.ack, true)
+ }
+ for _, frame := range p.frames {
+ wire.LogFrame(c.logger, frame.Frame, true)
+ }
+ for _, frame := range p.streamFrames {
+ wire.LogFrame(c.logger, frame.Frame, true)
+ }
+ }
+
+ // tracing
+ if c.qlogger != nil {
+ numFrames := len(p.frames) + len(p.streamFrames)
+ if p.ack != nil {
+ numFrames++
+ }
+ frames := make([]qlog.Frame, 0, numFrames)
+ if p.ack != nil {
+ frames = append(frames, toQlogFrame(p.ack))
+ }
+ for _, f := range p.frames {
+ frames = append(frames, toQlogFrame(f.Frame))
+ }
+ for _, f := range p.streamFrames {
+ frames = append(frames, toQlogFrame(f.Frame))
+ }
+ c.qlogger.RecordEvent(qlog.PacketSent{
+ Header: qlog.PacketHeader{
+ PacketType: toQlogPacketType(p.header.Type),
+ KeyPhaseBit: p.header.KeyPhase,
+ PacketNumber: p.header.PacketNumber,
+ Version: p.header.Version,
+ SrcConnectionID: p.header.SrcConnectionID,
+ DestConnectionID: p.header.DestConnectionID,
+ },
+ Raw: qlog.RawInfo{
+ Length: int(p.length),
+ PayloadLength: int(p.header.Length),
+ },
+ DatagramID: datagramID,
+ Frames: frames,
+ ECN: toQlogECN(ecn),
+ })
+ }
+}
+
+func (c *Conn) logShortHeaderPacket(p shortHeaderPacket, ecn protocol.ECN, size protocol.ByteCount) {
+ c.logShortHeaderPacketWithDatagramID(p, ecn, size, false, 0)
+}
+
+func (c *Conn) logShortHeaderPacketWithDatagramID(p shortHeaderPacket, ecn protocol.ECN, size protocol.ByteCount, isCoalesced bool, datagramID qlog.DatagramID) {
+ if c.logger.Debug() && !isCoalesced {
+ c.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, 1-RTT (ECN: %s)", p.PacketNumber, size, c.logID, ecn)
+ }
+ // quic-go logging
+ if c.logger.Debug() {
+ wire.LogShortHeader(c.logger, p.DestConnID, p.PacketNumber, p.PacketNumberLen, p.KeyPhase)
+ if p.Ack != nil {
+ wire.LogFrame(c.logger, p.Ack, true)
+ }
+ for _, f := range p.Frames {
+ wire.LogFrame(c.logger, f.Frame, true)
+ }
+ for _, f := range p.StreamFrames {
+ wire.LogFrame(c.logger, f.Frame, true)
+ }
+ }
+
+ // tracing
+ if c.qlogger != nil {
+ numFrames := len(p.Frames) + len(p.StreamFrames)
+ if p.Ack != nil {
+ numFrames++
+ }
+ fs := make([]qlog.Frame, 0, numFrames)
+ if p.Ack != nil {
+ fs = append(fs, toQlogFrame(p.Ack))
+ }
+ for _, f := range p.Frames {
+ fs = append(fs, toQlogFrame(f.Frame))
+ }
+ for _, f := range p.StreamFrames {
+ fs = append(fs, toQlogFrame(f.Frame))
+ }
+ c.qlogger.RecordEvent(qlog.PacketSent{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
+ KeyPhaseBit: p.KeyPhase,
+ PacketNumber: p.PacketNumber,
+ Version: c.version,
+ DestConnectionID: p.DestConnID,
+ },
+ Raw: qlog.RawInfo{
+ Length: int(size),
+ PayloadLength: int(size - wire.ShortHeaderLen(p.DestConnID, p.PacketNumberLen)),
+ },
+ DatagramID: datagramID,
+ Frames: fs,
+ ECN: toQlogECN(ecn),
+ })
+ }
+}
+
+func (c *Conn) logCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN) {
+ var datagramID qlog.DatagramID
+ if c.qlogger != nil {
+ datagramID = qlog.CalculateDatagramID(packet.buffer.Data)
+ }
+ if c.logger.Debug() {
+ // There's a short period between dropping both Initial and Handshake keys and completion of the handshake,
+ // during which we might call PackCoalescedPacket but just pack a short header packet.
+ if len(packet.longHdrPackets) == 0 && packet.shortHdrPacket != nil {
+ c.logShortHeaderPacketWithDatagramID(
+ *packet.shortHdrPacket,
+ ecn,
+ packet.shortHdrPacket.Length,
+ false,
+ datagramID,
+ )
+ return
+ }
+ if len(packet.longHdrPackets) > 1 {
+ c.logger.Debugf("-> Sending coalesced packet (%d parts, %d bytes) for connection %s", len(packet.longHdrPackets), packet.buffer.Len(), c.logID)
+ } else {
+ c.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, %s", packet.longHdrPackets[0].header.PacketNumber, packet.buffer.Len(), c.logID, packet.longHdrPackets[0].EncryptionLevel())
+ }
+ }
+ for _, p := range packet.longHdrPackets {
+ c.logLongHeaderPacket(p, ecn, datagramID)
+ }
+ if p := packet.shortHdrPacket; p != nil {
+ c.logShortHeaderPacketWithDatagramID(*p, ecn, p.Length, true, datagramID)
+ }
+}
+
+func (c *Conn) qlogTransportParameters(tp *wire.TransportParameters, sentBy protocol.Perspective, restore bool) {
+ ev := qlog.ParametersSet{
+ Restore: restore,
+ OriginalDestinationConnectionID: tp.OriginalDestinationConnectionID,
+ InitialSourceConnectionID: tp.InitialSourceConnectionID,
+ RetrySourceConnectionID: tp.RetrySourceConnectionID,
+ StatelessResetToken: tp.StatelessResetToken,
+ DisableActiveMigration: tp.DisableActiveMigration,
+ MaxIdleTimeout: tp.MaxIdleTimeout,
+ MaxUDPPayloadSize: tp.MaxUDPPayloadSize,
+ AckDelayExponent: tp.AckDelayExponent,
+ MaxAckDelay: tp.MaxAckDelay,
+ ActiveConnectionIDLimit: tp.ActiveConnectionIDLimit,
+ InitialMaxData: tp.InitialMaxData,
+ InitialMaxStreamDataBidiLocal: tp.InitialMaxStreamDataBidiLocal,
+ InitialMaxStreamDataBidiRemote: tp.InitialMaxStreamDataBidiRemote,
+ InitialMaxStreamDataUni: tp.InitialMaxStreamDataUni,
+ InitialMaxStreamsBidi: int64(tp.MaxBidiStreamNum),
+ InitialMaxStreamsUni: int64(tp.MaxUniStreamNum),
+ MaxDatagramFrameSize: tp.MaxDatagramFrameSize,
+ EnableResetStreamAt: tp.EnableResetStreamAt,
+ }
+ if sentBy == c.perspective {
+ ev.Initiator = qlog.InitiatorLocal
+ } else {
+ ev.Initiator = qlog.InitiatorRemote
+ }
+ if tp.PreferredAddress != nil {
+ ev.PreferredAddress = &qlog.PreferredAddress{
+ IPv4: tp.PreferredAddress.IPv4,
+ IPv6: tp.PreferredAddress.IPv6,
+ ConnectionID: tp.PreferredAddress.ConnectionID,
+ StatelessResetToken: tp.PreferredAddress.StatelessResetToken,
+ }
+ }
+ c.qlogger.RecordEvent(ev)
+}
+
+func toQlogECN(ecn protocol.ECN) qlog.ECN {
+ //nolint:exhaustive // only need to handle the 3 valid values
+ switch ecn {
+ case protocol.ECT0:
+ return qlog.ECT0
+ case protocol.ECT1:
+ return qlog.ECT1
+ case protocol.ECNCE:
+ return qlog.ECNCE
+ default:
+ return qlog.ECNUnsupported
+ }
+}
+
+func toQlogPacketType(pt protocol.PacketType) qlog.PacketType {
+ var qpt qlog.PacketType
+ switch pt {
+ case protocol.PacketTypeInitial:
+ qpt = qlog.PacketTypeInitial
+ case protocol.PacketTypeHandshake:
+ qpt = qlog.PacketTypeHandshake
+ case protocol.PacketType0RTT:
+ qpt = qlog.PacketType0RTT
+ case protocol.PacketTypeRetry:
+ qpt = qlog.PacketTypeRetry
+ }
+ return qpt
+}
+
+func toPathEndpointInfo(addr *net.UDPAddr) qlog.PathEndpointInfo {
+ if addr == nil {
+ return qlog.PathEndpointInfo{}
+ }
+
+ var info qlog.PathEndpointInfo
+ if addr.IP == nil || addr.IP.To4() != nil {
+ addrPort := netip.AddrPortFrom(netip.AddrFrom4([4]byte(addr.IP.To4())), uint16(addr.Port))
+ if addrPort.IsValid() {
+ info.IPv4 = addrPort
+ }
+ } else {
+ addrPort := netip.AddrPortFrom(netip.AddrFrom16([16]byte(addr.IP.To16())), uint16(addr.Port))
+ if addrPort.IsValid() {
+ info.IPv6 = addrPort
+ }
+ }
+ return info
+}
+
+// startedConnectionEvent builds a StartedConnection event using consistent logic
+// for both endpoints. If the local address is unspecified (e.g., dual-stack
+// listener), it selects the family based on the remote address and uses the
+// unspecified address of that family with the local port.
+func startedConnectionEvent(local, remote *net.UDPAddr) qlog.StartedConnection {
+ var localInfo, remoteInfo qlog.PathEndpointInfo
+ if remote != nil {
+ remoteInfo = toPathEndpointInfo(remote)
+ }
+ if local != nil {
+ if local.IP == nil || local.IP.IsUnspecified() {
+ // Choose local family based on the remote address family.
+ if remote != nil && remote.IP.To4() != nil {
+ ap := netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), uint16(local.Port))
+ if ap.IsValid() {
+ localInfo.IPv4 = ap
+ }
+ } else if remote != nil && remote.IP.To16() != nil && remote.IP.To4() == nil {
+ ap := netip.AddrPortFrom(netip.AddrFrom16([16]byte{}), uint16(local.Port))
+ if ap.IsValid() {
+ localInfo.IPv6 = ap
+ }
+ }
+ } else {
+ localInfo = toPathEndpointInfo(local)
+ }
+ }
+ return qlog.StartedConnection{Local: localInfo, Remote: remoteInfo}
+}
diff --git a/vendor/github.com/quic-go/quic-go/crypto_stream.go b/vendor/github.com/quic-go/quic-go/crypto_stream.go
new file mode 100644
index 00000000..6d39aa09
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/crypto_stream.go
@@ -0,0 +1,249 @@
+package quic
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "slices"
+ "strconv"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+const disableClientHelloScramblingEnv = "QUIC_GO_DISABLE_CLIENTHELLO_SCRAMBLING"
+
+// The baseCryptoStream is used by the cryptoStream and the initialCryptoStream.
+// This allows us to implement different logic for PopCryptoFrame for the two streams.
+type baseCryptoStream struct {
+ queue frameSorter
+
+ highestOffset protocol.ByteCount
+ finished bool
+
+ writeOffset protocol.ByteCount
+ writeBuf []byte
+}
+
+func newCryptoStream() *cryptoStream {
+ return &cryptoStream{baseCryptoStream{queue: *newFrameSorter()}}
+}
+
+func (s *baseCryptoStream) HandleCryptoFrame(f *wire.CryptoFrame) error {
+ highestOffset := f.Offset + protocol.ByteCount(len(f.Data))
+ if maxOffset := highestOffset; maxOffset > protocol.MaxCryptoStreamOffset {
+ return &qerr.TransportError{
+ ErrorCode: qerr.CryptoBufferExceeded,
+ ErrorMessage: fmt.Sprintf("received invalid offset %d on crypto stream, maximum allowed %d", maxOffset, protocol.MaxCryptoStreamOffset),
+ }
+ }
+ if s.finished {
+ if highestOffset > s.highestOffset {
+ // reject crypto data received after this stream was already finished
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "received crypto data after change of encryption level",
+ }
+ }
+ // ignore data with a smaller offset than the highest received
+ // could e.g. be a retransmission
+ return nil
+ }
+ s.highestOffset = max(s.highestOffset, highestOffset)
+ return s.queue.Push(f.Data, f.Offset, nil)
+}
+
+// GetCryptoData retrieves data that was received in CRYPTO frames
+func (s *baseCryptoStream) GetCryptoData() []byte {
+ _, data, _ := s.queue.Pop()
+ return data
+}
+
+func (s *baseCryptoStream) Finish() error {
+ if s.queue.HasMoreData() {
+ return &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "encryption level changed, but crypto stream has more data to read",
+ }
+ }
+ s.finished = true
+ return nil
+}
+
+// Writes writes data that should be sent out in CRYPTO frames
+func (s *baseCryptoStream) Write(p []byte) (int, error) {
+ s.writeBuf = append(s.writeBuf, p...)
+ return len(p), nil
+}
+
+func (s *baseCryptoStream) HasData() bool {
+ return len(s.writeBuf) > 0
+}
+
+func (s *baseCryptoStream) PopCryptoFrame(maxLen protocol.ByteCount) *wire.CryptoFrame {
+ f := &wire.CryptoFrame{Offset: s.writeOffset}
+ n := min(f.MaxDataLen(maxLen), protocol.ByteCount(len(s.writeBuf)))
+ if n <= 0 {
+ return nil
+ }
+ f.Data = s.writeBuf[:n]
+ s.writeBuf = s.writeBuf[n:]
+ s.writeOffset += n
+ return f
+}
+
+type cryptoStream struct {
+ baseCryptoStream
+}
+
+type clientHelloCut struct {
+ start protocol.ByteCount
+ end protocol.ByteCount
+}
+
+type initialCryptoStream struct {
+ baseCryptoStream
+
+ scramble bool
+ end protocol.ByteCount
+ cuts [2]clientHelloCut
+}
+
+func newInitialCryptoStream(isClient bool) *initialCryptoStream {
+ var scramble bool
+ if isClient {
+ disabled, err := strconv.ParseBool(os.Getenv(disableClientHelloScramblingEnv))
+ scramble = err != nil || !disabled
+ }
+ s := &initialCryptoStream{
+ baseCryptoStream: baseCryptoStream{queue: *newFrameSorter()},
+ scramble: scramble,
+ }
+ for i := range len(s.cuts) {
+ s.cuts[i].start = protocol.InvalidByteCount
+ s.cuts[i].end = protocol.InvalidByteCount
+ }
+ return s
+}
+
+func (s *initialCryptoStream) HasData() bool {
+ // The ClientHello might be written in multiple parts.
+ // In order to correctly split the ClientHello, we need the entire ClientHello has been queued.
+ if s.scramble && s.writeOffset == 0 && s.cuts[0].start == protocol.InvalidByteCount {
+ return false
+ }
+ return s.baseCryptoStream.HasData()
+}
+
+func (s *initialCryptoStream) Write(p []byte) (int, error) {
+ s.writeBuf = append(s.writeBuf, p...)
+ if !s.scramble {
+ return len(p), nil
+ }
+ if s.cuts[0].start == protocol.InvalidByteCount {
+ sniPos, sniLen, echPos, err := findSNIAndECH(s.writeBuf)
+ if errors.Is(err, io.ErrUnexpectedEOF) {
+ return len(p), nil
+ }
+ if err != nil {
+ return len(p), err
+ }
+ if sniPos == -1 && echPos == -1 {
+ // Neither SNI nor ECH found.
+ // There's nothing to scramble.
+ s.scramble = false
+ return len(p), nil
+ }
+ s.end = protocol.ByteCount(len(s.writeBuf))
+ s.cuts[0].start = protocol.ByteCount(sniPos + sniLen/2) // right in the middle
+ s.cuts[0].end = protocol.ByteCount(sniPos + sniLen)
+ if echPos > 0 {
+ // ECH extension found, cut the ECH extension type value (a uint16) in half
+ start := protocol.ByteCount(echPos + 1)
+ s.cuts[1].start = start
+ // cut somewhere (16 bytes), most likely in the ECH extension value
+ s.cuts[1].end = min(start+16, s.end)
+ }
+ slices.SortFunc(s.cuts[:], func(a, b clientHelloCut) int {
+ if a.start == protocol.InvalidByteCount {
+ return 1
+ }
+ if a.start > b.start {
+ return 1
+ }
+ return -1
+ })
+ }
+ return len(p), nil
+}
+
+func (s *initialCryptoStream) PopCryptoFrame(maxLen protocol.ByteCount) *wire.CryptoFrame {
+ if !s.scramble {
+ return s.baseCryptoStream.PopCryptoFrame(maxLen)
+ }
+
+ // send out the skipped parts
+ if s.writeOffset == s.end {
+ var foundCuts bool
+ var f *wire.CryptoFrame
+ for i, c := range s.cuts {
+ if c.start == protocol.InvalidByteCount {
+ continue
+ }
+ foundCuts = true
+ if f != nil {
+ break
+ }
+ f = &wire.CryptoFrame{Offset: c.start}
+ n := min(f.MaxDataLen(maxLen), c.end-c.start)
+ if n <= 0 {
+ return nil
+ }
+ f.Data = s.writeBuf[c.start : c.start+n]
+ s.cuts[i].start += n
+ if s.cuts[i].start == c.end {
+ s.cuts[i].start = protocol.InvalidByteCount
+ s.cuts[i].end = protocol.InvalidByteCount
+ foundCuts = false
+ }
+ }
+ if !foundCuts {
+ // no more cuts found, we're done sending out everything up until s.end
+ s.writeBuf = s.writeBuf[s.end:]
+ s.end = protocol.InvalidByteCount
+ s.scramble = false
+ }
+ return f
+ }
+
+ nextCut := clientHelloCut{start: protocol.InvalidByteCount, end: protocol.InvalidByteCount}
+ for _, c := range s.cuts {
+ if c.start == protocol.InvalidByteCount {
+ continue
+ }
+ if c.start > s.writeOffset {
+ nextCut = c
+ break
+ }
+ }
+ f := &wire.CryptoFrame{Offset: s.writeOffset}
+ maxOffset := nextCut.start
+ if maxOffset == protocol.InvalidByteCount {
+ maxOffset = s.end
+ }
+ n := min(f.MaxDataLen(maxLen), maxOffset-s.writeOffset)
+ if n <= 0 {
+ return nil
+ }
+ f.Data = s.writeBuf[s.writeOffset : s.writeOffset+n]
+ // Don't reslice the writeBuf yet.
+ // This is done once all parts have been sent out.
+ s.writeOffset += n
+ if s.writeOffset == nextCut.start {
+ s.writeOffset = nextCut.end
+ }
+
+ return f
+}
diff --git a/vendor/github.com/quic-go/quic-go/crypto_stream_manager.go b/vendor/github.com/quic-go/quic-go/crypto_stream_manager.go
new file mode 100644
index 00000000..1e7dbf74
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/crypto_stream_manager.go
@@ -0,0 +1,73 @@
+package quic
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type cryptoStreamManager struct {
+ initialStream *initialCryptoStream
+ handshakeStream *cryptoStream
+ oneRTTStream *cryptoStream
+}
+
+func newCryptoStreamManager(
+ initialStream *initialCryptoStream,
+ handshakeStream *cryptoStream,
+ oneRTTStream *cryptoStream,
+) *cryptoStreamManager {
+ return &cryptoStreamManager{
+ initialStream: initialStream,
+ handshakeStream: handshakeStream,
+ oneRTTStream: oneRTTStream,
+ }
+}
+
+func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) error {
+ //nolint:exhaustive // CRYPTO frames cannot be sent in 0-RTT packets.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return m.initialStream.HandleCryptoFrame(frame)
+ case protocol.EncryptionHandshake:
+ return m.handshakeStream.HandleCryptoFrame(frame)
+ case protocol.Encryption1RTT:
+ return m.oneRTTStream.HandleCryptoFrame(frame)
+ default:
+ return fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel)
+ }
+}
+
+func (m *cryptoStreamManager) GetCryptoData(encLevel protocol.EncryptionLevel) []byte {
+ //nolint:exhaustive // CRYPTO frames cannot be sent in 0-RTT packets.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return m.initialStream.GetCryptoData()
+ case protocol.EncryptionHandshake:
+ return m.handshakeStream.GetCryptoData()
+ case protocol.Encryption1RTT:
+ return m.oneRTTStream.GetCryptoData()
+ default:
+ panic(fmt.Sprintf("received CRYPTO frame with unexpected encryption level: %s", encLevel))
+ }
+}
+
+func (m *cryptoStreamManager) GetPostHandshakeData(maxSize protocol.ByteCount) *wire.CryptoFrame {
+ if !m.oneRTTStream.HasData() {
+ return nil
+ }
+ return m.oneRTTStream.PopCryptoFrame(maxSize)
+}
+
+func (m *cryptoStreamManager) Drop(encLevel protocol.EncryptionLevel) error {
+ //nolint:exhaustive // 1-RTT keys should never get dropped.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return m.initialStream.Finish()
+ case protocol.EncryptionHandshake:
+ return m.handshakeStream.Finish()
+ default:
+ panic(fmt.Sprintf("dropped unexpected encryption level: %s", encLevel))
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/datagram_queue.go b/vendor/github.com/quic-go/quic-go/datagram_queue.go
new file mode 100644
index 00000000..e26285b2
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/datagram_queue.go
@@ -0,0 +1,137 @@
+package quic
+
+import (
+ "context"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/utils/ringbuffer"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+const (
+ maxDatagramSendQueueLen = 32
+ maxDatagramRcvQueueLen = 128
+)
+
+type datagramQueue struct {
+ sendMx sync.Mutex
+ sendQueue ringbuffer.RingBuffer[*wire.DatagramFrame]
+ sent chan struct{} // used to notify Add that a datagram was dequeued
+
+ rcvMx sync.Mutex
+ rcvQueue [][]byte
+ rcvd chan struct{} // used to notify Receive that a new datagram was received
+
+ closeErr error
+ closed chan struct{}
+
+ hasData func()
+
+ logger utils.Logger
+}
+
+func newDatagramQueue(hasData func(), logger utils.Logger) *datagramQueue {
+ return &datagramQueue{
+ hasData: hasData,
+ rcvd: make(chan struct{}, 1),
+ sent: make(chan struct{}, 1),
+ closed: make(chan struct{}),
+ logger: logger,
+ }
+}
+
+// Add queues a new DATAGRAM frame for sending.
+// Up to 32 DATAGRAM frames will be queued.
+// Once that limit is reached, Add blocks until the queue size has reduced.
+func (h *datagramQueue) Add(f *wire.DatagramFrame) error {
+ h.sendMx.Lock()
+
+ for {
+ if h.sendQueue.Len() < maxDatagramSendQueueLen {
+ h.sendQueue.PushBack(f)
+ h.sendMx.Unlock()
+ h.hasData()
+ return nil
+ }
+ select {
+ case <-h.sent: // drain the queue so we don't loop immediately
+ default:
+ }
+ h.sendMx.Unlock()
+ select {
+ case <-h.closed:
+ return h.closeErr
+ case <-h.sent:
+ }
+ h.sendMx.Lock()
+ }
+}
+
+// Peek gets the next DATAGRAM frame for sending.
+// If actually sent out, Pop needs to be called before the next call to Peek.
+func (h *datagramQueue) Peek() *wire.DatagramFrame {
+ h.sendMx.Lock()
+ defer h.sendMx.Unlock()
+ if h.sendQueue.Empty() {
+ return nil
+ }
+ return h.sendQueue.PeekFront()
+}
+
+func (h *datagramQueue) Pop() {
+ h.sendMx.Lock()
+ defer h.sendMx.Unlock()
+ _ = h.sendQueue.PopFront()
+ select {
+ case h.sent <- struct{}{}:
+ default:
+ }
+}
+
+// HandleDatagramFrame handles a received DATAGRAM frame.
+func (h *datagramQueue) HandleDatagramFrame(f *wire.DatagramFrame) {
+ data := make([]byte, len(f.Data))
+ copy(data, f.Data)
+ var queued bool
+ h.rcvMx.Lock()
+ if len(h.rcvQueue) < maxDatagramRcvQueueLen {
+ h.rcvQueue = append(h.rcvQueue, data)
+ queued = true
+ select {
+ case h.rcvd <- struct{}{}:
+ default:
+ }
+ }
+ h.rcvMx.Unlock()
+ if !queued && h.logger.Debug() {
+ h.logger.Debugf("Discarding received DATAGRAM frame (%d bytes payload)", len(f.Data))
+ }
+}
+
+// Receive gets a received DATAGRAM frame.
+func (h *datagramQueue) Receive(ctx context.Context) ([]byte, error) {
+ for {
+ h.rcvMx.Lock()
+ if len(h.rcvQueue) > 0 {
+ data := h.rcvQueue[0]
+ h.rcvQueue = h.rcvQueue[1:]
+ h.rcvMx.Unlock()
+ return data, nil
+ }
+ h.rcvMx.Unlock()
+ select {
+ case <-h.rcvd:
+ continue
+ case <-h.closed:
+ return nil, h.closeErr
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ }
+}
+
+func (h *datagramQueue) CloseWithError(e error) {
+ h.closeErr = e
+ close(h.closed)
+}
diff --git a/vendor/github.com/quic-go/quic-go/errors.go b/vendor/github.com/quic-go/quic-go/errors.go
new file mode 100644
index 00000000..829730fe
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/errors.go
@@ -0,0 +1,105 @@
+package quic
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/qerr"
+)
+
+type (
+ // TransportError indicates an error that occurred on the QUIC transport layer.
+ // Every transport error other than CONNECTION_REFUSED and APPLICATION_ERROR is
+ // likely a bug in the implementation.
+ TransportError = qerr.TransportError
+ // ApplicationError is an application-defined error.
+ ApplicationError = qerr.ApplicationError
+ // VersionNegotiationError indicates a failure to negotiate a QUIC version.
+ VersionNegotiationError = qerr.VersionNegotiationError
+ // StatelessResetError indicates a stateless reset was received.
+ // This can happen when the peer reboots, or when packets are misrouted.
+ // See section 10.3 of RFC 9000 for details.
+ StatelessResetError = qerr.StatelessResetError
+ // IdleTimeoutError indicates that the connection timed out because it was inactive for too long.
+ IdleTimeoutError = qerr.IdleTimeoutError
+ // HandshakeTimeoutError indicates that the connection timed out before completing the handshake.
+ HandshakeTimeoutError = qerr.HandshakeTimeoutError
+)
+
+type (
+ // TransportErrorCode is a QUIC transport error code, see section 20 of RFC 9000.
+ TransportErrorCode = qerr.TransportErrorCode
+ // ApplicationErrorCode is an QUIC application error code.
+ ApplicationErrorCode = qerr.ApplicationErrorCode
+ // StreamErrorCode is a QUIC stream error code. The meaning of the value is defined by the application.
+ StreamErrorCode = qerr.StreamErrorCode
+)
+
+const (
+ // NoError is the NO_ERROR transport error code.
+ NoError = qerr.NoError
+ // InternalError is the INTERNAL_ERROR transport error code.
+ InternalError = qerr.InternalError
+ // ConnectionRefused is the CONNECTION_REFUSED transport error code.
+ ConnectionRefused = qerr.ConnectionRefused
+ // FlowControlError is the FLOW_CONTROL_ERROR transport error code.
+ FlowControlError = qerr.FlowControlError
+ // StreamLimitError is the STREAM_LIMIT_ERROR transport error code.
+ StreamLimitError = qerr.StreamLimitError
+ // StreamStateError is the STREAM_STATE_ERROR transport error code.
+ StreamStateError = qerr.StreamStateError
+ // FinalSizeError is the FINAL_SIZE_ERROR transport error code.
+ FinalSizeError = qerr.FinalSizeError
+ // FrameEncodingError is the FRAME_ENCODING_ERROR transport error code.
+ FrameEncodingError = qerr.FrameEncodingError
+ // TransportParameterError is the TRANSPORT_PARAMETER_ERROR transport error code.
+ TransportParameterError = qerr.TransportParameterError
+ // ConnectionIDLimitError is the CONNECTION_ID_LIMIT_ERROR transport error code.
+ ConnectionIDLimitError = qerr.ConnectionIDLimitError
+ // ProtocolViolation is the PROTOCOL_VIOLATION transport error code.
+ ProtocolViolation = qerr.ProtocolViolation
+ // InvalidToken is the INVALID_TOKEN transport error code.
+ InvalidToken = qerr.InvalidToken
+ // ApplicationErrorErrorCode is the APPLICATION_ERROR transport error code.
+ ApplicationErrorErrorCode = qerr.ApplicationErrorErrorCode
+ // CryptoBufferExceeded is the CRYPTO_BUFFER_EXCEEDED transport error code.
+ CryptoBufferExceeded = qerr.CryptoBufferExceeded
+ // KeyUpdateError is the KEY_UPDATE_ERROR transport error code.
+ KeyUpdateError = qerr.KeyUpdateError
+ // AEADLimitReached is the AEAD_LIMIT_REACHED transport error code.
+ AEADLimitReached = qerr.AEADLimitReached
+ // NoViablePathError is the NO_VIABLE_PATH_ERROR transport error code.
+ NoViablePathError = qerr.NoViablePathError
+)
+
+// A StreamError is used to signal stream cancellations.
+// It is returned from the Read and Write methods of the [ReceiveStream], [SendStream] and [Stream].
+type StreamError struct {
+ StreamID StreamID
+ ErrorCode StreamErrorCode
+ Remote bool
+}
+
+func (e *StreamError) Is(target error) bool {
+ t, ok := target.(*StreamError)
+ return ok && e.StreamID == t.StreamID && e.ErrorCode == t.ErrorCode && e.Remote == t.Remote
+}
+
+func (e *StreamError) Error() string {
+ pers := "local"
+ if e.Remote {
+ pers = "remote"
+ }
+ return fmt.Sprintf("stream %d canceled by %s with error code %d", e.StreamID, pers, e.ErrorCode)
+}
+
+// DatagramTooLargeError is returned from Conn.SendDatagram if the payload is too large to be sent.
+type DatagramTooLargeError struct {
+ MaxDatagramPayloadSize int64
+}
+
+func (e *DatagramTooLargeError) Is(target error) bool {
+ t, ok := target.(*DatagramTooLargeError)
+ return ok && e.MaxDatagramPayloadSize == t.MaxDatagramPayloadSize
+}
+
+func (e *DatagramTooLargeError) Error() string { return "DATAGRAM frame too large" }
diff --git a/vendor/github.com/quic-go/quic-go/frame_sorter.go b/vendor/github.com/quic-go/quic-go/frame_sorter.go
new file mode 100644
index 00000000..20c6d9cc
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/frame_sorter.go
@@ -0,0 +1,274 @@
+package quic
+
+import (
+ "errors"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ list "github.com/quic-go/quic-go/internal/utils/linkedlist"
+)
+
+// byteInterval is an interval from one ByteCount to the other
+type byteInterval struct {
+ Start protocol.ByteCount
+ End protocol.ByteCount
+}
+
+var byteIntervalElementPool sync.Pool
+
+func init() {
+ byteIntervalElementPool = *list.NewPool[byteInterval]()
+}
+
+type frameSorterEntry struct {
+ Data []byte
+ DoneCb func()
+}
+
+type frameSorter struct {
+ queue map[protocol.ByteCount]frameSorterEntry
+ readPos protocol.ByteCount
+ gaps *list.List[byteInterval]
+}
+
+var errDuplicateStreamData = errors.New("duplicate stream data")
+
+func newFrameSorter() *frameSorter {
+ s := frameSorter{
+ gaps: list.NewWithPool[byteInterval](&byteIntervalElementPool),
+ queue: make(map[protocol.ByteCount]frameSorterEntry),
+ }
+ s.gaps.PushFront(byteInterval{Start: 0, End: protocol.MaxByteCount})
+ return &s
+}
+
+func (s *frameSorter) Push(data []byte, offset protocol.ByteCount, doneCb func()) error {
+ err := s.push(data, offset, doneCb)
+ if err == errDuplicateStreamData {
+ if doneCb != nil {
+ doneCb()
+ }
+ return nil
+ }
+ return err
+}
+
+func (s *frameSorter) push(data []byte, offset protocol.ByteCount, doneCb func()) error {
+ if len(data) == 0 {
+ return errDuplicateStreamData
+ }
+
+ start := offset
+ end := offset + protocol.ByteCount(len(data))
+
+ if end <= s.gaps.Front().Value.Start {
+ return errDuplicateStreamData
+ }
+
+ startGap, startsInGap := s.findStartGap(start)
+ endGap, endsInGap := s.findEndGap(startGap, end)
+
+ startGapEqualsEndGap := startGap == endGap
+
+ if (startGapEqualsEndGap && end <= startGap.Value.Start) ||
+ (!startGapEqualsEndGap && startGap.Value.End >= endGap.Value.Start && end <= startGap.Value.Start) {
+ return errDuplicateStreamData
+ }
+
+ startGapNext := startGap.Next()
+ startGapEnd := startGap.Value.End // save it, in case startGap is modified
+ endGapStart := endGap.Value.Start // save it, in case endGap is modified
+ endGapEnd := endGap.Value.End // save it, in case endGap is modified
+ var adjustedStartGapEnd bool
+ var wasCut bool
+
+ pos := start
+ var hasReplacedAtLeastOne bool
+ for {
+ oldEntry, ok := s.queue[pos]
+ if !ok {
+ break
+ }
+ oldEntryLen := protocol.ByteCount(len(oldEntry.Data))
+ if end-pos > oldEntryLen || (hasReplacedAtLeastOne && end-pos == oldEntryLen) {
+ // The existing frame is shorter than the new frame. Replace it.
+ delete(s.queue, pos)
+ pos += oldEntryLen
+ hasReplacedAtLeastOne = true
+ if oldEntry.DoneCb != nil {
+ oldEntry.DoneCb()
+ }
+ } else {
+ if !hasReplacedAtLeastOne {
+ return errDuplicateStreamData
+ }
+ // The existing frame is longer than the new frame.
+ // Cut the new frame such that the end aligns with the start of the existing frame.
+ data = data[:pos-start]
+ end = pos
+ wasCut = true
+ break
+ }
+ }
+
+ if !startsInGap && !hasReplacedAtLeastOne {
+ // cut the frame, such that it starts at the start of the gap
+ data = data[startGap.Value.Start-start:]
+ start = startGap.Value.Start
+ wasCut = true
+ }
+ if start <= startGap.Value.Start {
+ if end >= startGap.Value.End {
+ // The frame covers the whole startGap. Delete the gap.
+ s.gaps.Remove(startGap)
+ } else {
+ startGap.Value.Start = end
+ }
+ } else if !hasReplacedAtLeastOne {
+ startGap.Value.End = start
+ adjustedStartGapEnd = true
+ }
+
+ if !startGapEqualsEndGap {
+ s.deleteConsecutive(startGapEnd)
+ var nextGap *list.Element[byteInterval]
+ for gap := startGapNext; gap.Value.End < endGapStart; gap = nextGap {
+ nextGap = gap.Next()
+ s.deleteConsecutive(gap.Value.End)
+ s.gaps.Remove(gap)
+ }
+ }
+
+ if !endsInGap && start != endGapEnd && end > endGapEnd {
+ // cut the frame, such that it ends at the end of the gap
+ data = data[:endGapEnd-start]
+ end = endGapEnd
+ wasCut = true
+ }
+ if end == endGapEnd {
+ if !startGapEqualsEndGap {
+ // The frame covers the whole endGap. Delete the gap.
+ s.gaps.Remove(endGap)
+ }
+ } else {
+ if startGapEqualsEndGap && adjustedStartGapEnd {
+ // The frame split the existing gap into two.
+ s.gaps.InsertAfter(byteInterval{Start: end, End: startGapEnd}, startGap)
+ } else if !startGapEqualsEndGap {
+ endGap.Value.Start = end
+ }
+ }
+
+ if wasCut && len(data) < protocol.MinStreamFrameBufferSize {
+ newData := make([]byte, len(data))
+ copy(newData, data)
+ data = newData
+ if doneCb != nil {
+ doneCb()
+ doneCb = nil
+ }
+ }
+
+ if s.gaps.Len() > protocol.MaxStreamFrameSorterGaps {
+ return errors.New("too many gaps in received data")
+ }
+
+ s.queue[start] = frameSorterEntry{Data: data, DoneCb: doneCb}
+ return nil
+}
+
+func (s *frameSorter) findStartGap(offset protocol.ByteCount) (*list.Element[byteInterval], bool) {
+ for gap := s.gaps.Front(); gap != nil; gap = gap.Next() {
+ if offset >= gap.Value.Start && offset <= gap.Value.End {
+ return gap, true
+ }
+ if offset < gap.Value.Start {
+ return gap, false
+ }
+ }
+ panic("no gap found")
+}
+
+func (s *frameSorter) findEndGap(startGap *list.Element[byteInterval], offset protocol.ByteCount) (*list.Element[byteInterval], bool) {
+ for gap := startGap; gap != nil; gap = gap.Next() {
+ if offset >= gap.Value.Start && offset < gap.Value.End {
+ return gap, true
+ }
+ if offset < gap.Value.Start {
+ return gap.Prev(), false
+ }
+ }
+ panic("no gap found")
+}
+
+// deleteConsecutive deletes consecutive frames from the queue, starting at pos
+func (s *frameSorter) deleteConsecutive(pos protocol.ByteCount) {
+ for {
+ oldEntry, ok := s.queue[pos]
+ if !ok {
+ break
+ }
+ oldEntryLen := protocol.ByteCount(len(oldEntry.Data))
+ delete(s.queue, pos)
+ if oldEntry.DoneCb != nil {
+ oldEntry.DoneCb()
+ }
+ pos += oldEntryLen
+ }
+}
+
+func (s *frameSorter) Pop() (protocol.ByteCount, []byte, func()) {
+ entry, ok := s.queue[s.readPos]
+ if !ok {
+ return s.readPos, nil, nil
+ }
+ delete(s.queue, s.readPos)
+ offset := s.readPos
+ s.readPos += protocol.ByteCount(len(entry.Data))
+ if s.gaps.Front().Value.End <= s.readPos {
+ panic("frame sorter BUG: read position higher than a gap")
+ }
+ return offset, entry.Data, entry.DoneCb
+}
+
+// HasMoreData says if there is any more data queued at *any* offset.
+func (s *frameSorter) HasMoreData() bool {
+ return len(s.queue) > 0
+}
+
+var errTooLittleData = errors.New("too little data")
+
+// Peek copies len(p) consecutive bytes starting at offset into p, without removing them.
+// It is only possible to peek from an offset where a frame starts.
+//
+// If there isn't enough consecutive data available, errTooLittleData is returned.
+func (s *frameSorter) Peek(offset protocol.ByteCount, p []byte) error {
+ if len(p) == 0 {
+ return nil
+ }
+
+ // first, check if we have enough consecutive data available
+ pos := offset
+ remaining := len(p)
+ for remaining > 0 {
+ entry, ok := s.queue[pos]
+ if !ok {
+ return errTooLittleData
+ }
+ entryLen := len(entry.Data)
+ if remaining <= entryLen {
+ break // enough data available
+ }
+ remaining -= entryLen
+ pos += protocol.ByteCount(entryLen)
+ }
+
+ pos = offset
+ var copied int
+ for copied < len(p) {
+ entry := s.queue[pos] // the entry is guaranteed to exist from the check above
+ copied += copy(p[copied:], entry.Data)
+ pos += protocol.ByteCount(len(entry.Data))
+ }
+ return nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/framer.go b/vendor/github.com/quic-go/quic-go/framer.go
new file mode 100644
index 00000000..d593c103
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/framer.go
@@ -0,0 +1,295 @@
+package quic
+
+import (
+ "slices"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/flowcontrol"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils/ringbuffer"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+const (
+ maxPathResponses = 256
+ maxControlFrames = 16 << 10
+)
+
+// This is the largest possible size of a stream-related control frame
+// (which is the RESET_STREAM frame).
+const maxStreamControlFrameSize = 25
+
+type streamFrameGetter interface {
+ popStreamFrame(protocol.ByteCount, protocol.Version) (ackhandler.StreamFrame, *wire.StreamDataBlockedFrame, bool)
+}
+
+type streamControlFrameGetter interface {
+ getControlFrame(monotime.Time) (_ ackhandler.Frame, ok, hasMore bool)
+}
+
+type framer struct {
+ mutex sync.Mutex
+
+ activeStreams map[protocol.StreamID]streamFrameGetter
+ streamQueue ringbuffer.RingBuffer[protocol.StreamID]
+ streamsWithControlFrames map[protocol.StreamID]streamControlFrameGetter
+
+ controlFrameMutex sync.Mutex
+ controlFrames []wire.Frame
+ pathResponses []*wire.PathResponseFrame
+ connFlowController flowcontrol.ConnectionFlowController
+ queuedTooManyControlFrames bool
+}
+
+func newFramer(connFlowController flowcontrol.ConnectionFlowController) *framer {
+ return &framer{
+ activeStreams: make(map[protocol.StreamID]streamFrameGetter),
+ streamsWithControlFrames: make(map[protocol.StreamID]streamControlFrameGetter),
+ connFlowController: connFlowController,
+ }
+}
+
+func (f *framer) HasData() bool {
+ f.mutex.Lock()
+ hasData := !f.streamQueue.Empty()
+ f.mutex.Unlock()
+ if hasData {
+ return true
+ }
+ f.controlFrameMutex.Lock()
+ defer f.controlFrameMutex.Unlock()
+ return len(f.streamsWithControlFrames) > 0 || len(f.controlFrames) > 0 || len(f.pathResponses) > 0
+}
+
+func (f *framer) QueueControlFrame(frame wire.Frame) {
+ f.controlFrameMutex.Lock()
+ defer f.controlFrameMutex.Unlock()
+
+ if pr, ok := frame.(*wire.PathResponseFrame); ok {
+ // Only queue up to maxPathResponses PATH_RESPONSE frames.
+ // This limit should be high enough to never be hit in practice,
+ // unless the peer is doing something malicious.
+ if len(f.pathResponses) >= maxPathResponses {
+ return
+ }
+ f.pathResponses = append(f.pathResponses, pr)
+ return
+ }
+ // This is a hack.
+ if len(f.controlFrames) >= maxControlFrames {
+ f.queuedTooManyControlFrames = true
+ return
+ }
+ f.controlFrames = append(f.controlFrames, frame)
+}
+
+func (f *framer) Append(
+ frames []ackhandler.Frame,
+ streamFrames []ackhandler.StreamFrame,
+ maxLen protocol.ByteCount,
+ now monotime.Time,
+ v protocol.Version,
+) ([]ackhandler.Frame, []ackhandler.StreamFrame, protocol.ByteCount) {
+ f.controlFrameMutex.Lock()
+ frames, controlFrameLen := f.appendControlFrames(frames, maxLen, now, v)
+ maxLen -= controlFrameLen
+
+ var lastFrame ackhandler.StreamFrame
+ var streamFrameLen protocol.ByteCount
+ f.mutex.Lock()
+ // pop STREAM frames, until less than 128 bytes are left in the packet
+ numActiveStreams := f.streamQueue.Len()
+ for range numActiveStreams {
+ if protocol.MinStreamFrameSize > maxLen {
+ break
+ }
+ sf, blocked := f.getNextStreamFrame(maxLen, v)
+ if sf.Frame != nil {
+ streamFrames = append(streamFrames, sf)
+ maxLen -= sf.Frame.Length(v)
+ lastFrame = sf
+ streamFrameLen += sf.Frame.Length(v)
+ }
+ // If the stream just became blocked on stream flow control, attempt to pack the
+ // STREAM_DATA_BLOCKED into the same packet.
+ if blocked != nil {
+ l := blocked.Length(v)
+ // In case it doesn't fit, queue it for the next packet.
+ if maxLen < l {
+ f.controlFrames = append(f.controlFrames, blocked)
+ break
+ }
+ frames = append(frames, ackhandler.Frame{Frame: blocked})
+ maxLen -= l
+ controlFrameLen += l
+ }
+ }
+
+ // The only way to become blocked on connection-level flow control is by sending STREAM frames.
+ if isBlocked, offset := f.connFlowController.IsNewlyBlocked(); isBlocked {
+ blocked := &wire.DataBlockedFrame{MaximumData: offset}
+ l := blocked.Length(v)
+ // In case it doesn't fit, queue it for the next packet.
+ if maxLen >= l {
+ frames = append(frames, ackhandler.Frame{Frame: blocked})
+ controlFrameLen += l
+ } else {
+ f.controlFrames = append(f.controlFrames, blocked)
+ }
+ }
+
+ f.mutex.Unlock()
+ f.controlFrameMutex.Unlock()
+
+ if lastFrame.Frame != nil {
+ // account for the smaller size of the last STREAM frame
+ streamFrameLen -= lastFrame.Frame.Length(v)
+ lastFrame.Frame.DataLenPresent = false
+ streamFrameLen += lastFrame.Frame.Length(v)
+ }
+
+ return frames, streamFrames, controlFrameLen + streamFrameLen
+}
+
+func (f *framer) appendControlFrames(
+ frames []ackhandler.Frame,
+ maxLen protocol.ByteCount,
+ now monotime.Time,
+ v protocol.Version,
+) ([]ackhandler.Frame, protocol.ByteCount) {
+ var length protocol.ByteCount
+ // add a PATH_RESPONSE first, but only pack a single PATH_RESPONSE per packet
+ if len(f.pathResponses) > 0 {
+ frame := f.pathResponses[0]
+ frameLen := frame.Length(v)
+ if frameLen <= maxLen {
+ frames = append(frames, ackhandler.Frame{Frame: frame})
+ length += frameLen
+ f.pathResponses = f.pathResponses[1:]
+ }
+ }
+
+ // add stream-related control frames
+ for id, str := range f.streamsWithControlFrames {
+ start:
+ remainingLen := maxLen - length
+ if remainingLen <= maxStreamControlFrameSize {
+ break
+ }
+ fr, ok, hasMore := str.getControlFrame(now)
+ if !hasMore {
+ delete(f.streamsWithControlFrames, id)
+ }
+ if !ok {
+ continue
+ }
+ frames = append(frames, fr)
+ length += fr.Frame.Length(v)
+ if hasMore {
+ // It is rare that a stream has more than one control frame to queue.
+ // We don't want to spawn another loop for just to cover that case.
+ goto start
+ }
+ }
+
+ for len(f.controlFrames) > 0 {
+ frame := f.controlFrames[len(f.controlFrames)-1]
+ frameLen := frame.Length(v)
+ if length+frameLen > maxLen {
+ break
+ }
+ frames = append(frames, ackhandler.Frame{Frame: frame})
+ length += frameLen
+ f.controlFrames = f.controlFrames[:len(f.controlFrames)-1]
+ }
+
+ return frames, length
+}
+
+// QueuedTooManyControlFrames says if the control frame queue exceeded its maximum queue length.
+// This is a hack.
+// It is easier to implement than propagating an error return value in QueueControlFrame.
+// The correct solution would be to queue frames with their respective structs.
+// See https://github.com/quic-go/quic-go/issues/4271 for the queueing of stream-related control frames.
+func (f *framer) QueuedTooManyControlFrames() bool {
+ return f.queuedTooManyControlFrames
+}
+
+func (f *framer) AddActiveStream(id protocol.StreamID, str streamFrameGetter) {
+ f.mutex.Lock()
+ if _, ok := f.activeStreams[id]; !ok {
+ f.streamQueue.PushBack(id)
+ f.activeStreams[id] = str
+ }
+ f.mutex.Unlock()
+}
+
+func (f *framer) AddStreamWithControlFrames(id protocol.StreamID, str streamControlFrameGetter) {
+ f.controlFrameMutex.Lock()
+ if _, ok := f.streamsWithControlFrames[id]; !ok {
+ f.streamsWithControlFrames[id] = str
+ }
+ f.controlFrameMutex.Unlock()
+}
+
+// RemoveActiveStream is called when a stream completes.
+func (f *framer) RemoveActiveStream(id protocol.StreamID) {
+ f.mutex.Lock()
+ delete(f.activeStreams, id)
+ // We don't delete the stream from the streamQueue,
+ // since we'd have to iterate over the ringbuffer.
+ // Instead, we check if the stream is still in activeStreams when appending STREAM frames.
+ f.mutex.Unlock()
+}
+
+func (f *framer) getNextStreamFrame(maxLen protocol.ByteCount, v protocol.Version) (ackhandler.StreamFrame, *wire.StreamDataBlockedFrame) {
+ id := f.streamQueue.PopFront()
+ // This should never return an error. Better check it anyway.
+ // The stream will only be in the streamQueue, if it enqueued itself there.
+ str, ok := f.activeStreams[id]
+ // The stream might have been removed after being enqueued.
+ if !ok {
+ return ackhandler.StreamFrame{}, nil
+ }
+ // For the last STREAM frame, we'll remove the DataLen field later.
+ // Therefore, we can pretend to have more bytes available when popping
+ // the STREAM frame (which will always have the DataLen set).
+ maxLen += protocol.ByteCount(quicvarint.Len(uint64(maxLen)))
+ frame, blocked, hasMoreData := str.popStreamFrame(maxLen, v)
+ if hasMoreData { // put the stream back in the queue (at the end)
+ f.streamQueue.PushBack(id)
+ } else { // no more data to send. Stream is not active
+ delete(f.activeStreams, id)
+ }
+ // Note that the frame.Frame can be nil:
+ // * if the stream was canceled after it said it had data
+ // * the remaining size doesn't allow us to add another STREAM frame
+ return frame, blocked
+}
+
+func (f *framer) Handle0RTTRejection() {
+ f.mutex.Lock()
+ defer f.mutex.Unlock()
+ f.controlFrameMutex.Lock()
+ defer f.controlFrameMutex.Unlock()
+
+ f.streamQueue.Clear()
+ for id := range f.activeStreams {
+ delete(f.activeStreams, id)
+ }
+ var j int
+ for i, frame := range f.controlFrames {
+ switch frame.(type) {
+ case *wire.MaxDataFrame, *wire.MaxStreamDataFrame, *wire.MaxStreamsFrame,
+ *wire.DataBlockedFrame, *wire.StreamDataBlockedFrame, *wire.StreamsBlockedFrame:
+ continue
+ default:
+ f.controlFrames[j] = f.controlFrames[i]
+ j++
+ }
+ }
+ f.controlFrames = slices.Delete(f.controlFrames, j, len(f.controlFrames))
+}
diff --git a/vendor/github.com/quic-go/quic-go/http3/qlog/event.go b/vendor/github.com/quic-go/quic-go/http3/qlog/event.go
new file mode 100644
index 00000000..b5bbe112
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/http3/qlog/event.go
@@ -0,0 +1,138 @@
+package qlog
+
+import (
+ "time"
+
+ "github.com/quic-go/quic-go"
+ "github.com/quic-go/quic-go/qlogwriter/jsontext"
+)
+
+type encoderHelper struct {
+ enc *jsontext.Encoder
+ err error
+}
+
+func (h *encoderHelper) WriteToken(t jsontext.Token) {
+ if h.err != nil {
+ return
+ }
+ h.err = h.enc.WriteToken(t)
+}
+
+type RawInfo struct {
+ Length int // full packet length, including header and AEAD authentication tag
+ PayloadLength int // length of the packet payload, excluding AEAD tag
+}
+
+func (i RawInfo) HasValues() bool {
+ return i.Length != 0 || i.PayloadLength != 0
+}
+
+func (i RawInfo) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if i.Length != 0 {
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Uint(uint64(i.Length)))
+ }
+ if i.PayloadLength != 0 {
+ h.WriteToken(jsontext.String("payload_length"))
+ h.WriteToken(jsontext.Uint(uint64(i.PayloadLength)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type FrameParsed struct {
+ StreamID quic.StreamID
+ Raw RawInfo
+ Frame Frame
+}
+
+func (e FrameParsed) Name() string { return "http3:frame_parsed" }
+
+func (e FrameParsed) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Uint(uint64(e.StreamID)))
+ if e.Raw.HasValues() {
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ }
+ h.WriteToken(jsontext.String("frame"))
+ if err := e.Frame.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type FrameCreated struct {
+ StreamID quic.StreamID
+ Raw RawInfo
+ Frame Frame
+}
+
+func (e FrameCreated) Name() string { return "http3:frame_created" }
+
+func (e FrameCreated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Uint(uint64(e.StreamID)))
+ if e.Raw.HasValues() {
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ }
+ h.WriteToken(jsontext.String("frame"))
+ if err := e.Frame.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type DatagramCreated struct {
+ QuarterStreamID uint64
+ Raw RawInfo
+}
+
+func (e DatagramCreated) Name() string { return "http3:datagram_created" }
+
+func (e DatagramCreated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("quarter_stream_id"))
+ h.WriteToken(jsontext.Uint(e.QuarterStreamID))
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type DatagramParsed struct {
+ QuarterStreamID uint64
+ Raw RawInfo
+}
+
+func (e DatagramParsed) Name() string { return "http3:datagram_parsed" }
+
+func (e DatagramParsed) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("quarter_stream_id"))
+ h.WriteToken(jsontext.Uint(e.QuarterStreamID))
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
diff --git a/vendor/github.com/quic-go/quic-go/http3/qlog/frame.go b/vendor/github.com/quic-go/quic-go/http3/qlog/frame.go
new file mode 100644
index 00000000..b404453d
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/http3/qlog/frame.go
@@ -0,0 +1,220 @@
+package qlog
+
+import (
+ "github.com/quic-go/quic-go"
+ "github.com/quic-go/quic-go/qlogwriter/jsontext"
+)
+
+// Frame represents an HTTP/3 frame.
+type Frame struct {
+ Frame any
+}
+
+func (f Frame) encode(enc *jsontext.Encoder) error {
+ switch frame := f.Frame.(type) {
+ case DataFrame:
+ return frame.encode(enc)
+ case HeadersFrame:
+ return frame.encode(enc)
+ case GoAwayFrame:
+ return frame.encode(enc)
+ case SettingsFrame:
+ return frame.encode(enc)
+ case PushPromiseFrame:
+ return frame.encode(enc)
+ case CancelPushFrame:
+ return frame.encode(enc)
+ case MaxPushIDFrame:
+ return frame.encode(enc)
+ case ReservedFrame:
+ return frame.encode(enc)
+ case UnknownFrame:
+ return frame.encode(enc)
+ }
+ // This shouldn't happen if the code is correctly logging frames.
+ // Write a null token to produce valid JSON.
+ return enc.WriteToken(jsontext.Null)
+}
+
+// A DataFrame is a DATA frame
+type DataFrame struct{}
+
+func (f *DataFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("data"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type HeaderField struct {
+ Name string
+ Value string
+}
+
+// A HeadersFrame is a HEADERS frame
+type HeadersFrame struct {
+ HeaderFields []HeaderField
+}
+
+func (f *HeadersFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("headers"))
+ if len(f.HeaderFields) > 0 {
+ h.WriteToken(jsontext.String("header_fields"))
+ h.WriteToken(jsontext.BeginArray)
+ for _, f := range f.HeaderFields {
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String(f.Name))
+ h.WriteToken(jsontext.String("value"))
+ h.WriteToken(jsontext.String(f.Value))
+ h.WriteToken(jsontext.EndObject)
+ }
+ h.WriteToken(jsontext.EndArray)
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// A GoAwayFrame is a GOAWAY frame
+type GoAwayFrame struct {
+ StreamID quic.StreamID
+}
+
+func (f *GoAwayFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("goaway"))
+ h.WriteToken(jsontext.String("id"))
+ h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type SettingsFrame struct {
+ MaxFieldSectionSize int64
+ Datagram *bool
+ ExtendedConnect *bool
+ Other map[uint64]uint64
+}
+
+func (f *SettingsFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("settings"))
+ h.WriteToken(jsontext.String("settings"))
+ h.WriteToken(jsontext.BeginArray)
+ if f.MaxFieldSectionSize >= 0 {
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String("settings_max_field_section_size"))
+ h.WriteToken(jsontext.String("value"))
+ h.WriteToken(jsontext.Uint(uint64(f.MaxFieldSectionSize)))
+ h.WriteToken(jsontext.EndObject)
+ }
+ if f.Datagram != nil {
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String("settings_h3_datagram"))
+ h.WriteToken(jsontext.String("value"))
+ h.WriteToken(jsontext.Bool(*f.Datagram))
+ h.WriteToken(jsontext.EndObject)
+ }
+ if f.ExtendedConnect != nil {
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String("settings_enable_connect_protocol"))
+ h.WriteToken(jsontext.String("value"))
+ h.WriteToken(jsontext.Bool(*f.ExtendedConnect))
+ h.WriteToken(jsontext.EndObject)
+ }
+ if len(f.Other) > 0 {
+ for k, v := range f.Other {
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String("unknown"))
+ h.WriteToken(jsontext.String("name_bytes"))
+ h.WriteToken(jsontext.Uint(k))
+ h.WriteToken(jsontext.String("value"))
+ h.WriteToken(jsontext.Uint(v))
+ h.WriteToken(jsontext.EndObject)
+ }
+ }
+ h.WriteToken(jsontext.EndArray)
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// A PushPromiseFrame is a PUSH_PROMISE frame
+type PushPromiseFrame struct{}
+
+func (f *PushPromiseFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("push_promise"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// A CancelPushFrame is a CANCEL_PUSH frame
+type CancelPushFrame struct{}
+
+func (f *CancelPushFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("cancel_push"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// A MaxPushIDFrame is a MAX_PUSH_ID frame
+type MaxPushIDFrame struct{}
+
+func (f *MaxPushIDFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("max_push_id"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// A ReservedFrame is one of the reserved frame types
+type ReservedFrame struct {
+ Type uint64
+}
+
+func (f *ReservedFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("reserved"))
+ h.WriteToken(jsontext.String("frame_type_bytes"))
+ h.WriteToken(jsontext.Uint(f.Type))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// An UnknownFrame is an unknown frame type
+type UnknownFrame struct {
+ Type uint64
+}
+
+func (f *UnknownFrame) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("unknown"))
+ h.WriteToken(jsontext.String("frame_type_bytes"))
+ h.WriteToken(jsontext.Uint(f.Type))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
diff --git a/vendor/github.com/quic-go/quic-go/http3/qlog/qlog_dir.go b/vendor/github.com/quic-go/quic-go/http3/qlog/qlog_dir.go
new file mode 100644
index 00000000..898d17c6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/http3/qlog/qlog_dir.go
@@ -0,0 +1,15 @@
+package qlog
+
+import (
+ "context"
+
+ "github.com/quic-go/quic-go"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+const EventSchema = "urn:ietf:params:qlog:events:http3-12"
+
+func DefaultConnectionTracer(ctx context.Context, isClient bool, connID quic.ConnectionID) qlogwriter.Trace {
+ return qlog.DefaultConnectionTracerWithSchemas(ctx, isClient, connID, []string{qlog.EventSchema, EventSchema})
+}
diff --git a/vendor/github.com/quic-go/quic-go/interface.go b/vendor/github.com/quic-go/quic-go/interface.go
new file mode 100644
index 00000000..119e3205
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/interface.go
@@ -0,0 +1,215 @@
+package quic
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "net"
+ "slices"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/handshake"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+// The StreamID is the ID of a QUIC stream.
+type StreamID = protocol.StreamID
+
+// A Version is a QUIC version number.
+type Version = protocol.Version
+
+const (
+ // Version1 is RFC 9000
+ Version1 = protocol.Version1
+ // Version2 is RFC 9369
+ Version2 = protocol.Version2
+)
+
+// SupportedVersions returns the support versions, sorted in descending order of preference.
+func SupportedVersions() []Version {
+ // clone the slice to prevent the caller from modifying the slice
+ return slices.Clone(protocol.SupportedVersions)
+}
+
+// A ClientToken is a token received by the client.
+// It can be used to skip address validation on future connection attempts.
+type ClientToken struct {
+ data []byte
+ rtt time.Duration
+}
+
+type TokenStore interface {
+ // Pop searches for a ClientToken associated with the given key.
+ // Since tokens are not supposed to be reused, it must remove the token from the cache.
+ // It returns nil when no token is found.
+ Pop(key string) (token *ClientToken)
+
+ // Put adds a token to the cache with the given key. It might get called
+ // multiple times in a connection.
+ Put(key string, token *ClientToken)
+}
+
+// Err0RTTRejected is the returned from:
+// - Open{Uni}Stream{Sync}
+// - Accept{Uni}Stream
+// - Stream.Read and Stream.Write
+//
+// when the server rejects a 0-RTT connection attempt.
+var Err0RTTRejected = errors.New("0-RTT rejected")
+
+// QUICVersionContextKey can be used to find out the QUIC version of a TLS handshake from the
+// context returned by tls.Config.ClientInfo.Context.
+var QUICVersionContextKey = handshake.QUICVersionContextKey
+
+// StatelessResetKey is a key used to derive stateless reset tokens.
+type StatelessResetKey [32]byte
+
+// TokenGeneratorKey is a key used to encrypt session resumption tokens.
+type TokenGeneratorKey = handshake.TokenProtectorKey
+
+// A ConnectionID is a QUIC Connection ID, as defined in RFC 9000.
+// It is not able to handle QUIC Connection IDs longer than 20 bytes,
+// as they are allowed by RFC 8999.
+type ConnectionID = protocol.ConnectionID
+
+// ConnectionIDFromBytes interprets b as a [ConnectionID]. It panics if b is
+// longer than 20 bytes.
+func ConnectionIDFromBytes(b []byte) ConnectionID {
+ return protocol.ParseConnectionID(b)
+}
+
+// A ConnectionIDGenerator allows the application to take control over the generation of Connection IDs.
+// Connection IDs generated by an implementation must be of constant length.
+type ConnectionIDGenerator interface {
+ // GenerateConnectionID generates a new Connection ID.
+ // Generated Connection IDs must be unique and observers should not be able to correlate two Connection IDs.
+ GenerateConnectionID() (ConnectionID, error)
+
+ // ConnectionIDLen returns the length of Connection IDs generated by this implementation.
+ // Implementations must return constant-length Connection IDs with lengths between 0 and 20 bytes.
+ // A length of 0 can only be used when an endpoint doesn't need to multiplex connections during migration.
+ ConnectionIDLen() int
+}
+
+// Config contains all configuration data needed for a QUIC server or client.
+type Config struct {
+ // GetConfigForClient is called for incoming connections.
+ // If the error is not nil, the connection attempt is refused.
+ GetConfigForClient func(info *ClientInfo) (*Config, error)
+ // The QUIC versions that can be negotiated.
+ // If not set, it uses all versions available.
+ Versions []Version
+ // HandshakeIdleTimeout is the idle timeout before completion of the handshake.
+ // If we don't receive any packet from the peer within this time, the connection attempt is aborted.
+ // Additionally, if the handshake doesn't complete in twice this time, the connection attempt is also aborted.
+ // If this value is zero, the timeout is set to 5 seconds.
+ HandshakeIdleTimeout time.Duration
+ // MaxIdleTimeout is the maximum duration that may pass without any incoming network activity.
+ // The actual value for the idle timeout is the minimum of this value and the peer's.
+ // This value only applies after the handshake has completed.
+ // If the timeout is exceeded, the connection is closed.
+ // If this value is zero, the timeout is set to 30 seconds.
+ MaxIdleTimeout time.Duration
+ // The TokenStore stores tokens received from the server.
+ // Tokens are used to skip address validation on future connection attempts.
+ // The key used to store tokens is the ServerName from the tls.Config, if set
+ // otherwise the token is associated with the server's IP address.
+ TokenStore TokenStore
+ // InitialStreamReceiveWindow is the initial size of the stream-level flow control window for receiving data.
+ // If the application is consuming data quickly enough, the flow control auto-tuning algorithm
+ // will increase the window up to MaxStreamReceiveWindow.
+ // If this value is zero, it will default to 512 KB.
+ // Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
+ InitialStreamReceiveWindow uint64
+ // MaxStreamReceiveWindow is the maximum stream-level flow control window for receiving data.
+ // If this value is zero, it will default to 6 MB.
+ // Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
+ MaxStreamReceiveWindow uint64
+ // InitialConnectionReceiveWindow is the initial size of the stream-level flow control window for receiving data.
+ // If the application is consuming data quickly enough, the flow control auto-tuning algorithm
+ // will increase the window up to MaxConnectionReceiveWindow.
+ // If this value is zero, it will default to 512 KB.
+ // Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
+ InitialConnectionReceiveWindow uint64
+ // MaxConnectionReceiveWindow is the connection-level flow control window for receiving data.
+ // If this value is zero, it will default to 15 MB.
+ // Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
+ MaxConnectionReceiveWindow uint64
+ // AllowConnectionWindowIncrease is called every time the connection flow controller attempts
+ // to increase the connection flow control window.
+ // If set, the caller can prevent an increase of the window. Typically, it would do so to
+ // limit the memory usage.
+ // To avoid deadlocks, it is not valid to call other functions on the connection or on streams
+ // in this callback.
+ AllowConnectionWindowIncrease func(conn *Conn, delta uint64) bool
+ // MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
+ // If not set, it will default to 100.
+ // If set to a negative value, it doesn't allow any bidirectional streams.
+ // Values larger than 2^60 will be clipped to that value.
+ MaxIncomingStreams int64
+ // MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
+ // If not set, it will default to 100.
+ // If set to a negative value, it doesn't allow any unidirectional streams.
+ // Values larger than 2^60 will be clipped to that value.
+ MaxIncomingUniStreams int64
+ // KeepAlivePeriod defines whether this peer will periodically send a packet to keep the connection alive.
+ // If set to 0, then no keep alive is sent. Otherwise, the keep alive is sent on that period (or at most
+ // every half of MaxIdleTimeout, whichever is smaller).
+ KeepAlivePeriod time.Duration
+ // InitialPacketSize is the initial size (and the lower limit) for packets sent.
+ // Under most circumstances, it is not necessary to manually set this value,
+ // since path MTU discovery quickly finds the path's MTU.
+ // If set too high, the path might not support packets of that size, leading to a timeout of the QUIC handshake.
+ // Values below 1200 are invalid.
+ InitialPacketSize uint16
+ // DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899).
+ // This allows the sending of QUIC packets that fully utilize the available MTU of the path.
+ // Path MTU discovery is only available on systems that allow setting of the Don't Fragment (DF) bit.
+ DisablePathMTUDiscovery bool
+ // Allow0RTT allows the application to decide if a 0-RTT connection attempt should be accepted.
+ // Only valid for the server.
+ Allow0RTT bool
+ // Enable QUIC datagram support (RFC 9221).
+ EnableDatagrams bool
+ // Enable QUIC Stream Resets with Partial Delivery.
+ // See https://datatracker.ietf.org/doc/html/draft-ietf-quic-reliable-stream-reset-07.
+ EnableStreamResetPartialDelivery bool
+
+ Tracer func(ctx context.Context, isClient bool, connID ConnectionID) qlogwriter.Trace
+}
+
+// ClientInfo contains information about an incoming connection attempt.
+type ClientInfo struct {
+ // RemoteAddr is the remote address on the Initial packet.
+ // Unless AddrVerified is set, the address is not yet verified, and could be a spoofed IP address.
+ RemoteAddr net.Addr
+ // AddrVerified says if the remote address was verified using QUIC's Retry mechanism.
+ // Note that the Retry mechanism costs one network roundtrip,
+ // and is not performed unless Transport.MaxUnvalidatedHandshakes is surpassed.
+ AddrVerified bool
+}
+
+// ConnectionState records basic details about a QUIC connection.
+type ConnectionState struct {
+ // TLS contains information about the TLS connection state, incl. the tls.ConnectionState.
+ TLS tls.ConnectionState
+ // SupportsDatagrams indicates support for QUIC datagrams (RFC 9221).
+ SupportsDatagrams struct {
+ // Remote is true if the peer advertised datagram support.
+ // Local is true if datagram support was enabled via Config.EnableDatagrams.
+ Remote, Local bool
+ }
+ // SupportsStreamResetPartialDelivery indicates support for QUIC Stream Resets with Partial Delivery.
+ SupportsStreamResetPartialDelivery struct {
+ // Remote is true if the peer advertised support.
+ // Local is true if support was enabled via Config.EnableStreamResetPartialDelivery.
+ Remote, Local bool
+ }
+ // Used0RTT says if 0-RTT resumption was used.
+ Used0RTT bool
+ // Version is the QUIC version of the QUIC connection.
+ Version Version
+ // GSO says if generic segmentation offload is used.
+ GSO bool
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go
new file mode 100644
index 00000000..8d843612
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go
@@ -0,0 +1,33 @@
+package ackhandler
+
+import "github.com/quic-go/quic-go/internal/wire"
+
+// IsFrameTypeAckEliciting returns true if the frame is ack-eliciting.
+func IsFrameTypeAckEliciting(t wire.FrameType) bool {
+ //nolint:exhaustive // The default case catches the rest.
+ switch t {
+ case wire.FrameTypeAck, wire.FrameTypeAckECN:
+ return false
+ case wire.FrameTypeConnectionClose, wire.FrameTypeApplicationClose:
+ return false
+ default:
+ return true
+ }
+}
+
+// IsFrameAckEliciting returns true if the frame is ack-eliciting.
+func IsFrameAckEliciting(f wire.Frame) bool {
+ _, isAck := f.(*wire.AckFrame)
+ _, isConnectionClose := f.(*wire.ConnectionCloseFrame)
+ return !isAck && !isConnectionClose
+}
+
+// HasAckElicitingFrames returns true if at least one frame is ack-eliciting.
+func HasAckElicitingFrames(fs []Frame) bool {
+ for _, f := range fs {
+ if IsFrameAckEliciting(f.Frame) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
new file mode 100644
index 00000000..123d3a34
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
@@ -0,0 +1,340 @@
+package ackhandler
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+type ecnState uint8
+
+const (
+ ecnStateInitial ecnState = iota
+ ecnStateTesting
+ ecnStateUnknown
+ ecnStateCapable
+ ecnStateFailed
+)
+
+const (
+ // ecnFailedNoECNCounts is emitted when an ACK acknowledges ECN-marked packets,
+ // but doesn't contain any ECN counts
+ ecnFailedNoECNCounts = "ACK doesn't contain ECN marks"
+ // ecnFailedDecreasedECNCounts is emitted when an ACK frame decreases ECN counts
+ ecnFailedDecreasedECNCounts = "ACK decreases ECN counts"
+ // ecnFailedLostAllTestingPackets is emitted when all ECN testing packets are declared lost
+ ecnFailedLostAllTestingPackets = "all ECN testing packets declared lost"
+ // ecnFailedMoreECNCountsThanSent is emitted when an ACK contains more ECN counts than ECN-marked packets were sent
+ ecnFailedMoreECNCountsThanSent = "ACK contains more ECN counts than ECN-marked packets sent"
+ // ecnFailedTooFewECNCounts is emitted when an ACK contains fewer ECN counts than it acknowledges packets
+ ecnFailedTooFewECNCounts = "ACK contains fewer new ECN counts than acknowledged ECN-marked packets"
+ // ecnFailedManglingDetected is emitted when the path marks all ECN-marked packets as CE
+ ecnFailedManglingDetected = "ECN mangling detected"
+)
+
+// must fit into an uint8, otherwise numSentTesting and numLostTesting must have a larger type
+const numECNTestingPackets = 10
+
+type ecnHandler interface {
+ SentPacket(protocol.PacketNumber, protocol.ECN)
+ Mode() protocol.ECN
+ HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ect1, ecnce int64) (congested bool)
+ LostPacket(protocol.PacketNumber)
+}
+
+// The ecnTracker performs ECN validation of a path.
+// Once failed, it doesn't do any re-validation of the path.
+// It is designed only work for 1-RTT packets, it doesn't handle multiple packet number spaces.
+// In order to avoid revealing any internal state to on-path observers,
+// callers should make sure to start using ECN (i.e. calling Mode) for the very first 1-RTT packet sent.
+// The validation logic implemented here strictly follows the algorithm described in RFC 9000 section 13.4.2 and A.4.
+type ecnTracker struct {
+ state ecnState
+ numSentTesting, numLostTesting uint8
+
+ firstTestingPacket protocol.PacketNumber
+ lastTestingPacket protocol.PacketNumber
+ firstCapablePacket protocol.PacketNumber
+
+ numSentECT0, numSentECT1 int64
+ numAckedECT0, numAckedECT1, numAckedECNCE int64
+
+ qlogger qlogwriter.Recorder
+ logger utils.Logger
+}
+
+var _ ecnHandler = &ecnTracker{}
+
+func newECNTracker(logger utils.Logger, qlogger qlogwriter.Recorder) *ecnTracker {
+ return &ecnTracker{
+ firstTestingPacket: protocol.InvalidPacketNumber,
+ lastTestingPacket: protocol.InvalidPacketNumber,
+ firstCapablePacket: protocol.InvalidPacketNumber,
+ state: ecnStateInitial,
+ logger: logger,
+ qlogger: qlogger,
+ }
+}
+
+func (e *ecnTracker) SentPacket(pn protocol.PacketNumber, ecn protocol.ECN) {
+ //nolint:exhaustive // These are the only ones we need to take care of.
+ switch ecn {
+ case protocol.ECNNon:
+ return
+ case protocol.ECT0:
+ e.numSentECT0++
+ case protocol.ECT1:
+ e.numSentECT1++
+ case protocol.ECNUnsupported:
+ if e.state != ecnStateFailed {
+ panic("didn't expect ECN to be unsupported")
+ }
+ default:
+ panic(fmt.Sprintf("sent packet with unexpected ECN marking: %s", ecn))
+ }
+
+ if e.state == ecnStateCapable && e.firstCapablePacket == protocol.InvalidPacketNumber {
+ e.firstCapablePacket = pn
+ }
+
+ if e.state != ecnStateTesting {
+ return
+ }
+
+ e.numSentTesting++
+ if e.firstTestingPacket == protocol.InvalidPacketNumber {
+ e.firstTestingPacket = pn
+ }
+ if e.numSentECT0+e.numSentECT1 >= numECNTestingPackets {
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateUnknown,
+ })
+ }
+ e.state = ecnStateUnknown
+ e.lastTestingPacket = pn
+ }
+}
+
+func (e *ecnTracker) Mode() protocol.ECN {
+ switch e.state {
+ case ecnStateInitial:
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateTesting,
+ })
+ }
+ e.state = ecnStateTesting
+ return e.Mode()
+ case ecnStateTesting, ecnStateCapable:
+ return protocol.ECT0
+ case ecnStateUnknown, ecnStateFailed:
+ return protocol.ECNNon
+ default:
+ panic(fmt.Sprintf("unknown ECN state: %d", e.state))
+ }
+}
+
+func (e *ecnTracker) LostPacket(pn protocol.PacketNumber) {
+ if e.state != ecnStateTesting && e.state != ecnStateUnknown {
+ return
+ }
+ if !e.isTestingPacket(pn) {
+ return
+ }
+ e.numLostTesting++
+ // Only proceed if we have sent all 10 testing packets.
+ if e.state != ecnStateUnknown {
+ return
+ }
+ if e.numLostTesting >= e.numSentTesting {
+ e.logger.Debugf("Disabling ECN. All testing packets were lost.")
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedLostAllTestingPackets,
+ })
+ }
+ e.state = ecnStateFailed
+ return
+ }
+ // Path validation also fails if some testing packets are lost, and all other testing packets where CE-marked
+ e.failIfMangled()
+}
+
+// HandleNewlyAcked handles the ECN counts on an ACK frame.
+// It must only be called for ACK frames that increase the largest acknowledged packet number,
+// see section 13.4.2.1 of RFC 9000.
+func (e *ecnTracker) HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ect1, ecnce int64) (congested bool) {
+ if e.state == ecnStateFailed {
+ return false
+ }
+
+ // ECN validation can fail if the received total count for either ECT(0) or ECT(1) exceeds
+ // the total number of packets sent with each corresponding ECT codepoint.
+ if ect0 > e.numSentECT0 || ect1 > e.numSentECT1 {
+ e.logger.Debugf("Disabling ECN. Received more ECT(0) / ECT(1) acknowledgements than packets sent.")
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedMoreECNCountsThanSent,
+ })
+ }
+ e.state = ecnStateFailed
+ return false
+ }
+
+ // Count ECT0 and ECT1 marks that we used when sending the packets that are now being acknowledged.
+ var ackedECT0, ackedECT1 int64
+ for _, p := range packets {
+ //nolint:exhaustive // We only ever send ECT(0) and ECT(1).
+ switch e.ecnMarking(p.PacketNumber) {
+ case protocol.ECT0:
+ ackedECT0++
+ case protocol.ECT1:
+ ackedECT1++
+ }
+ }
+
+ // If an ACK frame newly acknowledges a packet that the endpoint sent with either the ECT(0) or ECT(1)
+ // codepoint set, ECN validation fails if the corresponding ECN counts are not present in the ACK frame.
+ // This check detects:
+ // * paths that bleach all ECN marks, and
+ // * peers that don't report any ECN counts
+ if (ackedECT0 > 0 || ackedECT1 > 0) && ect0 == 0 && ect1 == 0 && ecnce == 0 {
+ e.logger.Debugf("Disabling ECN. ECN-marked packet acknowledged, but no ECN counts on ACK frame.")
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedNoECNCounts,
+ })
+ }
+ e.state = ecnStateFailed
+ return false
+ }
+
+ // Determine the increase in ECT0, ECT1 and ECNCE marks
+ newECT0 := ect0 - e.numAckedECT0
+ newECT1 := ect1 - e.numAckedECT1
+ newECNCE := ecnce - e.numAckedECNCE
+
+ // We're only processing ACKs that increase the Largest Acked.
+ // Therefore, the ECN counters should only ever increase.
+ // Any decrease means that the peer's counting logic is broken.
+ if newECT0 < 0 || newECT1 < 0 || newECNCE < 0 {
+ e.logger.Debugf("Disabling ECN. ECN counts decreased unexpectedly.")
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedDecreasedECNCounts,
+ })
+ }
+ e.state = ecnStateFailed
+ return false
+ }
+
+ // ECN validation also fails if the sum of the increase in ECT(0) and ECN-CE counts is less than the number
+ // of newly acknowledged packets that were originally sent with an ECT(0) marking.
+ // This could be the result of (partial) bleaching.
+ if newECT0+newECNCE < ackedECT0 {
+ e.logger.Debugf("Disabling ECN. Received less ECT(0) + ECN-CE than packets sent with ECT(0).")
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedTooFewECNCounts,
+ })
+ }
+ e.state = ecnStateFailed
+ return false
+ }
+ // Similarly, ECN validation fails if the sum of the increases to ECT(1) and ECN-CE counts is less than
+ // the number of newly acknowledged packets sent with an ECT(1) marking.
+ if newECT1+newECNCE < ackedECT1 {
+ e.logger.Debugf("Disabling ECN. Received less ECT(1) + ECN-CE than packets sent with ECT(1).")
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedTooFewECNCounts,
+ })
+ }
+ e.state = ecnStateFailed
+ return false
+ }
+
+ // update our counters
+ e.numAckedECT0 = ect0
+ e.numAckedECT1 = ect1
+ e.numAckedECNCE = ecnce
+
+ // Detect mangling (a path remarking all ECN-marked testing packets as CE),
+ // once all 10 testing packets have been sent out.
+ if e.state == ecnStateUnknown {
+ e.failIfMangled()
+ if e.state == ecnStateFailed {
+ return false
+ }
+ }
+ if e.state == ecnStateTesting || e.state == ecnStateUnknown {
+ var ackedTestingPacket bool
+ for _, p := range packets {
+ if e.isTestingPacket(p.PacketNumber) {
+ ackedTestingPacket = true
+ break
+ }
+ }
+ // This check won't succeed if the path is mangling ECN-marks (i.e. rewrites all ECN-marked packets to CE).
+ if ackedTestingPacket && (newECT0 > 0 || newECT1 > 0) {
+ e.logger.Debugf("ECN capability confirmed.")
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateCapable,
+ })
+ }
+ e.state = ecnStateCapable
+ }
+ }
+
+ // Don't trust CE marks before having confirmed ECN capability of the path.
+ // Otherwise, mangling would be misinterpreted as actual congestion.
+ return e.state == ecnStateCapable && newECNCE > 0
+}
+
+// failIfMangled fails ECN validation if all testing packets are lost or CE-marked.
+func (e *ecnTracker) failIfMangled() {
+ numAckedECNCE := e.numAckedECNCE + int64(e.numLostTesting)
+ if e.numSentECT0+e.numSentECT1 > numAckedECNCE {
+ return
+ }
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedManglingDetected,
+ })
+ }
+ e.state = ecnStateFailed
+}
+
+func (e *ecnTracker) ecnMarking(pn protocol.PacketNumber) protocol.ECN {
+ if pn < e.firstTestingPacket || e.firstTestingPacket == protocol.InvalidPacketNumber {
+ return protocol.ECNNon
+ }
+ if pn < e.lastTestingPacket || e.lastTestingPacket == protocol.InvalidPacketNumber {
+ return protocol.ECT0
+ }
+ if pn < e.firstCapablePacket || e.firstCapablePacket == protocol.InvalidPacketNumber {
+ return protocol.ECNNon
+ }
+ // We don't need to deal with the case when ECN validation fails,
+ // since we're ignoring any ECN counts reported in ACK frames in that case.
+ return protocol.ECT0
+}
+
+func (e *ecnTracker) isTestingPacket(pn protocol.PacketNumber) bool {
+ if e.firstTestingPacket == protocol.InvalidPacketNumber {
+ return false
+ }
+ return pn >= e.firstTestingPacket && (pn <= e.lastTestingPacket || e.lastTestingPacket == protocol.InvalidPacketNumber)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go
new file mode 100644
index 00000000..e03a8080
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go
@@ -0,0 +1,21 @@
+package ackhandler
+
+import (
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+// FrameHandler handles the acknowledgement and the loss of a frame.
+type FrameHandler interface {
+ OnAcked(wire.Frame)
+ OnLost(wire.Frame)
+}
+
+type Frame struct {
+ Frame wire.Frame // nil if the frame has already been acknowledged in another packet
+ Handler FrameHandler
+}
+
+type StreamFrame struct {
+ Frame *wire.StreamFrame
+ Handler FrameHandler
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
new file mode 100644
index 00000000..620a5e11
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
@@ -0,0 +1,39 @@
+package ackhandler
+
+import (
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+// SentPacketHandler handles ACKs received for outgoing packets
+type SentPacketHandler interface {
+ // SentPacket may modify the packet
+ SentPacket(t monotime.Time, pn, largestAcked protocol.PacketNumber, streamFrames []StreamFrame, frames []Frame, encLevel protocol.EncryptionLevel, ecn protocol.ECN, size protocol.ByteCount, isPathMTUProbePacket, isPathProbePacket bool)
+ // ReceivedAck processes an ACK frame.
+ // It does not store a copy of the frame.
+ ReceivedAck(f *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime monotime.Time) (bool /* 1-RTT packet acked */, error)
+ ReceivedPacket(protocol.EncryptionLevel, monotime.Time)
+ ReceivedBytes(_ protocol.ByteCount, rcvTime monotime.Time)
+ DropPackets(_ protocol.EncryptionLevel, rcvTime monotime.Time)
+ ResetForRetry(rcvTime monotime.Time)
+
+ // The SendMode determines if and what kind of packets can be sent.
+ SendMode(now monotime.Time) SendMode
+ // TimeUntilSend is the time when the next packet should be sent.
+ // It is used for pacing packets.
+ TimeUntilSend() monotime.Time
+ SetMaxDatagramSize(count protocol.ByteCount)
+
+ // only to be called once the handshake is complete
+ QueueProbePacket(protocol.EncryptionLevel) bool /* was a packet queued */
+
+ ECNMode(isShortHeaderPacket bool) protocol.ECN // isShortHeaderPacket should only be true for non-coalesced 1-RTT packets
+ PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
+ PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
+
+ GetLossDetectionTimeout() monotime.Time
+ OnLossDetectionTimeout(now monotime.Time) error
+
+ MigratedPath(now monotime.Time, initialMaxPacketSize protocol.ByteCount)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/lost_packet_tracker.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/lost_packet_tracker.go
new file mode 100644
index 00000000..40665734
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/lost_packet_tracker.go
@@ -0,0 +1,73 @@
+package ackhandler
+
+import (
+ "iter"
+ "slices"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+type lostPacket struct {
+ PacketNumber protocol.PacketNumber
+ SendTime monotime.Time
+}
+
+type lostPacketTracker struct {
+ maxLength int
+ lostPackets []lostPacket
+}
+
+func newLostPacketTracker(maxLength int) *lostPacketTracker {
+ return &lostPacketTracker{
+ maxLength: maxLength,
+ // Preallocate a small slice only.
+ // Hopefully we won't lose many packets.
+ lostPackets: make([]lostPacket, 0, 4),
+ }
+}
+
+func (t *lostPacketTracker) Add(p protocol.PacketNumber, sendTime monotime.Time) {
+ if len(t.lostPackets) == t.maxLength {
+ t.lostPackets = t.lostPackets[1:]
+ }
+ t.lostPackets = append(t.lostPackets, lostPacket{
+ PacketNumber: p,
+ SendTime: sendTime,
+ })
+}
+
+// Delete deletes a packet from the lost packet tracker.
+// This function is not optimized for performance if many packets are lost,
+// but it is only used when a spurious loss is detected, which is rare.
+func (t *lostPacketTracker) Delete(pn protocol.PacketNumber) {
+ t.lostPackets = slices.DeleteFunc(t.lostPackets, func(p lostPacket) bool {
+ return p.PacketNumber == pn
+ })
+}
+
+func (t *lostPacketTracker) All() iter.Seq2[protocol.PacketNumber, monotime.Time] {
+ return func(yield func(protocol.PacketNumber, monotime.Time) bool) {
+ for _, p := range t.lostPackets {
+ if !yield(p.PacketNumber, p.SendTime) {
+ return
+ }
+ }
+ }
+}
+
+func (t *lostPacketTracker) DeleteBefore(ti monotime.Time) {
+ if len(t.lostPackets) == 0 {
+ return
+ }
+ if !t.lostPackets[0].SendTime.Before(ti) {
+ return
+ }
+ var idx int
+ for ; idx < len(t.lostPackets); idx++ {
+ if !t.lostPackets[idx].SendTime.Before(ti) {
+ break
+ }
+ }
+ t.lostPackets = slices.Delete(t.lostPackets, 0, idx)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
new file mode 100644
index 00000000..3add80d1
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
@@ -0,0 +1,6 @@
+//go:build gomock || generate
+
+package ackhandler
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_ecn_handler_test.go github.com/quic-go/quic-go/internal/ackhandler ECNHandler"
+type ECNHandler = ecnHandler
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
new file mode 100644
index 00000000..7d986300
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
@@ -0,0 +1,60 @@
+package ackhandler
+
+import (
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+type packetWithPacketNumber struct {
+ PacketNumber protocol.PacketNumber
+ *packet
+}
+
+// A Packet is a packet
+type packet struct {
+ SendTime monotime.Time
+ StreamFrames []StreamFrame
+ Frames []Frame
+ LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
+ Length protocol.ByteCount
+ EncryptionLevel protocol.EncryptionLevel
+
+ IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
+
+ includedInBytesInFlight bool
+ isPathProbePacket bool
+}
+
+func (p *packet) Outstanding() bool {
+ return !p.IsPathMTUProbePacket && !p.isPathProbePacket && p.IsAckEliciting()
+}
+
+func (p *packet) IsAckEliciting() bool {
+ return len(p.StreamFrames) > 0 || len(p.Frames) > 0
+}
+
+var packetPool = sync.Pool{New: func() any { return &packet{} }}
+
+func getPacket() *packet {
+ p := packetPool.Get().(*packet)
+ p.StreamFrames = nil
+ p.Frames = nil
+ p.LargestAcked = 0
+ p.Length = 0
+ p.EncryptionLevel = protocol.EncryptionLevel(0)
+ p.SendTime = 0
+ p.IsPathMTUProbePacket = false
+ p.includedInBytesInFlight = false
+ p.isPathProbePacket = false
+ return p
+}
+
+// We currently only return Packets back into the pool when they're acknowledged (not when they're lost).
+// This simplifies the code, and gives the vast majority of the performance benefit we can gain from using the pool.
+func putPacket(p *packet) {
+ p.Frames = nil
+ p.StreamFrames = nil
+ packetPool.Put(p)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go
new file mode 100644
index 00000000..4a9db863
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go
@@ -0,0 +1,84 @@
+package ackhandler
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+type packetNumberGenerator interface {
+ Peek() protocol.PacketNumber
+ // Pop pops the packet number.
+ // It reports if the packet number (before the one just popped) was skipped.
+ // It never skips more than one packet number in a row.
+ Pop() (skipped bool, _ protocol.PacketNumber)
+}
+
+type sequentialPacketNumberGenerator struct {
+ next protocol.PacketNumber
+}
+
+var _ packetNumberGenerator = &sequentialPacketNumberGenerator{}
+
+func newSequentialPacketNumberGenerator(initial protocol.PacketNumber) packetNumberGenerator {
+ return &sequentialPacketNumberGenerator{next: initial}
+}
+
+func (p *sequentialPacketNumberGenerator) Peek() protocol.PacketNumber {
+ return p.next
+}
+
+func (p *sequentialPacketNumberGenerator) Pop() (bool, protocol.PacketNumber) {
+ next := p.next
+ p.next++
+ return false, next
+}
+
+// The skippingPacketNumberGenerator generates the packet number for the next packet
+// it randomly skips a packet number every averagePeriod packets (on average).
+// It is guaranteed to never skip two consecutive packet numbers.
+type skippingPacketNumberGenerator struct {
+ period protocol.PacketNumber
+ maxPeriod protocol.PacketNumber
+
+ next protocol.PacketNumber
+ nextToSkip protocol.PacketNumber
+
+ rng utils.Rand
+}
+
+var _ packetNumberGenerator = &skippingPacketNumberGenerator{}
+
+func newSkippingPacketNumberGenerator(initial, initialPeriod, maxPeriod protocol.PacketNumber) packetNumberGenerator {
+ g := &skippingPacketNumberGenerator{
+ next: initial,
+ period: initialPeriod,
+ maxPeriod: maxPeriod,
+ }
+ g.generateNewSkip()
+ return g
+}
+
+func (p *skippingPacketNumberGenerator) Peek() protocol.PacketNumber {
+ if p.next == p.nextToSkip {
+ return p.next + 1
+ }
+ return p.next
+}
+
+func (p *skippingPacketNumberGenerator) Pop() (bool, protocol.PacketNumber) {
+ next := p.next
+ if p.next == p.nextToSkip {
+ next++
+ p.next += 2
+ p.generateNewSkip()
+ return true, next
+ }
+ p.next++ // generate a new packet number for the next packet
+ return false, next
+}
+
+func (p *skippingPacketNumberGenerator) generateNewSkip() {
+ // make sure that there are never two consecutive packet numbers that are skipped
+ p.nextToSkip = p.next + 3 + protocol.PacketNumber(p.rng.Int31n(int32(2*p.period)))
+ p.period = min(2*p.period, p.maxPeriod)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
new file mode 100644
index 00000000..d0d24bf3
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
@@ -0,0 +1,119 @@
+package ackhandler
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type ReceivedPacketHandler struct {
+ initialPackets *receivedPacketTracker
+ handshakePackets *receivedPacketTracker
+ appDataPackets appDataReceivedPacketTracker
+
+ lowest1RTTPacket protocol.PacketNumber
+}
+
+func NewReceivedPacketHandler(logger utils.Logger) *ReceivedPacketHandler {
+ return &ReceivedPacketHandler{
+ initialPackets: newReceivedPacketTracker(),
+ handshakePackets: newReceivedPacketTracker(),
+ appDataPackets: *newAppDataReceivedPacketTracker(logger),
+ lowest1RTTPacket: protocol.InvalidPacketNumber,
+ }
+}
+
+func (h *ReceivedPacketHandler) ReceivedPacket(
+ pn protocol.PacketNumber,
+ ecn protocol.ECN,
+ encLevel protocol.EncryptionLevel,
+ rcvTime monotime.Time,
+ ackEliciting bool,
+) error {
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return h.initialPackets.ReceivedPacket(pn, ecn, ackEliciting)
+ case protocol.EncryptionHandshake:
+ // The Handshake packet number space might already have been dropped as a result
+ // of processing the CRYPTO frame that was contained in this packet.
+ if h.handshakePackets == nil {
+ return nil
+ }
+ return h.handshakePackets.ReceivedPacket(pn, ecn, ackEliciting)
+ case protocol.Encryption0RTT:
+ if h.lowest1RTTPacket != protocol.InvalidPacketNumber && pn > h.lowest1RTTPacket {
+ return fmt.Errorf("received packet number %d on a 0-RTT packet after receiving %d on a 1-RTT packet", pn, h.lowest1RTTPacket)
+ }
+ return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
+ case protocol.Encryption1RTT:
+ if h.lowest1RTTPacket == protocol.InvalidPacketNumber || pn < h.lowest1RTTPacket {
+ h.lowest1RTTPacket = pn
+ }
+ return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
+ default:
+ panic(fmt.Sprintf("received packet with unknown encryption level: %s", encLevel))
+ }
+}
+
+func (h *ReceivedPacketHandler) IgnorePacketsBelow(pn protocol.PacketNumber) {
+ h.appDataPackets.IgnoreBelow(pn)
+}
+
+func (h *ReceivedPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
+ //nolint:exhaustive // 1-RTT packet number space is never dropped.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ h.initialPackets = nil
+ case protocol.EncryptionHandshake:
+ h.handshakePackets = nil
+ case protocol.Encryption0RTT:
+ // Nothing to do here.
+ // If we are rejecting 0-RTT, no 0-RTT packets will have been decrypted.
+ default:
+ panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
+ }
+}
+
+func (h *ReceivedPacketHandler) GetAlarmTimeout() monotime.Time {
+ return h.appDataPackets.GetAlarmTimeout()
+}
+
+func (h *ReceivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel, now monotime.Time, onlyIfQueued bool) *wire.AckFrame {
+ //nolint:exhaustive // 0-RTT packets can't contain ACK frames.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ if h.initialPackets != nil {
+ return h.initialPackets.GetAckFrame()
+ }
+ return nil
+ case protocol.EncryptionHandshake:
+ if h.handshakePackets != nil {
+ return h.handshakePackets.GetAckFrame()
+ }
+ return nil
+ case protocol.Encryption1RTT:
+ return h.appDataPackets.GetAckFrame(now, onlyIfQueued)
+ default:
+ // 0-RTT packets can't contain ACK frames
+ return nil
+ }
+}
+
+func (h *ReceivedPacketHandler) IsPotentiallyDuplicate(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) bool {
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ if h.initialPackets != nil {
+ return h.initialPackets.IsPotentiallyDuplicate(pn)
+ }
+ case protocol.EncryptionHandshake:
+ if h.handshakePackets != nil {
+ return h.handshakePackets.IsPotentiallyDuplicate(pn)
+ }
+ case protocol.Encryption0RTT, protocol.Encryption1RTT:
+ return h.appDataPackets.IsPotentiallyDuplicate(pn)
+ }
+ panic("unexpected encryption level")
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_history.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_history.go
new file mode 100644
index 00000000..d065b6e6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_history.go
@@ -0,0 +1,159 @@
+package ackhandler
+
+import (
+ "iter"
+ "slices"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// interval is an interval from one PacketNumber to the other
+type interval struct {
+ Start protocol.PacketNumber
+ End protocol.PacketNumber
+}
+
+// The receivedPacketHistory stores if a packet number has already been received.
+// It generates ACK ranges which can be used to assemble an ACK frame.
+// It does not store packet contents.
+type receivedPacketHistory struct {
+ ranges []interval // maximum length: protocol.MaxNumAckRanges
+
+ deletedBelow protocol.PacketNumber
+}
+
+func newReceivedPacketHistory() *receivedPacketHistory {
+ return &receivedPacketHistory{
+ deletedBelow: protocol.InvalidPacketNumber,
+ }
+}
+
+// ReceivedPacket registers a packet with PacketNumber p and updates the ranges
+func (h *receivedPacketHistory) ReceivedPacket(p protocol.PacketNumber) bool /* is a new packet (and not a duplicate / delayed packet) */ {
+ // ignore delayed packets, if we already deleted the range
+ if p < h.deletedBelow {
+ return false
+ }
+
+ isNew := h.addToRanges(p)
+ // Delete old ranges, if we're tracking too many of them.
+ // This is a DoS defense against a peer that sends us too many gaps.
+ if len(h.ranges) > protocol.MaxNumAckRanges {
+ h.ranges = slices.Delete(h.ranges, 0, len(h.ranges)-protocol.MaxNumAckRanges)
+ }
+ return isNew
+}
+
+func (h *receivedPacketHistory) addToRanges(p protocol.PacketNumber) bool /* is a new packet (and not a duplicate / delayed packet) */ {
+ if len(h.ranges) == 0 {
+ h.ranges = append(h.ranges, interval{Start: p, End: p})
+ return true
+ }
+
+ for i := len(h.ranges) - 1; i >= 0; i-- {
+ // p already included in an existing range. Nothing to do here
+ if p >= h.ranges[i].Start && p <= h.ranges[i].End {
+ return false
+ }
+
+ if h.ranges[i].End == p-1 { // extend a range at the end
+ h.ranges[i].End = p
+ return true
+ }
+ if h.ranges[i].Start == p+1 { // extend a range at the beginning
+ h.ranges[i].Start = p
+
+ if i > 0 && h.ranges[i-1].End+1 == h.ranges[i].Start { // merge two ranges
+ h.ranges[i-1].End = h.ranges[i].End
+ h.ranges = slices.Delete(h.ranges, i, i+1)
+ }
+ return true
+ }
+
+ // create a new range after the current one
+ if p > h.ranges[i].End {
+ h.ranges = slices.Insert(h.ranges, i+1, interval{Start: p, End: p})
+ return true
+ }
+ }
+
+ // create a new range at the beginning
+ h.ranges = slices.Insert(h.ranges, 0, interval{Start: p, End: p})
+ return true
+}
+
+// DeleteBelow deletes all entries below (but not including) p
+func (h *receivedPacketHistory) DeleteBelow(p protocol.PacketNumber) {
+ if p < h.deletedBelow {
+ return
+ }
+ h.deletedBelow = p
+
+ if len(h.ranges) == 0 {
+ return
+ }
+
+ idx := -1
+ for i := 0; i < len(h.ranges); i++ {
+ if h.ranges[i].End < p { // delete a whole range
+ idx = i
+ } else if p > h.ranges[i].Start && p <= h.ranges[i].End {
+ h.ranges[i].Start = p
+ break
+ } else { // no ranges affected. Nothing to do
+ break
+ }
+ }
+ if idx >= 0 {
+ h.ranges = slices.Delete(h.ranges, 0, idx+1)
+ }
+}
+
+// Backward returns an iterator over the ranges in reverse order
+func (h *receivedPacketHistory) Backward() iter.Seq[interval] {
+ return func(yield func(interval) bool) {
+ for i := len(h.ranges) - 1; i >= 0; i-- {
+ if !yield(h.ranges[i]) {
+ return
+ }
+ }
+ }
+}
+
+func (h *receivedPacketHistory) HighestMissingUpTo(p protocol.PacketNumber) protocol.PacketNumber {
+ if len(h.ranges) == 0 || (h.deletedBelow != protocol.InvalidPacketNumber && p < h.deletedBelow) {
+ return protocol.InvalidPacketNumber
+ }
+ p = min(h.ranges[len(h.ranges)-1].End, p)
+ for i := len(h.ranges) - 1; i >= 0; i-- {
+ r := h.ranges[i]
+ if p >= r.Start && p <= r.End { // p is contained in this range
+ highest := r.Start - 1 // highest packet in the gap before this range
+ if h.deletedBelow != protocol.InvalidPacketNumber && highest < h.deletedBelow {
+ return protocol.InvalidPacketNumber
+ }
+ return highest
+ }
+ if i >= 1 && p > h.ranges[i-1].End && p <= r.Start {
+ // p is in the gap between the previous range and this range
+ return p
+ }
+ }
+ return p
+}
+
+func (h *receivedPacketHistory) IsPotentiallyDuplicate(p protocol.PacketNumber) bool {
+ if p < h.deletedBelow {
+ return true
+ }
+ // Iterating over the slices is faster than using a binary search (using slices.BinarySearchFunc).
+ for i := len(h.ranges) - 1; i >= 0; i-- {
+ if p > h.ranges[i].End {
+ return false
+ }
+ if p <= h.ranges[i].End && p >= h.ranges[i].Start {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
new file mode 100644
index 00000000..64092ccc
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
@@ -0,0 +1,228 @@
+package ackhandler
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+const reorderingThreshold = 1
+
+// The receivedPacketTracker tracks packets for the Initial and Handshake packet number space.
+// Every received packet is acknowledged immediately.
+type receivedPacketTracker struct {
+ ect0, ect1, ecnce uint64
+
+ packetHistory receivedPacketHistory
+
+ lastAck *wire.AckFrame
+ hasNewAck bool // true as soon as we received an ack-eliciting new packet
+}
+
+func newReceivedPacketTracker() *receivedPacketTracker {
+ return &receivedPacketTracker{packetHistory: *newReceivedPacketHistory()}
+}
+
+func (h *receivedPacketTracker) ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, ackEliciting bool) error {
+ if isNew := h.packetHistory.ReceivedPacket(pn); !isNew {
+ return fmt.Errorf("receivedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", pn)
+ }
+
+ //nolint:exhaustive // Only need to count ECT(0), ECT(1) and ECN-CE.
+ switch ecn {
+ case protocol.ECT0:
+ h.ect0++
+ case protocol.ECT1:
+ h.ect1++
+ case protocol.ECNCE:
+ h.ecnce++
+ }
+ if !ackEliciting {
+ return nil
+ }
+ h.hasNewAck = true
+ return nil
+}
+
+func (h *receivedPacketTracker) GetAckFrame() *wire.AckFrame {
+ if !h.hasNewAck {
+ return nil
+ }
+
+ // This function always returns the same ACK frame struct, filled with the most recent values.
+ ack := h.lastAck
+ if ack == nil {
+ ack = &wire.AckFrame{}
+ }
+ ack.Reset()
+ ack.ECT0 = h.ect0
+ ack.ECT1 = h.ect1
+ ack.ECNCE = h.ecnce
+ for r := range h.packetHistory.Backward() {
+ ack.AckRanges = append(ack.AckRanges, wire.AckRange{Smallest: r.Start, Largest: r.End})
+ }
+
+ h.lastAck = ack
+ h.hasNewAck = false
+ return ack
+}
+
+func (h *receivedPacketTracker) IsPotentiallyDuplicate(pn protocol.PacketNumber) bool {
+ return h.packetHistory.IsPotentiallyDuplicate(pn)
+}
+
+// number of ack-eliciting packets received before sending an ACK
+const packetsBeforeAck = 2
+
+// The appDataReceivedPacketTracker tracks packets received in the Application Data packet number space.
+// It waits until at least 2 packets were received before queueing an ACK, or until the max_ack_delay was reached.
+type appDataReceivedPacketTracker struct {
+ receivedPacketTracker
+
+ largestObservedRcvdTime monotime.Time
+
+ largestObserved protocol.PacketNumber
+ ignoreBelow protocol.PacketNumber
+
+ maxAckDelay time.Duration
+ ackQueued bool // true if we need send a new ACK
+
+ ackElicitingPacketsReceivedSinceLastAck int
+ ackAlarm monotime.Time
+
+ logger utils.Logger
+}
+
+func newAppDataReceivedPacketTracker(logger utils.Logger) *appDataReceivedPacketTracker {
+ h := &appDataReceivedPacketTracker{
+ receivedPacketTracker: *newReceivedPacketTracker(),
+ maxAckDelay: protocol.MaxAckDelay,
+ logger: logger,
+ }
+ return h
+}
+
+func (h *appDataReceivedPacketTracker) ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, rcvTime monotime.Time, ackEliciting bool) error {
+ if err := h.receivedPacketTracker.ReceivedPacket(pn, ecn, ackEliciting); err != nil {
+ return err
+ }
+ if pn >= h.largestObserved {
+ h.largestObserved = pn
+ h.largestObservedRcvdTime = rcvTime
+ }
+ if !ackEliciting {
+ return nil
+ }
+ h.ackElicitingPacketsReceivedSinceLastAck++
+ isMissing := h.isMissing(pn)
+ if !h.ackQueued && h.shouldQueueACK(pn, ecn, isMissing) {
+ h.ackQueued = true
+ h.ackAlarm = 0 // cancel the ack alarm
+ }
+ if !h.ackQueued {
+ // No ACK queued, but we'll need to acknowledge the packet after max_ack_delay.
+ h.ackAlarm = rcvTime.Add(h.maxAckDelay)
+ if h.logger.Debug() {
+ h.logger.Debugf("\tSetting ACK timer to max ack delay: %s", h.maxAckDelay)
+ }
+ }
+ return nil
+}
+
+// IgnoreBelow sets a lower limit for acknowledging packets.
+// Packets with packet numbers smaller than p will not be acked.
+func (h *appDataReceivedPacketTracker) IgnoreBelow(pn protocol.PacketNumber) {
+ if pn <= h.ignoreBelow {
+ return
+ }
+ h.ignoreBelow = pn
+ h.packetHistory.DeleteBelow(pn)
+ if h.logger.Debug() {
+ h.logger.Debugf("\tIgnoring all packets below %d.", pn)
+ }
+}
+
+// isMissing says if a packet was reported missing in the last ACK.
+func (h *appDataReceivedPacketTracker) isMissing(p protocol.PacketNumber) bool {
+ if h.lastAck == nil || p < h.ignoreBelow {
+ return false
+ }
+ return p < h.lastAck.LargestAcked() && !h.lastAck.AcksPacket(p)
+}
+
+func (h *appDataReceivedPacketTracker) hasNewMissingPackets() bool {
+ if h.lastAck == nil {
+ return false
+ }
+ if h.largestObserved < reorderingThreshold {
+ return false
+ }
+ highestMissing := h.packetHistory.HighestMissingUpTo(h.largestObserved - reorderingThreshold)
+ if highestMissing == protocol.InvalidPacketNumber {
+ return false
+ }
+ if highestMissing < h.lastAck.LargestAcked() {
+ // the packet was already reported missing in the last ACK
+ return false
+ }
+ return highestMissing > h.lastAck.LargestAcked()-reorderingThreshold
+}
+
+func (h *appDataReceivedPacketTracker) shouldQueueACK(pn protocol.PacketNumber, ecn protocol.ECN, wasMissing bool) bool {
+ // Send an ACK if this packet was reported missing in an ACK sent before.
+ // Ack decimation with reordering relies on the timer to send an ACK, but if
+ // missing packets we reported in the previous ACK, send an ACK immediately.
+ if wasMissing {
+ if h.logger.Debug() {
+ h.logger.Debugf("\tQueueing ACK because packet %d was missing before.", pn)
+ }
+ return true
+ }
+
+ // send an ACK every 2 ack-eliciting packets
+ if h.ackElicitingPacketsReceivedSinceLastAck >= packetsBeforeAck {
+ if h.logger.Debug() {
+ h.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d).", h.ackElicitingPacketsReceivedSinceLastAck, packetsBeforeAck)
+ }
+ return true
+ }
+
+ // queue an ACK if there are new missing packets to report
+ if h.hasNewMissingPackets() {
+ h.logger.Debugf("\tQueuing ACK because there's a new missing packet to report.")
+ return true
+ }
+
+ // queue an ACK if the packet was ECN-CE marked
+ if ecn == protocol.ECNCE {
+ h.logger.Debugf("\tQueuing ACK because the packet was ECN-CE marked.")
+ return true
+ }
+ return false
+}
+
+func (h *appDataReceivedPacketTracker) GetAckFrame(now monotime.Time, onlyIfQueued bool) *wire.AckFrame {
+ if onlyIfQueued && !h.ackQueued {
+ if h.ackAlarm.IsZero() || h.ackAlarm.After(now) {
+ return nil
+ }
+ if h.logger.Debug() && !h.ackAlarm.IsZero() {
+ h.logger.Debugf("Sending ACK because the ACK timer expired.")
+ }
+ }
+ ack := h.receivedPacketTracker.GetAckFrame()
+ if ack == nil {
+ return nil
+ }
+ ack.DelayTime = max(0, now.Sub(h.largestObservedRcvdTime))
+ h.ackQueued = false
+ h.ackAlarm = 0
+ h.ackElicitingPacketsReceivedSinceLastAck = 0
+ return ack
+}
+
+func (h *appDataReceivedPacketTracker) GetAlarmTimeout() monotime.Time { return h.ackAlarm }
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go
new file mode 100644
index 00000000..c03f3a6f
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go
@@ -0,0 +1,46 @@
+package ackhandler
+
+import "fmt"
+
+// The SendMode says what kind of packets can be sent.
+type SendMode uint8
+
+const (
+ // SendNone means that no packets should be sent
+ SendNone SendMode = iota
+ // SendAck means an ACK-only packet should be sent
+ SendAck
+ // SendPTOInitial means that an Initial probe packet should be sent
+ SendPTOInitial
+ // SendPTOHandshake means that a Handshake probe packet should be sent
+ SendPTOHandshake
+ // SendPTOAppData means that an Application data probe packet should be sent
+ SendPTOAppData
+ // SendPacingLimited means that the pacer doesn't allow sending of a packet right now,
+ // but will do in a little while.
+ // The timestamp when sending is allowed again can be obtained via the SentPacketHandler.TimeUntilSend.
+ SendPacingLimited
+ // SendAny means that any packet should be sent
+ SendAny
+)
+
+func (s SendMode) String() string {
+ switch s {
+ case SendNone:
+ return "none"
+ case SendAck:
+ return "ack"
+ case SendPTOInitial:
+ return "pto (Initial)"
+ case SendPTOHandshake:
+ return "pto (Handshake)"
+ case SendPTOAppData:
+ return "pto (Application Data)"
+ case SendAny:
+ return "any"
+ case SendPacingLimited:
+ return "pacing limited"
+ default:
+ return fmt.Sprintf("invalid send mode: %d", s)
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
new file mode 100644
index 00000000..9b539ead
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
@@ -0,0 +1,1143 @@
+package ackhandler
+
+import (
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/congestion"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+const (
+ // Maximum reordering in time space before time based loss detection considers a packet lost.
+ // Specified as an RTT multiplier.
+ timeThreshold = 9.0 / 8
+ // Maximum reordering in packets before packet threshold loss detection considers a packet lost.
+ packetThreshold = 3
+ // Before validating the client's address, the server won't send more than 3x bytes than it received.
+ amplificationFactor = 3
+ // We use Retry packets to derive an RTT estimate. Make sure we don't set the RTT to a super low value yet.
+ minRTTAfterRetry = 5 * time.Millisecond
+ // The PTO duration uses exponential backoff, but is truncated to a maximum value, as allowed by RFC 8961, section 4.4.
+ maxPTODuration = 60 * time.Second
+)
+
+// Path probe packets are declared lost after this time.
+const pathProbePacketLossTimeout = time.Second
+
+type packetNumberSpace struct {
+ history sentPacketHistory
+ pns packetNumberGenerator
+
+ lossTime monotime.Time
+ lastAckElicitingPacketTime monotime.Time
+
+ largestAcked protocol.PacketNumber
+ largestSent protocol.PacketNumber
+}
+
+func newPacketNumberSpace(initialPN protocol.PacketNumber, isAppData bool) *packetNumberSpace {
+ var pns packetNumberGenerator
+ if isAppData {
+ pns = newSkippingPacketNumberGenerator(initialPN, protocol.SkipPacketInitialPeriod, protocol.SkipPacketMaxPeriod)
+ } else {
+ pns = newSequentialPacketNumberGenerator(initialPN)
+ }
+ return &packetNumberSpace{
+ history: *newSentPacketHistory(isAppData),
+ pns: pns,
+ largestSent: protocol.InvalidPacketNumber,
+ largestAcked: protocol.InvalidPacketNumber,
+ }
+}
+
+type alarmTimer struct {
+ Time monotime.Time
+ TimerType qlog.TimerType
+ EncryptionLevel protocol.EncryptionLevel
+}
+
+type sentPacketHandler struct {
+ initialPackets *packetNumberSpace
+ handshakePackets *packetNumberSpace
+ appDataPackets *packetNumberSpace
+ lostPackets lostPacketTracker // only for application-data packet number space
+ // send time of the largest acknowledged packet, across all packet number spaces
+ largestAckedTime monotime.Time
+
+ // Do we know that the peer completed address validation yet?
+ // Always true for the server.
+ peerCompletedAddressValidation bool
+ bytesReceived protocol.ByteCount
+ bytesSent protocol.ByteCount
+ // Have we validated the peer's address yet?
+ // Always true for the client.
+ peerAddressValidated bool
+
+ handshakeConfirmed bool
+
+ ignorePacketsBelow func(protocol.PacketNumber)
+
+ ackedPackets []packetWithPacketNumber // to avoid allocations in detectAndRemoveAckedPackets
+
+ bytesInFlight protocol.ByteCount
+
+ congestion congestion.SendAlgorithmWithDebugInfos
+ rttStats *utils.RTTStats
+ connStats *utils.ConnectionStats
+
+ // The number of times a PTO has been sent without receiving an ack.
+ ptoCount uint32
+ ptoMode SendMode
+ // The number of PTO probe packets that should be sent.
+ // Only applies to the application-data packet number space.
+ numProbesToSend int
+
+ // The alarm timeout
+ alarm alarmTimer
+
+ enableECN bool
+ ecnTracker ecnHandler
+
+ perspective protocol.Perspective
+
+ qlogger qlogwriter.Recorder
+ lastMetrics qlog.MetricsUpdated
+ logger utils.Logger
+}
+
+var _ SentPacketHandler = &sentPacketHandler{}
+
+// clientAddressValidated indicates whether the address was validated beforehand by an address validation token.
+// If the address was validated, the amplification limit doesn't apply. It has no effect for a client.
+func NewSentPacketHandler(
+ initialPN protocol.PacketNumber,
+ initialMaxDatagramSize protocol.ByteCount,
+ rttStats *utils.RTTStats,
+ connStats *utils.ConnectionStats,
+ clientAddressValidated bool,
+ enableECN bool,
+ ignorePacketsBelow func(protocol.PacketNumber),
+ pers protocol.Perspective,
+ qlogger qlogwriter.Recorder,
+ logger utils.Logger,
+) SentPacketHandler {
+ congestion := congestion.NewCubicSender(
+ congestion.DefaultClock{},
+ rttStats,
+ connStats,
+ initialMaxDatagramSize,
+ true, // use Reno
+ qlogger,
+ )
+
+ h := &sentPacketHandler{
+ peerCompletedAddressValidation: pers == protocol.PerspectiveServer,
+ peerAddressValidated: pers == protocol.PerspectiveClient || clientAddressValidated,
+ initialPackets: newPacketNumberSpace(initialPN, false),
+ handshakePackets: newPacketNumberSpace(0, false),
+ appDataPackets: newPacketNumberSpace(0, true),
+ lostPackets: *newLostPacketTracker(64),
+ rttStats: rttStats,
+ connStats: connStats,
+ congestion: congestion,
+ ignorePacketsBelow: ignorePacketsBelow,
+ perspective: pers,
+ qlogger: qlogger,
+ logger: logger,
+ }
+ if enableECN {
+ h.enableECN = true
+ h.ecnTracker = newECNTracker(logger, qlogger)
+ }
+ return h
+}
+
+func (h *sentPacketHandler) removeFromBytesInFlight(p *packet) {
+ if p.includedInBytesInFlight {
+ if p.Length > h.bytesInFlight {
+ panic("negative bytes_in_flight")
+ }
+ h.bytesInFlight -= p.Length
+ p.includedInBytesInFlight = false
+ }
+}
+
+func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel, now monotime.Time) {
+ // The server won't await address validation after the handshake is confirmed.
+ // This applies even if we didn't receive an ACK for a Handshake packet.
+ if h.perspective == protocol.PerspectiveClient && encLevel == protocol.EncryptionHandshake {
+ h.peerCompletedAddressValidation = true
+ }
+ // remove outstanding packets from bytes_in_flight
+ if encLevel == protocol.EncryptionInitial || encLevel == protocol.EncryptionHandshake {
+ pnSpace := h.getPacketNumberSpace(encLevel)
+ // We might already have dropped this packet number space.
+ if pnSpace == nil {
+ return
+ }
+ for _, p := range pnSpace.history.Packets() {
+ h.removeFromBytesInFlight(p)
+ }
+ }
+ // drop the packet history
+ //nolint:exhaustive // Not every packet number space can be dropped.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ h.initialPackets = nil
+ case protocol.EncryptionHandshake:
+ // Dropping the handshake packet number space means that the handshake is confirmed,
+ // see section 4.9.2 of RFC 9001.
+ h.handshakeConfirmed = true
+ h.handshakePackets = nil
+ case protocol.Encryption0RTT:
+ // This function is only called when 0-RTT is rejected,
+ // and not when the client drops 0-RTT keys when the handshake completes.
+ // When 0-RTT is rejected, all application data sent so far becomes invalid.
+ // Delete the packets from the history and remove them from bytes_in_flight.
+ for pn, p := range h.appDataPackets.history.Packets() {
+ if p.EncryptionLevel != protocol.Encryption0RTT {
+ break
+ }
+ h.removeFromBytesInFlight(p)
+ h.appDataPackets.history.Remove(pn)
+ }
+ default:
+ panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
+ }
+ if h.qlogger != nil && h.ptoCount != 0 {
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
+ }
+ h.ptoCount = 0
+ h.numProbesToSend = 0
+ h.ptoMode = SendNone
+ h.setLossDetectionTimer(now)
+}
+
+func (h *sentPacketHandler) ReceivedBytes(n protocol.ByteCount, t monotime.Time) {
+ h.connStats.BytesReceived.Add(uint64(n))
+ wasAmplificationLimit := h.isAmplificationLimited()
+ h.bytesReceived += n
+ if wasAmplificationLimit && !h.isAmplificationLimited() {
+ h.setLossDetectionTimer(t)
+ }
+}
+
+func (h *sentPacketHandler) ReceivedPacket(l protocol.EncryptionLevel, t monotime.Time) {
+ h.connStats.PacketsReceived.Add(1)
+ if h.perspective == protocol.PerspectiveServer && l == protocol.EncryptionHandshake && !h.peerAddressValidated {
+ h.peerAddressValidated = true
+ h.setLossDetectionTimer(t)
+ }
+}
+
+func (h *sentPacketHandler) packetsInFlight() int {
+ packetsInFlight := h.appDataPackets.history.NumOutstanding()
+ if h.handshakePackets != nil {
+ packetsInFlight += h.handshakePackets.history.NumOutstanding()
+ }
+ if h.initialPackets != nil {
+ packetsInFlight += h.initialPackets.history.NumOutstanding()
+ }
+ return packetsInFlight
+}
+
+func (h *sentPacketHandler) SentPacket(
+ t monotime.Time,
+ pn, largestAcked protocol.PacketNumber,
+ streamFrames []StreamFrame,
+ frames []Frame,
+ encLevel protocol.EncryptionLevel,
+ ecn protocol.ECN,
+ size protocol.ByteCount,
+ isPathMTUProbePacket bool,
+ isPathProbePacket bool,
+) {
+ h.bytesSent += size
+ h.connStats.BytesSent.Add(uint64(size))
+ h.connStats.PacketsSent.Add(1)
+
+ pnSpace := h.getPacketNumberSpace(encLevel)
+ if h.logger.Debug() && (pnSpace.history.HasOutstandingPackets() || pnSpace.history.HasOutstandingPathProbes()) {
+ for p := max(0, pnSpace.largestSent+1); p < pn; p++ {
+ h.logger.Debugf("Skipping packet number %d", p)
+ }
+ }
+
+ pnSpace.largestSent = pn
+
+ p := getPacket()
+ p.SendTime = t
+ p.EncryptionLevel = encLevel
+ p.Length = size
+ p.Frames = frames
+ p.LargestAcked = largestAcked
+ p.StreamFrames = streamFrames
+ p.IsPathMTUProbePacket = isPathMTUProbePacket
+ p.isPathProbePacket = isPathProbePacket
+ isAckEliciting := p.IsAckEliciting()
+
+ if isPathProbePacket {
+ pnSpace.history.SentPathProbePacket(pn, p)
+ h.setLossDetectionTimer(t)
+ return
+ }
+ if isAckEliciting {
+ pnSpace.lastAckElicitingPacketTime = t
+ h.bytesInFlight += size
+ p.includedInBytesInFlight = true
+ if h.numProbesToSend > 0 {
+ h.numProbesToSend--
+ }
+ }
+ h.congestion.OnPacketSent(t, h.bytesInFlight, pn, size, isAckEliciting)
+
+ if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil {
+ h.ecnTracker.SentPacket(pn, ecn)
+ }
+
+ pnSpace.history.SentPacket(pn, p)
+ if !isAckEliciting {
+ if !h.peerCompletedAddressValidation {
+ h.setLossDetectionTimer(t)
+ }
+ return
+ }
+ if h.qlogger != nil {
+ h.qlogMetricsUpdated()
+ }
+ h.setLossDetectionTimer(t)
+}
+
+func (h *sentPacketHandler) qlogMetricsUpdated() {
+ var metricsUpdatedEvent qlog.MetricsUpdated
+ var updated bool
+ if h.rttStats.HasMeasurement() {
+ if h.lastMetrics.MinRTT != h.rttStats.MinRTT() {
+ metricsUpdatedEvent.MinRTT = h.rttStats.MinRTT()
+ h.lastMetrics.MinRTT = metricsUpdatedEvent.MinRTT
+ updated = true
+ }
+ if h.lastMetrics.SmoothedRTT != h.rttStats.SmoothedRTT() {
+ metricsUpdatedEvent.SmoothedRTT = h.rttStats.SmoothedRTT()
+ h.lastMetrics.SmoothedRTT = metricsUpdatedEvent.SmoothedRTT
+ updated = true
+ }
+ if h.lastMetrics.LatestRTT != h.rttStats.LatestRTT() {
+ metricsUpdatedEvent.LatestRTT = h.rttStats.LatestRTT()
+ h.lastMetrics.LatestRTT = metricsUpdatedEvent.LatestRTT
+ updated = true
+ }
+ if h.lastMetrics.RTTVariance != h.rttStats.MeanDeviation() {
+ metricsUpdatedEvent.RTTVariance = h.rttStats.MeanDeviation()
+ h.lastMetrics.RTTVariance = metricsUpdatedEvent.RTTVariance
+ updated = true
+ }
+ }
+ if cwnd := h.congestion.GetCongestionWindow(); h.lastMetrics.CongestionWindow != int(cwnd) {
+ metricsUpdatedEvent.CongestionWindow = int(cwnd)
+ h.lastMetrics.CongestionWindow = metricsUpdatedEvent.CongestionWindow
+ updated = true
+ }
+ if h.lastMetrics.BytesInFlight != int(h.bytesInFlight) {
+ metricsUpdatedEvent.BytesInFlight = int(h.bytesInFlight)
+ h.lastMetrics.BytesInFlight = metricsUpdatedEvent.BytesInFlight
+ updated = true
+ }
+ packetsInFlight := h.packetsInFlight()
+ if h.lastMetrics.PacketsInFlight != packetsInFlight {
+ metricsUpdatedEvent.PacketsInFlight = packetsInFlight
+ h.lastMetrics.PacketsInFlight = metricsUpdatedEvent.PacketsInFlight
+ updated = true
+ }
+ if updated {
+ h.qlogger.RecordEvent(metricsUpdatedEvent)
+ }
+}
+
+func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLevel) *packetNumberSpace {
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return h.initialPackets
+ case protocol.EncryptionHandshake:
+ return h.handshakePackets
+ case protocol.Encryption0RTT, protocol.Encryption1RTT:
+ return h.appDataPackets
+ default:
+ panic("invalid packet number space")
+ }
+}
+
+func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime monotime.Time) (bool /* contained 1-RTT packet */, error) {
+ pnSpace := h.getPacketNumberSpace(encLevel)
+
+ largestAcked := ack.LargestAcked()
+ if largestAcked > pnSpace.largestSent {
+ return false, &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "received ACK for an unsent packet",
+ }
+ }
+
+ // Servers complete address validation when a protected packet is received.
+ if h.perspective == protocol.PerspectiveClient && !h.peerCompletedAddressValidation &&
+ (encLevel == protocol.EncryptionHandshake || encLevel == protocol.Encryption1RTT) {
+ h.peerCompletedAddressValidation = true
+ h.logger.Debugf("Peer doesn't await address validation any longer.")
+ // Make sure that the timer is reset, even if this ACK doesn't acknowledge any (ack-eliciting) packets.
+ h.setLossDetectionTimer(rcvTime)
+ }
+
+ priorInFlight := h.bytesInFlight
+ ackedPackets, hasAckEliciting, err := h.detectAndRemoveAckedPackets(ack, encLevel)
+ if err != nil || len(ackedPackets) == 0 {
+ return false, err
+ }
+ // update the RTT, if:
+ // * the largest acked is newly acknowledged, AND
+ // * at least one new ack-eliciting packet was acknowledged
+ if len(ackedPackets) > 0 {
+ if p := ackedPackets[len(ackedPackets)-1]; p.PacketNumber == ack.LargestAcked() && !p.isPathProbePacket && hasAckEliciting {
+ // don't use the ack delay for Initial and Handshake packets
+ var ackDelay time.Duration
+ if encLevel == protocol.Encryption1RTT {
+ ackDelay = min(ack.DelayTime, h.rttStats.MaxAckDelay())
+ }
+ if h.largestAckedTime.IsZero() || !p.SendTime.Before(h.largestAckedTime) {
+ h.rttStats.UpdateRTT(rcvTime.Sub(p.SendTime), ackDelay)
+ if h.logger.Debug() {
+ h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
+ }
+ h.largestAckedTime = p.SendTime
+ }
+ h.congestion.MaybeExitSlowStart()
+ }
+ }
+
+ // Only inform the ECN tracker about new 1-RTT ACKs if the ACK increases the largest acked.
+ if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil && largestAcked > pnSpace.largestAcked {
+ congested := h.ecnTracker.HandleNewlyAcked(ackedPackets, int64(ack.ECT0), int64(ack.ECT1), int64(ack.ECNCE))
+ if congested {
+ h.congestion.OnCongestionEvent(largestAcked, 0, priorInFlight)
+ }
+ }
+
+ pnSpace.largestAcked = max(pnSpace.largestAcked, largestAcked)
+
+ h.detectLostPackets(rcvTime, encLevel)
+ if encLevel == protocol.Encryption1RTT {
+ h.detectLostPathProbes(rcvTime)
+ }
+ var acked1RTTPacket bool
+ for _, p := range ackedPackets {
+ if p.includedInBytesInFlight {
+ h.congestion.OnPacketAcked(p.PacketNumber, p.Length, priorInFlight, rcvTime)
+ }
+ if p.EncryptionLevel == protocol.Encryption1RTT {
+ acked1RTTPacket = true
+ }
+ h.removeFromBytesInFlight(p.packet)
+ if !p.isPathProbePacket {
+ putPacket(p.packet)
+ }
+ }
+
+ // detect spurious losses for application data packets, if the ACK was not reordered
+ if encLevel == protocol.Encryption1RTT && largestAcked == pnSpace.largestAcked {
+ h.detectSpuriousLosses(
+ ack,
+ rcvTime.Add(-min(ack.DelayTime, h.rttStats.MaxAckDelay())),
+ )
+ // clean up lost packet history
+ h.lostPackets.DeleteBefore(rcvTime.Add(-3 * h.rttStats.PTO(false)))
+ }
+
+ // After this point, we must not use ackedPackets any longer!
+ // We've already returned the buffers.
+ ackedPackets = nil //nolint:ineffassign // This is just to be on the safe side.
+ clear(h.ackedPackets) // make sure the memory is released
+ h.ackedPackets = h.ackedPackets[:0]
+
+ // Reset the pto_count unless the client is unsure if the server has validated the client's address.
+ if h.peerCompletedAddressValidation {
+ if h.qlogger != nil && h.ptoCount != 0 {
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
+ }
+ h.ptoCount = 0
+ }
+ h.numProbesToSend = 0
+
+ if h.qlogger != nil {
+ h.qlogMetricsUpdated()
+ }
+
+ h.setLossDetectionTimer(rcvTime)
+ return acked1RTTPacket, nil
+}
+
+func (h *sentPacketHandler) detectSpuriousLosses(ack *wire.AckFrame, ackTime monotime.Time) {
+ var maxPacketReordering protocol.PacketNumber
+ var maxTimeReordering time.Duration
+ ackRangeIdx := len(ack.AckRanges) - 1
+ var spuriousLosses []protocol.PacketNumber
+ for pn, sendTime := range h.lostPackets.All() {
+ ackRange := ack.AckRanges[ackRangeIdx]
+ for pn > ackRange.Largest {
+ // this should never happen, since detectSpuriousLosses is only called for ACKs that increase the largest acked
+ if ackRangeIdx == 0 {
+ break
+ }
+ ackRangeIdx--
+ ackRange = ack.AckRanges[ackRangeIdx]
+ }
+ if pn < ackRange.Smallest {
+ continue
+ }
+ if pn <= ackRange.Largest {
+ packetReordering := h.appDataPackets.history.Difference(ack.LargestAcked(), pn)
+ timeReordering := ackTime.Sub(sendTime)
+ maxPacketReordering = max(maxPacketReordering, packetReordering)
+ maxTimeReordering = max(maxTimeReordering, timeReordering)
+
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.SpuriousLoss{
+ EncryptionLevel: protocol.Encryption1RTT,
+ PacketNumber: pn,
+ PacketReordering: uint64(packetReordering),
+ TimeReordering: timeReordering,
+ })
+ }
+ spuriousLosses = append(spuriousLosses, pn)
+ }
+ }
+ for _, pn := range spuriousLosses {
+ h.lostPackets.Delete(pn)
+ }
+}
+
+// Packets are returned in ascending packet number order.
+func (h *sentPacketHandler) detectAndRemoveAckedPackets(
+ ack *wire.AckFrame,
+ encLevel protocol.EncryptionLevel,
+) (_ []packetWithPacketNumber, hasAckEliciting bool, _ error) {
+ if len(h.ackedPackets) > 0 {
+ return nil, false, errors.New("ackhandler BUG: ackedPackets slice not empty")
+ }
+
+ pnSpace := h.getPacketNumberSpace(encLevel)
+
+ if encLevel == protocol.Encryption1RTT {
+ for p := range pnSpace.history.SkippedPackets() {
+ if ack.AcksPacket(p) {
+ return nil, false, &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: fmt.Sprintf("received an ACK for skipped packet number: %d (%s)", p, encLevel),
+ }
+ }
+ }
+ }
+
+ var ackRangeIndex int
+ lowestAcked := ack.LowestAcked()
+ largestAcked := ack.LargestAcked()
+ for pn, p := range pnSpace.history.Packets() {
+ // ignore packets below the lowest acked
+ if pn < lowestAcked {
+ continue
+ }
+ if pn > largestAcked {
+ break
+ }
+
+ if ack.HasMissingRanges() {
+ ackRange := ack.AckRanges[len(ack.AckRanges)-1-ackRangeIndex]
+
+ for pn > ackRange.Largest && ackRangeIndex < len(ack.AckRanges)-1 {
+ ackRangeIndex++
+ ackRange = ack.AckRanges[len(ack.AckRanges)-1-ackRangeIndex]
+ }
+
+ if pn < ackRange.Smallest { // packet not contained in ACK range
+ continue
+ }
+ if pn > ackRange.Largest {
+ return nil, false, fmt.Errorf("BUG: ackhandler would have acked wrong packet %d, while evaluating range %d -> %d", pn, ackRange.Smallest, ackRange.Largest)
+ }
+ }
+ if p.isPathProbePacket {
+ probePacket := pnSpace.history.RemovePathProbe(pn)
+ // the probe packet might already have been declared lost
+ if probePacket != nil {
+ h.ackedPackets = append(h.ackedPackets, packetWithPacketNumber{PacketNumber: pn, packet: probePacket})
+ }
+ continue
+ }
+ if p.IsAckEliciting() {
+ hasAckEliciting = true
+ }
+ h.ackedPackets = append(h.ackedPackets, packetWithPacketNumber{PacketNumber: pn, packet: p})
+ }
+ if h.logger.Debug() && len(h.ackedPackets) > 0 {
+ pns := make([]protocol.PacketNumber, len(h.ackedPackets))
+ for i, p := range h.ackedPackets {
+ pns[i] = p.PacketNumber
+ }
+ h.logger.Debugf("\tnewly acked packets (%d): %d", len(pns), pns)
+ }
+
+ for _, p := range h.ackedPackets {
+ if p.LargestAcked != protocol.InvalidPacketNumber && encLevel == protocol.Encryption1RTT && h.ignorePacketsBelow != nil {
+ h.ignorePacketsBelow(p.LargestAcked + 1)
+ }
+
+ for _, f := range p.Frames {
+ if f.Handler != nil {
+ f.Handler.OnAcked(f.Frame)
+ }
+ }
+ for _, f := range p.StreamFrames {
+ if f.Handler != nil {
+ f.Handler.OnAcked(f.Frame)
+ }
+ }
+ if err := pnSpace.history.Remove(p.PacketNumber); err != nil {
+ return nil, false, err
+ }
+ }
+ // TODO: add support for the transport:packets_acked qlog event
+ return h.ackedPackets, hasAckEliciting, nil
+}
+
+func (h *sentPacketHandler) getLossTimeAndSpace() (monotime.Time, protocol.EncryptionLevel) {
+ var encLevel protocol.EncryptionLevel
+ var lossTime monotime.Time
+
+ if h.initialPackets != nil {
+ lossTime = h.initialPackets.lossTime
+ encLevel = protocol.EncryptionInitial
+ }
+ if h.handshakePackets != nil && (lossTime.IsZero() || (!h.handshakePackets.lossTime.IsZero() && h.handshakePackets.lossTime.Before(lossTime))) {
+ lossTime = h.handshakePackets.lossTime
+ encLevel = protocol.EncryptionHandshake
+ }
+ if lossTime.IsZero() || (!h.appDataPackets.lossTime.IsZero() && h.appDataPackets.lossTime.Before(lossTime)) {
+ lossTime = h.appDataPackets.lossTime
+ encLevel = protocol.Encryption1RTT
+ }
+ return lossTime, encLevel
+}
+
+func (h *sentPacketHandler) getScaledPTO(includeMaxAckDelay bool) time.Duration {
+ pto := h.rttStats.PTO(includeMaxAckDelay) << h.ptoCount
+ if pto > maxPTODuration || pto <= 0 {
+ return maxPTODuration
+ }
+ return pto
+}
+
+// same logic as getLossTimeAndSpace, but for lastAckElicitingPacketTime instead of lossTime
+func (h *sentPacketHandler) getPTOTimeAndSpace(now monotime.Time) (pto monotime.Time, encLevel protocol.EncryptionLevel) {
+ // We only send application data probe packets once the handshake is confirmed,
+ // because before that, we don't have the keys to decrypt ACKs sent in 1-RTT packets.
+ if !h.handshakeConfirmed && !h.hasOutstandingCryptoPackets() {
+ if h.peerCompletedAddressValidation {
+ return
+ }
+ t := now.Add(h.getScaledPTO(false))
+ if h.initialPackets != nil {
+ return t, protocol.EncryptionInitial
+ }
+ return t, protocol.EncryptionHandshake
+ }
+
+ if h.initialPackets != nil && h.initialPackets.history.HasOutstandingPackets() &&
+ !h.initialPackets.lastAckElicitingPacketTime.IsZero() {
+ encLevel = protocol.EncryptionInitial
+ if t := h.initialPackets.lastAckElicitingPacketTime; !t.IsZero() {
+ pto = t.Add(h.getScaledPTO(false))
+ }
+ }
+ if h.handshakePackets != nil && h.handshakePackets.history.HasOutstandingPackets() &&
+ !h.handshakePackets.lastAckElicitingPacketTime.IsZero() {
+ t := h.handshakePackets.lastAckElicitingPacketTime.Add(h.getScaledPTO(false))
+ if pto.IsZero() || (!t.IsZero() && t.Before(pto)) {
+ pto = t
+ encLevel = protocol.EncryptionHandshake
+ }
+ }
+ if h.handshakeConfirmed && h.appDataPackets.history.HasOutstandingPackets() &&
+ !h.appDataPackets.lastAckElicitingPacketTime.IsZero() {
+ t := h.appDataPackets.lastAckElicitingPacketTime.Add(h.getScaledPTO(true))
+ if pto.IsZero() || (!t.IsZero() && t.Before(pto)) {
+ pto = t
+ encLevel = protocol.Encryption1RTT
+ }
+ }
+ return pto, encLevel
+}
+
+func (h *sentPacketHandler) hasOutstandingCryptoPackets() bool {
+ if h.initialPackets != nil && h.initialPackets.history.HasOutstandingPackets() {
+ return true
+ }
+ if h.handshakePackets != nil && h.handshakePackets.history.HasOutstandingPackets() {
+ return true
+ }
+ return false
+}
+
+func (h *sentPacketHandler) setLossDetectionTimer(now monotime.Time) {
+ oldAlarm := h.alarm // only needed in case tracing is enabled
+ newAlarm := h.lossDetectionTime(now)
+ h.alarm = newAlarm
+
+ hasAlarm := !newAlarm.Time.IsZero()
+ if !hasAlarm && !oldAlarm.Time.IsZero() {
+ h.logger.Debugf("Canceling loss detection timer.")
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeCancelled,
+ })
+ }
+ }
+
+ if h.qlogger != nil && hasAlarm && newAlarm != oldAlarm {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeSet,
+ TimerType: newAlarm.TimerType,
+ EncLevel: newAlarm.EncryptionLevel,
+ Time: newAlarm.Time.ToTime(),
+ })
+ }
+}
+
+func (h *sentPacketHandler) lossDetectionTime(now monotime.Time) alarmTimer {
+ // cancel the alarm if no packets are outstanding
+ if h.peerCompletedAddressValidation && !h.hasOutstandingCryptoPackets() &&
+ !h.appDataPackets.history.HasOutstandingPackets() && !h.appDataPackets.history.HasOutstandingPathProbes() {
+ return alarmTimer{}
+ }
+
+ // cancel the alarm if amplification limited
+ if h.isAmplificationLimited() {
+ return alarmTimer{}
+ }
+
+ var pathProbeLossTime monotime.Time
+ if h.appDataPackets.history.HasOutstandingPathProbes() {
+ if _, p := h.appDataPackets.history.FirstOutstandingPathProbe(); p != nil {
+ pathProbeLossTime = p.SendTime.Add(pathProbePacketLossTimeout)
+ }
+ }
+
+ // early retransmit timer or time loss detection
+ lossTime, encLevel := h.getLossTimeAndSpace()
+ if !lossTime.IsZero() && (pathProbeLossTime.IsZero() || lossTime.Before(pathProbeLossTime)) {
+ return alarmTimer{
+ Time: lossTime,
+ TimerType: qlog.TimerTypeACK,
+ EncryptionLevel: encLevel,
+ }
+ }
+ ptoTime, encLevel := h.getPTOTimeAndSpace(now)
+ if !ptoTime.IsZero() && (pathProbeLossTime.IsZero() || ptoTime.Before(pathProbeLossTime)) {
+ return alarmTimer{
+ Time: ptoTime,
+ TimerType: qlog.TimerTypePTO,
+ EncryptionLevel: encLevel,
+ }
+ }
+ if !pathProbeLossTime.IsZero() {
+ return alarmTimer{
+ Time: pathProbeLossTime,
+ TimerType: qlog.TimerTypePathProbe,
+ EncryptionLevel: protocol.Encryption1RTT,
+ }
+ }
+ return alarmTimer{}
+}
+
+func (h *sentPacketHandler) detectLostPathProbes(now monotime.Time) {
+ if !h.appDataPackets.history.HasOutstandingPathProbes() {
+ return
+ }
+ lossTime := now.Add(-pathProbePacketLossTimeout)
+ // RemovePathProbe cannot be called while iterating.
+ var lostPathProbes []packetWithPacketNumber
+ for pn, p := range h.appDataPackets.history.PathProbes() {
+ if !p.SendTime.After(lossTime) {
+ lostPathProbes = append(lostPathProbes, packetWithPacketNumber{PacketNumber: pn, packet: p})
+ }
+ }
+ for _, p := range lostPathProbes {
+ for _, f := range p.Frames {
+ f.Handler.OnLost(f.Frame)
+ }
+ h.appDataPackets.history.RemovePathProbe(p.PacketNumber)
+ }
+}
+
+func (h *sentPacketHandler) detectLostPackets(now monotime.Time, encLevel protocol.EncryptionLevel) {
+ pnSpace := h.getPacketNumberSpace(encLevel)
+ pnSpace.lossTime = 0
+
+ maxRTT := float64(max(h.rttStats.LatestRTT(), h.rttStats.SmoothedRTT()))
+ lossDelay := time.Duration(timeThreshold * maxRTT)
+
+ // Minimum time of granularity before packets are deemed lost.
+ lossDelay = max(lossDelay, protocol.TimerGranularity)
+
+ // Packets sent before this time are deemed lost.
+ lostSendTime := now.Add(-lossDelay)
+
+ priorInFlight := h.bytesInFlight
+ for pn, p := range pnSpace.history.Packets() {
+ if pn > pnSpace.largestAcked {
+ break
+ }
+
+ var packetLost bool
+ if !p.SendTime.After(lostSendTime) {
+ packetLost = true
+ if !p.isPathProbePacket && p.IsAckEliciting() {
+ if h.logger.Debug() {
+ h.logger.Debugf("\tlost packet %d (time threshold)", pn)
+ }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.PacketLost{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.EncryptionLevelToPacketType(p.EncryptionLevel),
+ PacketNumber: pn,
+ },
+ Trigger: qlog.PacketLossTimeThreshold,
+ })
+ }
+ }
+ } else if pnSpace.history.Difference(pnSpace.largestAcked, pn) >= packetThreshold {
+ packetLost = true
+ if !p.isPathProbePacket && p.IsAckEliciting() {
+ if h.logger.Debug() {
+ h.logger.Debugf("\tlost packet %d (reordering threshold)", pn)
+ }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.PacketLost{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.EncryptionLevelToPacketType(p.EncryptionLevel),
+ PacketNumber: pn,
+ },
+ Trigger: qlog.PacketLossReorderingThreshold,
+ })
+ }
+ }
+ } else if pnSpace.lossTime.IsZero() {
+ // Note: This conditional is only entered once per call
+ lossTime := p.SendTime.Add(lossDelay)
+ if h.logger.Debug() {
+ h.logger.Debugf("\tsetting loss timer for packet %d (%s) to %s (in %s)", pn, encLevel, lossDelay, lossTime)
+ }
+ pnSpace.lossTime = lossTime
+ }
+ if packetLost {
+ if encLevel == protocol.Encryption0RTT || encLevel == protocol.Encryption1RTT {
+ h.lostPackets.Add(pn, p.SendTime)
+ }
+ pnSpace.history.DeclareLost(pn)
+ if !p.isPathProbePacket && p.IsAckEliciting() {
+ // the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
+ h.removeFromBytesInFlight(p)
+ h.queueFramesForRetransmission(p)
+ if !p.IsPathMTUProbePacket {
+ h.congestion.OnCongestionEvent(pn, p.Length, priorInFlight)
+ }
+ if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil {
+ h.ecnTracker.LostPacket(pn)
+ }
+ }
+ }
+ }
+}
+
+func (h *sentPacketHandler) OnLossDetectionTimeout(now monotime.Time) error {
+ defer h.setLossDetectionTimer(now)
+
+ if h.handshakeConfirmed {
+ h.detectLostPathProbes(now)
+ }
+
+ earliestLossTime, encLevel := h.getLossTimeAndSpace()
+ if !earliestLossTime.IsZero() {
+ if h.logger.Debug() {
+ h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", earliestLossTime)
+ }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeExpired,
+ TimerType: qlog.TimerTypeACK,
+ EncLevel: encLevel,
+ })
+ }
+ // Early retransmit or time loss detection
+ h.detectLostPackets(now, encLevel)
+ return nil
+ }
+
+ // PTO
+ // When all outstanding are acknowledged, the alarm is canceled in setLossDetectionTimer.
+ // However, there's no way to reset the timer in the connection.
+ // When OnLossDetectionTimeout is called, we therefore need to make sure that there are
+ // actually packets outstanding.
+ if h.bytesInFlight == 0 && !h.peerCompletedAddressValidation {
+ h.ptoCount++
+ h.numProbesToSend++
+ if h.initialPackets != nil {
+ h.ptoMode = SendPTOInitial
+ } else if h.handshakePackets != nil {
+ h.ptoMode = SendPTOHandshake
+ } else {
+ return errors.New("sentPacketHandler BUG: PTO fired, but bytes_in_flight is 0 and Initial and Handshake already dropped")
+ }
+ return nil
+ }
+
+ ptoTime, encLevel := h.getPTOTimeAndSpace(now)
+ if ptoTime.IsZero() {
+ return nil
+ }
+ ps := h.getPacketNumberSpace(encLevel)
+ if !ps.history.HasOutstandingPackets() && !ps.history.HasOutstandingPathProbes() && !h.peerCompletedAddressValidation {
+ return nil
+ }
+ h.ptoCount++
+ if h.logger.Debug() {
+ h.logger.Debugf("Loss detection alarm for %s fired in PTO mode. PTO count: %d", encLevel, h.ptoCount)
+ }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeExpired,
+ TimerType: qlog.TimerTypePTO,
+ EncLevel: encLevel,
+ })
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: h.ptoCount})
+ }
+ h.numProbesToSend += 2
+ //nolint:exhaustive // We never arm a PTO timer for 0-RTT packets.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ h.ptoMode = SendPTOInitial
+ case protocol.EncryptionHandshake:
+ h.ptoMode = SendPTOHandshake
+ case protocol.Encryption1RTT:
+ // skip a packet number in order to elicit an immediate ACK
+ pn := h.PopPacketNumber(protocol.Encryption1RTT)
+ h.getPacketNumberSpace(protocol.Encryption1RTT).history.SkippedPacket(pn)
+ h.ptoMode = SendPTOAppData
+ default:
+ return fmt.Errorf("PTO timer in unexpected encryption level: %s", encLevel)
+ }
+ return nil
+}
+
+func (h *sentPacketHandler) GetLossDetectionTimeout() monotime.Time {
+ return h.alarm.Time
+}
+
+func (h *sentPacketHandler) ECNMode(isShortHeaderPacket bool) protocol.ECN {
+ if !h.enableECN {
+ return protocol.ECNUnsupported
+ }
+ if !isShortHeaderPacket {
+ return protocol.ECNNon
+ }
+ return h.ecnTracker.Mode()
+}
+
+func (h *sentPacketHandler) PeekPacketNumber(encLevel protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen) {
+ pnSpace := h.getPacketNumberSpace(encLevel)
+ pn := pnSpace.pns.Peek()
+ // See section 17.1 of RFC 9000.
+ return pn, protocol.PacketNumberLengthForHeader(pn, pnSpace.largestAcked)
+}
+
+func (h *sentPacketHandler) PopPacketNumber(encLevel protocol.EncryptionLevel) protocol.PacketNumber {
+ pnSpace := h.getPacketNumberSpace(encLevel)
+ skipped, pn := pnSpace.pns.Pop()
+ if skipped {
+ skippedPN := pn - 1
+ pnSpace.history.SkippedPacket(skippedPN)
+ if h.logger.Debug() {
+ h.logger.Debugf("Skipping packet number %d", skippedPN)
+ }
+ }
+ return pn
+}
+
+func (h *sentPacketHandler) SendMode(now monotime.Time) SendMode {
+ numTrackedPackets := h.appDataPackets.history.Len()
+ if h.initialPackets != nil {
+ numTrackedPackets += h.initialPackets.history.Len()
+ }
+ if h.handshakePackets != nil {
+ numTrackedPackets += h.handshakePackets.history.Len()
+ }
+
+ if h.isAmplificationLimited() {
+ h.logger.Debugf("Amplification window limited. Received %d bytes, already sent out %d bytes", h.bytesReceived, h.bytesSent)
+ return SendNone
+ }
+ // Don't send any packets if we're keeping track of the maximum number of packets.
+ // Note that since MaxOutstandingSentPackets is smaller than MaxTrackedSentPackets,
+ // we will stop sending out new data when reaching MaxOutstandingSentPackets,
+ // but still allow sending of retransmissions and ACKs.
+ if numTrackedPackets >= protocol.MaxTrackedSentPackets {
+ if h.logger.Debug() {
+ h.logger.Debugf("Limited by the number of tracked packets: tracking %d packets, maximum %d", numTrackedPackets, protocol.MaxTrackedSentPackets)
+ }
+ return SendNone
+ }
+ if h.numProbesToSend > 0 {
+ return h.ptoMode
+ }
+ // Only send ACKs if we're congestion limited.
+ if !h.congestion.CanSend(h.bytesInFlight) {
+ if h.logger.Debug() {
+ h.logger.Debugf("Congestion limited: bytes in flight %d, window %d", h.bytesInFlight, h.congestion.GetCongestionWindow())
+ }
+ return SendAck
+ }
+ if numTrackedPackets >= protocol.MaxOutstandingSentPackets {
+ if h.logger.Debug() {
+ h.logger.Debugf("Max outstanding limited: tracking %d packets, maximum: %d", numTrackedPackets, protocol.MaxOutstandingSentPackets)
+ }
+ return SendAck
+ }
+ if !h.congestion.HasPacingBudget(now) {
+ return SendPacingLimited
+ }
+ return SendAny
+}
+
+func (h *sentPacketHandler) TimeUntilSend() monotime.Time {
+ return h.congestion.TimeUntilSend(h.bytesInFlight)
+}
+
+func (h *sentPacketHandler) SetMaxDatagramSize(s protocol.ByteCount) {
+ h.congestion.SetMaxDatagramSize(s)
+}
+
+func (h *sentPacketHandler) isAmplificationLimited() bool {
+ if h.peerAddressValidated {
+ return false
+ }
+ return h.bytesSent >= amplificationFactor*h.bytesReceived
+}
+
+func (h *sentPacketHandler) QueueProbePacket(encLevel protocol.EncryptionLevel) bool {
+ pnSpace := h.getPacketNumberSpace(encLevel)
+ pn, p := pnSpace.history.FirstOutstanding()
+ if p == nil {
+ return false
+ }
+ // TODO: don't declare the packet lost here.
+ // Keep track of acknowledged frames instead.
+ // Call DeclareLost before queueFramesForRetransmission, which clears the packet's frames.
+ pnSpace.history.DeclareLost(pn)
+ h.removeFromBytesInFlight(p)
+ h.queueFramesForRetransmission(p)
+ return true
+}
+
+func (h *sentPacketHandler) queueFramesForRetransmission(p *packet) {
+ if len(p.Frames) == 0 && len(p.StreamFrames) == 0 {
+ panic("no frames")
+ }
+ for _, f := range p.Frames {
+ if f.Handler != nil {
+ f.Handler.OnLost(f.Frame)
+ }
+ }
+ for _, f := range p.StreamFrames {
+ if f.Handler != nil {
+ f.Handler.OnLost(f.Frame)
+ }
+ }
+ p.StreamFrames = nil
+ p.Frames = nil
+}
+
+func (h *sentPacketHandler) ResetForRetry(now monotime.Time) {
+ h.bytesInFlight = 0
+ var firstPacketSendTime monotime.Time
+ for _, p := range h.initialPackets.history.Packets() {
+ if firstPacketSendTime.IsZero() {
+ firstPacketSendTime = p.SendTime
+ }
+ if p.IsAckEliciting() {
+ h.queueFramesForRetransmission(p)
+ }
+ }
+ // All application data packets sent at this point are 0-RTT packets.
+ // In the case of a Retry, we can assume that the server dropped all of them.
+ for _, p := range h.appDataPackets.history.Packets() {
+ if p.IsAckEliciting() {
+ h.queueFramesForRetransmission(p)
+ }
+ }
+
+ // Only use the Retry to estimate the RTT if we didn't send any retransmission for the Initial.
+ // Otherwise, we don't know which Initial the Retry was sent in response to.
+ if h.ptoCount == 0 {
+ // Don't set the RTT to a value lower than 5ms here.
+ h.rttStats.UpdateRTT(max(minRTTAfterRetry, now.Sub(firstPacketSendTime)), 0)
+ if h.logger.Debug() {
+ h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
+ }
+ if h.qlogger != nil {
+ h.qlogMetricsUpdated()
+ }
+ }
+ h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Peek(), false)
+ h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Peek(), true)
+ oldAlarm := h.alarm
+ h.alarm = alarmTimer{}
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
+ if !oldAlarm.Time.IsZero() {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeCancelled,
+ })
+ }
+ }
+ h.ptoCount = 0
+}
+
+func (h *sentPacketHandler) MigratedPath(now monotime.Time, initialMaxDatagramSize protocol.ByteCount) {
+ h.rttStats.ResetForPathMigration()
+ for pn, p := range h.appDataPackets.history.Packets() {
+ h.appDataPackets.history.DeclareLost(pn)
+ if !p.isPathProbePacket {
+ h.removeFromBytesInFlight(p)
+ if p.IsAckEliciting() {
+ h.queueFramesForRetransmission(p)
+ }
+ }
+ }
+ for pn := range h.appDataPackets.history.PathProbes() {
+ h.appDataPackets.history.RemovePathProbe(pn)
+ }
+ h.congestion = congestion.NewCubicSender(
+ congestion.DefaultClock{},
+ h.rttStats,
+ h.connStats,
+ initialMaxDatagramSize,
+ true, // use Reno
+ h.qlogger,
+ )
+ h.setLossDetectionTimer(now)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
new file mode 100644
index 00000000..1500e1cd
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
@@ -0,0 +1,274 @@
+package ackhandler
+
+import (
+ "fmt"
+ "iter"
+ "slices"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+const maxSkippedPackets = 4
+
+type sentPacketHistory struct {
+ packets []*packet
+ pathProbePackets []packetWithPacketNumber
+ skippedPackets []protocol.PacketNumber
+
+ numOutstanding int
+
+ firstPacketNumber protocol.PacketNumber
+ highestPacketNumber protocol.PacketNumber
+}
+
+func newSentPacketHistory(isAppData bool) *sentPacketHistory {
+ h := &sentPacketHistory{
+ highestPacketNumber: protocol.InvalidPacketNumber,
+ firstPacketNumber: protocol.InvalidPacketNumber,
+ }
+ if isAppData {
+ h.packets = make([]*packet, 0, 32)
+ h.skippedPackets = make([]protocol.PacketNumber, 0, maxSkippedPackets)
+ } else {
+ h.packets = make([]*packet, 0, 6)
+ }
+ return h
+}
+
+func (h *sentPacketHistory) checkSequentialPacketNumberUse(pn protocol.PacketNumber) {
+ if h.highestPacketNumber != protocol.InvalidPacketNumber {
+ if pn != h.highestPacketNumber+1 {
+ panic("non-sequential packet number use")
+ }
+ }
+ h.highestPacketNumber = pn
+ if len(h.packets) == 0 {
+ h.firstPacketNumber = pn
+ }
+}
+
+func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
+ h.checkSequentialPacketNumberUse(pn)
+ if len(h.packets) > 0 {
+ h.packets = append(h.packets, nil)
+ }
+ if len(h.skippedPackets) == maxSkippedPackets {
+ h.skippedPackets = slices.Delete(h.skippedPackets, 0, 1)
+ }
+ h.skippedPackets = append(h.skippedPackets, pn)
+}
+
+func (h *sentPacketHistory) SentPacket(pn protocol.PacketNumber, p *packet) {
+ h.checkSequentialPacketNumberUse(pn)
+ h.packets = append(h.packets, p)
+ if p.Outstanding() {
+ h.numOutstanding++
+ }
+}
+
+func (h *sentPacketHistory) SentPathProbePacket(pn protocol.PacketNumber, p *packet) {
+ h.checkSequentialPacketNumberUse(pn)
+ h.packets = append(h.packets, &packet{isPathProbePacket: true})
+ h.pathProbePackets = append(h.pathProbePackets, packetWithPacketNumber{PacketNumber: pn, packet: p})
+}
+
+func (h *sentPacketHistory) Packets() iter.Seq2[protocol.PacketNumber, *packet] {
+ return func(yield func(protocol.PacketNumber, *packet) bool) {
+ // h.firstPacketNumber might be updated in the yield function,
+ // so we need to save it here.
+ firstPacketNumber := h.firstPacketNumber
+ for i, p := range h.packets {
+ if p == nil {
+ continue
+ }
+ if !yield(firstPacketNumber+protocol.PacketNumber(i), p) {
+ return
+ }
+ }
+ }
+}
+
+func (h *sentPacketHistory) PathProbes() iter.Seq2[protocol.PacketNumber, *packet] {
+ return func(yield func(protocol.PacketNumber, *packet) bool) {
+ for _, p := range h.pathProbePackets {
+ if !yield(p.PacketNumber, p.packet) {
+ return
+ }
+ }
+ }
+}
+
+// FirstOutstanding returns the first outstanding packet.
+func (h *sentPacketHistory) FirstOutstanding() (protocol.PacketNumber, *packet) {
+ if !h.HasOutstandingPackets() {
+ return protocol.InvalidPacketNumber, nil
+ }
+ for i, p := range h.packets {
+ if p != nil && p.Outstanding() {
+ return h.firstPacketNumber + protocol.PacketNumber(i), p
+ }
+ }
+ return protocol.InvalidPacketNumber, nil
+}
+
+// FirstOutstandingPathProbe returns the first outstanding path probe packet
+func (h *sentPacketHistory) FirstOutstandingPathProbe() (protocol.PacketNumber, *packet) {
+ if len(h.pathProbePackets) == 0 {
+ return protocol.InvalidPacketNumber, nil
+ }
+ return h.pathProbePackets[0].PacketNumber, h.pathProbePackets[0].packet
+}
+
+func (h *sentPacketHistory) SkippedPackets() iter.Seq[protocol.PacketNumber] {
+ return func(yield func(protocol.PacketNumber) bool) {
+ for _, p := range h.skippedPackets {
+ if !yield(p) {
+ return
+ }
+ }
+ }
+}
+
+func (h *sentPacketHistory) Len() int {
+ return len(h.packets)
+}
+
+func (h *sentPacketHistory) NumOutstanding() int {
+ return h.numOutstanding
+}
+
+// Remove removes a packet from the sent packet history.
+// It must not be used for skipped packet numbers.
+func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error {
+ idx, ok := h.getIndex(pn)
+ if !ok {
+ return fmt.Errorf("packet %d not found in sent packet history", pn)
+ }
+ p := h.packets[idx]
+ if p.Outstanding() {
+ h.numOutstanding--
+ if h.numOutstanding < 0 {
+ panic("negative number of outstanding packets")
+ }
+ }
+ h.packets[idx] = nil
+ // clean up all skipped packets directly before this packet number
+ var hasPacketBefore bool
+ for idx > 0 {
+ idx--
+ if h.packets[idx] != nil {
+ hasPacketBefore = true
+ break
+ }
+ }
+ if !hasPacketBefore {
+ h.cleanupStart()
+ }
+ if len(h.packets) > 0 && h.packets[0] == nil {
+ panic("cleanup failed")
+ }
+ return nil
+}
+
+// RemovePathProbe removes a path probe packet.
+// It scales O(N), but that's ok, since we don't expect to send many path probe packets.
+// It is not valid to call this function in IteratePathProbes.
+func (h *sentPacketHistory) RemovePathProbe(pn protocol.PacketNumber) *packet {
+ var packetToDelete *packet
+ idx := -1
+ for i, p := range h.pathProbePackets {
+ if p.PacketNumber == pn {
+ packetToDelete = p.packet
+ idx = i
+ break
+ }
+ }
+ if idx != -1 {
+ // don't use slices.Delete, because it zeros the deleted element
+ copy(h.pathProbePackets[idx:], h.pathProbePackets[idx+1:])
+ h.pathProbePackets = h.pathProbePackets[:len(h.pathProbePackets)-1]
+ }
+ return packetToDelete
+}
+
+// getIndex gets the index of packet p in the packets slice.
+func (h *sentPacketHistory) getIndex(p protocol.PacketNumber) (int, bool) {
+ if len(h.packets) == 0 {
+ return 0, false
+ }
+ if p < h.firstPacketNumber {
+ return 0, false
+ }
+ index := int(p - h.firstPacketNumber)
+ if index > len(h.packets)-1 {
+ return 0, false
+ }
+ return index, true
+}
+
+func (h *sentPacketHistory) HasOutstandingPackets() bool {
+ return h.numOutstanding > 0
+}
+
+func (h *sentPacketHistory) HasOutstandingPathProbes() bool {
+ return len(h.pathProbePackets) > 0
+}
+
+// delete all nil entries at the beginning of the packets slice
+func (h *sentPacketHistory) cleanupStart() {
+ for i, p := range h.packets {
+ if p != nil {
+ h.packets = h.packets[i:]
+ h.firstPacketNumber += protocol.PacketNumber(i)
+ return
+ }
+ }
+ h.packets = h.packets[:0]
+ h.firstPacketNumber = protocol.InvalidPacketNumber
+}
+
+func (h *sentPacketHistory) LowestPacketNumber() protocol.PacketNumber {
+ if len(h.packets) == 0 {
+ return protocol.InvalidPacketNumber
+ }
+ return h.firstPacketNumber
+}
+
+func (h *sentPacketHistory) DeclareLost(pn protocol.PacketNumber) {
+ idx, ok := h.getIndex(pn)
+ if !ok {
+ return
+ }
+ p := h.packets[idx]
+ if p.Outstanding() {
+ h.numOutstanding--
+ if h.numOutstanding < 0 {
+ panic("negative number of outstanding packets")
+ }
+ }
+ h.packets[idx] = nil
+ if idx == 0 {
+ h.cleanupStart()
+ }
+}
+
+// Difference returns the difference between two packet numbers a and b (a - b),
+// taking into account any skipped packet numbers between them.
+//
+// Note that old skipped packets are garbage collected at some point,
+// so this function is not guaranteed to return the correct result after a while.
+func (h *sentPacketHistory) Difference(a, b protocol.PacketNumber) protocol.PacketNumber {
+ diff := a - b
+ if len(h.skippedPackets) == 0 {
+ return diff
+ }
+ if a < h.skippedPackets[0] || b > h.skippedPackets[len(h.skippedPackets)-1] {
+ return diff
+ }
+ for _, p := range h.skippedPackets {
+ if p > b && p < a {
+ diff--
+ }
+ }
+ return diff
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go b/vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go
new file mode 100644
index 00000000..3ad827d2
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go
@@ -0,0 +1,22 @@
+package congestion
+
+import (
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// Bandwidth of a connection
+type Bandwidth uint64
+
+const (
+ // BitsPerSecond is 1 bit per second
+ BitsPerSecond Bandwidth = 1
+ // BytesPerSecond is 1 byte per second
+ BytesPerSecond = 8 * BitsPerSecond
+)
+
+// BandwidthFromDelta calculates the bandwidth from a number of bytes and a time delta
+func BandwidthFromDelta(bytes protocol.ByteCount, delta time.Duration) Bandwidth {
+ return Bandwidth(bytes) * Bandwidth(time.Second) / Bandwidth(delta) * BytesPerSecond
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/clock.go b/vendor/github.com/quic-go/quic-go/internal/congestion/clock.go
new file mode 100644
index 00000000..8315026f
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/clock.go
@@ -0,0 +1,20 @@
+package congestion
+
+import (
+ "github.com/quic-go/quic-go/internal/monotime"
+)
+
+// A Clock returns the current time
+type Clock interface {
+ Now() monotime.Time
+}
+
+// DefaultClock implements the Clock interface using the Go stdlib clock.
+type DefaultClock struct{}
+
+var _ Clock = DefaultClock{}
+
+// Now gets the current time
+func (DefaultClock) Now() monotime.Time {
+ return monotime.Now()
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/cubic.go b/vendor/github.com/quic-go/quic-go/internal/congestion/cubic.go
new file mode 100644
index 00000000..40655de6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/cubic.go
@@ -0,0 +1,214 @@
+package congestion
+
+import (
+ "math"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// This cubic implementation is based on the one found in Chromiums's QUIC
+// implementation, in the files net/quic/congestion_control/cubic.{hh,cc}.
+
+// Constants based on TCP defaults.
+// The following constants are in 2^10 fractions of a second instead of ms to
+// allow a 10 shift right to divide.
+
+// 1024*1024^3 (first 1024 is from 0.100^3)
+// where 0.100 is 100 ms which is the scaling round trip time.
+const (
+ cubeScale = 40
+ cubeCongestionWindowScale = 410
+ cubeFactor = 1 << cubeScale / cubeCongestionWindowScale / maxDatagramSize
+ // TODO: when re-enabling cubic, make sure to use the actual packet size here
+ maxDatagramSize = protocol.ByteCount(protocol.InitialPacketSize)
+)
+
+const defaultNumConnections = 1
+
+// Default Cubic backoff factor
+const beta float32 = 0.7
+
+// Additional backoff factor when loss occurs in the concave part of the Cubic
+// curve. This additional backoff factor is expected to give up bandwidth to
+// new concurrent flows and speed up convergence.
+const betaLastMax float32 = 0.85
+
+// Cubic implements the cubic algorithm from TCP
+type Cubic struct {
+ clock Clock
+
+ // Number of connections to simulate.
+ numConnections int
+
+ // Time when this cycle started, after last loss event.
+ epoch monotime.Time
+
+ // Max congestion window used just before last loss event.
+ // Note: to improve fairness to other streams an additional back off is
+ // applied to this value if the new value is below our latest value.
+ lastMaxCongestionWindow protocol.ByteCount
+
+ // Number of acked bytes since the cycle started (epoch).
+ ackedBytesCount protocol.ByteCount
+
+ // TCP Reno equivalent congestion window in packets.
+ estimatedTCPcongestionWindow protocol.ByteCount
+
+ // Origin point of cubic function.
+ originPointCongestionWindow protocol.ByteCount
+
+ // Time to origin point of cubic function in 2^10 fractions of a second.
+ timeToOriginPoint uint32
+
+ // Last congestion window in packets computed by cubic function.
+ lastTargetCongestionWindow protocol.ByteCount
+}
+
+// NewCubic returns a new Cubic instance
+func NewCubic(clock Clock) *Cubic {
+ c := &Cubic{
+ clock: clock,
+ numConnections: defaultNumConnections,
+ }
+ c.Reset()
+ return c
+}
+
+// Reset is called after a timeout to reset the cubic state
+func (c *Cubic) Reset() {
+ c.epoch = 0
+ c.lastMaxCongestionWindow = 0
+ c.ackedBytesCount = 0
+ c.estimatedTCPcongestionWindow = 0
+ c.originPointCongestionWindow = 0
+ c.timeToOriginPoint = 0
+ c.lastTargetCongestionWindow = 0
+}
+
+func (c *Cubic) alpha() float32 {
+ // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that
+ // beta here is a cwnd multiplier, and is equal to 1-beta from the paper.
+ // We derive the equivalent alpha for an N-connection emulation as:
+ b := c.beta()
+ return 3 * float32(c.numConnections) * float32(c.numConnections) * (1 - b) / (1 + b)
+}
+
+func (c *Cubic) beta() float32 {
+ // kNConnectionBeta is the backoff factor after loss for our N-connection
+ // emulation, which emulates the effective backoff of an ensemble of N
+ // TCP-Reno connections on a single loss event. The effective multiplier is
+ // computed as:
+ return (float32(c.numConnections) - 1 + beta) / float32(c.numConnections)
+}
+
+func (c *Cubic) betaLastMax() float32 {
+ // betaLastMax is the additional backoff factor after loss for our
+ // N-connection emulation, which emulates the additional backoff of
+ // an ensemble of N TCP-Reno connections on a single loss event. The
+ // effective multiplier is computed as:
+ return (float32(c.numConnections) - 1 + betaLastMax) / float32(c.numConnections)
+}
+
+// OnApplicationLimited is called on ack arrival when sender is unable to use
+// the available congestion window. Resets Cubic state during quiescence.
+func (c *Cubic) OnApplicationLimited() {
+ // When sender is not using the available congestion window, the window does
+ // not grow. But to be RTT-independent, Cubic assumes that the sender has been
+ // using the entire window during the time since the beginning of the current
+ // "epoch" (the end of the last loss recovery period). Since
+ // application-limited periods break this assumption, we reset the epoch when
+ // in such a period. This reset effectively freezes congestion window growth
+ // through application-limited periods and allows Cubic growth to continue
+ // when the entire window is being used.
+ c.epoch = 0
+}
+
+// CongestionWindowAfterPacketLoss computes a new congestion window to use after
+// a loss event. Returns the new congestion window in packets. The new
+// congestion window is a multiplicative decrease of our current window.
+func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow protocol.ByteCount) protocol.ByteCount {
+ if currentCongestionWindow+maxDatagramSize < c.lastMaxCongestionWindow {
+ // We never reached the old max, so assume we are competing with another
+ // flow. Use our extra back off factor to allow the other flow to go up.
+ c.lastMaxCongestionWindow = protocol.ByteCount(c.betaLastMax() * float32(currentCongestionWindow))
+ } else {
+ c.lastMaxCongestionWindow = currentCongestionWindow
+ }
+ c.epoch = 0 // Reset time.
+ return protocol.ByteCount(float32(currentCongestionWindow) * c.beta())
+}
+
+// CongestionWindowAfterAck computes a new congestion window to use after a received ACK.
+// Returns the new congestion window in packets. The new congestion window
+// follows a cubic function that depends on the time passed since last
+// packet loss.
+func (c *Cubic) CongestionWindowAfterAck(
+ ackedBytes protocol.ByteCount,
+ currentCongestionWindow protocol.ByteCount,
+ delayMin time.Duration,
+ eventTime monotime.Time,
+) protocol.ByteCount {
+ c.ackedBytesCount += ackedBytes
+
+ if c.epoch.IsZero() {
+ // First ACK after a loss event.
+ c.epoch = eventTime // Start of epoch.
+ c.ackedBytesCount = ackedBytes // Reset count.
+ // Reset estimated_tcp_congestion_window_ to be in sync with cubic.
+ c.estimatedTCPcongestionWindow = currentCongestionWindow
+ if c.lastMaxCongestionWindow <= currentCongestionWindow {
+ c.timeToOriginPoint = 0
+ c.originPointCongestionWindow = currentCongestionWindow
+ } else {
+ c.timeToOriginPoint = uint32(math.Cbrt(float64(cubeFactor * (c.lastMaxCongestionWindow - currentCongestionWindow))))
+ c.originPointCongestionWindow = c.lastMaxCongestionWindow
+ }
+ }
+
+ // Change the time unit from microseconds to 2^10 fractions per second. Take
+ // the round trip time in account. This is done to allow us to use shift as a
+ // divide operator.
+ elapsedTime := int64(eventTime.Add(delayMin).Sub(c.epoch)/time.Microsecond) << 10 / (1000 * 1000)
+
+ // Right-shifts of negative, signed numbers have implementation-dependent
+ // behavior, so force the offset to be positive, as is done in the kernel.
+ offset := int64(c.timeToOriginPoint) - elapsedTime
+ if offset < 0 {
+ offset = -offset
+ }
+
+ deltaCongestionWindow := protocol.ByteCount(cubeCongestionWindowScale*offset*offset*offset) * maxDatagramSize >> cubeScale
+ var targetCongestionWindow protocol.ByteCount
+ if elapsedTime > int64(c.timeToOriginPoint) {
+ targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow
+ } else {
+ targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow
+ }
+ // Limit the CWND increase to half the acked bytes.
+ targetCongestionWindow = min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2)
+
+ // Increase the window by approximately Alpha * 1 MSS of bytes every
+ // time we ack an estimated tcp window of bytes. For small
+ // congestion windows (less than 25), the formula below will
+ // increase slightly slower than linearly per estimated tcp window
+ // of bytes.
+ c.estimatedTCPcongestionWindow += protocol.ByteCount(float32(c.ackedBytesCount) * c.alpha() * float32(maxDatagramSize) / float32(c.estimatedTCPcongestionWindow))
+ c.ackedBytesCount = 0
+
+ // We have a new cubic congestion window.
+ c.lastTargetCongestionWindow = targetCongestionWindow
+
+ // Compute target congestion_window based on cubic target and estimated TCP
+ // congestion_window, use highest (fastest).
+ if targetCongestionWindow < c.estimatedTCPcongestionWindow {
+ targetCongestionWindow = c.estimatedTCPcongestionWindow
+ }
+ return targetCongestionWindow
+}
+
+// SetNumConnections sets the number of emulated connections
+func (c *Cubic) SetNumConnections(n int) {
+ c.numConnections = n
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go b/vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
new file mode 100644
index 00000000..e5457ddb
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
@@ -0,0 +1,330 @@
+package congestion
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+const (
+ // maxDatagramSize is the default maximum packet size used in the Linux TCP implementation.
+ // Used in QUIC for congestion window computations in bytes.
+ initialMaxDatagramSize = protocol.ByteCount(protocol.InitialPacketSize)
+ maxBurstPackets = 3
+ renoBeta = 0.7 // Reno backoff factor.
+ minCongestionWindowPackets = 2
+ initialCongestionWindow = 32
+)
+
+type cubicSender struct {
+ hybridSlowStart HybridSlowStart
+ rttStats *utils.RTTStats
+ connStats *utils.ConnectionStats
+ cubic *Cubic
+ pacer *pacer
+ clock Clock
+
+ reno bool
+
+ // Track the largest packet that has been sent.
+ largestSentPacketNumber protocol.PacketNumber
+
+ // Track the largest packet that has been acked.
+ largestAckedPacketNumber protocol.PacketNumber
+
+ // Track the largest packet number outstanding when a CWND cutback occurs.
+ largestSentAtLastCutback protocol.PacketNumber
+
+ // Whether the last loss event caused us to exit slowstart.
+ // Used for stats collection of slowstartPacketsLost
+ lastCutbackExitedSlowstart bool
+
+ // Congestion window in bytes.
+ congestionWindow protocol.ByteCount
+
+ // Slow start congestion window in bytes, aka ssthresh.
+ slowStartThreshold protocol.ByteCount
+
+ // ACK counter for the Reno implementation.
+ numAckedPackets uint64
+
+ initialCongestionWindow protocol.ByteCount
+ initialMaxCongestionWindow protocol.ByteCount
+
+ maxDatagramSize protocol.ByteCount
+
+ lastState qlog.CongestionState
+ qlogger qlogwriter.Recorder
+}
+
+var (
+ _ SendAlgorithm = &cubicSender{}
+ _ SendAlgorithmWithDebugInfos = &cubicSender{}
+)
+
+// NewCubicSender makes a new cubic sender
+func NewCubicSender(
+ clock Clock,
+ rttStats *utils.RTTStats,
+ connStats *utils.ConnectionStats,
+ initialMaxDatagramSize protocol.ByteCount,
+ reno bool,
+ qlogger qlogwriter.Recorder,
+) *cubicSender {
+ return newCubicSender(
+ clock,
+ rttStats,
+ connStats,
+ reno,
+ initialMaxDatagramSize,
+ initialCongestionWindow*initialMaxDatagramSize,
+ protocol.MaxCongestionWindowPackets*initialMaxDatagramSize,
+ qlogger,
+ )
+}
+
+func newCubicSender(
+ clock Clock,
+ rttStats *utils.RTTStats,
+ connStats *utils.ConnectionStats,
+ reno bool,
+ initialMaxDatagramSize,
+ initialCongestionWindow,
+ initialMaxCongestionWindow protocol.ByteCount,
+ qlogger qlogwriter.Recorder,
+) *cubicSender {
+ c := &cubicSender{
+ rttStats: rttStats,
+ connStats: connStats,
+ largestSentPacketNumber: protocol.InvalidPacketNumber,
+ largestAckedPacketNumber: protocol.InvalidPacketNumber,
+ largestSentAtLastCutback: protocol.InvalidPacketNumber,
+ initialCongestionWindow: initialCongestionWindow,
+ initialMaxCongestionWindow: initialMaxCongestionWindow,
+ congestionWindow: initialCongestionWindow,
+ slowStartThreshold: protocol.MaxByteCount,
+ cubic: NewCubic(clock),
+ clock: clock,
+ reno: reno,
+ qlogger: qlogger,
+ maxDatagramSize: initialMaxDatagramSize,
+ }
+ c.pacer = newPacer(c.BandwidthEstimate)
+ if c.qlogger != nil {
+ c.lastState = qlog.CongestionStateSlowStart
+ c.qlogger.RecordEvent(qlog.CongestionStateUpdated{
+ State: qlog.CongestionStateSlowStart,
+ })
+ }
+ return c
+}
+
+// TimeUntilSend returns when the next packet should be sent.
+func (c *cubicSender) TimeUntilSend(_ protocol.ByteCount) monotime.Time {
+ return c.pacer.TimeUntilSend()
+}
+
+func (c *cubicSender) HasPacingBudget(now monotime.Time) bool {
+ return c.pacer.Budget(now) >= c.maxDatagramSize
+}
+
+func (c *cubicSender) maxCongestionWindow() protocol.ByteCount {
+ return c.maxDatagramSize * protocol.MaxCongestionWindowPackets
+}
+
+func (c *cubicSender) minCongestionWindow() protocol.ByteCount {
+ return c.maxDatagramSize * minCongestionWindowPackets
+}
+
+func (c *cubicSender) OnPacketSent(
+ sentTime monotime.Time,
+ _ protocol.ByteCount,
+ packetNumber protocol.PacketNumber,
+ bytes protocol.ByteCount,
+ isRetransmittable bool,
+) {
+ c.pacer.SentPacket(sentTime, bytes)
+ if !isRetransmittable {
+ return
+ }
+ c.largestSentPacketNumber = packetNumber
+ c.hybridSlowStart.OnPacketSent(packetNumber)
+}
+
+func (c *cubicSender) CanSend(bytesInFlight protocol.ByteCount) bool {
+ return bytesInFlight < c.GetCongestionWindow()
+}
+
+func (c *cubicSender) InRecovery() bool {
+ return c.largestAckedPacketNumber != protocol.InvalidPacketNumber && c.largestAckedPacketNumber <= c.largestSentAtLastCutback
+}
+
+func (c *cubicSender) InSlowStart() bool {
+ return c.GetCongestionWindow() < c.slowStartThreshold
+}
+
+func (c *cubicSender) GetCongestionWindow() protocol.ByteCount {
+ return c.congestionWindow
+}
+
+func (c *cubicSender) MaybeExitSlowStart() {
+ if c.InSlowStart() &&
+ c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) {
+ // exit slow start
+ c.slowStartThreshold = c.congestionWindow
+ c.maybeQlogStateChange(qlog.CongestionStateCongestionAvoidance)
+ }
+}
+
+func (c *cubicSender) OnPacketAcked(
+ ackedPacketNumber protocol.PacketNumber,
+ ackedBytes protocol.ByteCount,
+ priorInFlight protocol.ByteCount,
+ eventTime monotime.Time,
+) {
+ c.largestAckedPacketNumber = max(ackedPacketNumber, c.largestAckedPacketNumber)
+ if c.InRecovery() {
+ return
+ }
+ c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime)
+ if c.InSlowStart() {
+ c.hybridSlowStart.OnPacketAcked(ackedPacketNumber)
+ }
+}
+
+func (c *cubicSender) OnCongestionEvent(packetNumber protocol.PacketNumber, lostBytes, priorInFlight protocol.ByteCount) {
+ c.connStats.PacketsLost.Add(1)
+ c.connStats.BytesLost.Add(uint64(lostBytes))
+
+ // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
+ // already sent should be treated as a single loss event, since it's expected.
+ if packetNumber <= c.largestSentAtLastCutback {
+ return
+ }
+ c.lastCutbackExitedSlowstart = c.InSlowStart()
+ c.maybeQlogStateChange(qlog.CongestionStateRecovery)
+
+ if c.reno {
+ c.congestionWindow = protocol.ByteCount(float64(c.congestionWindow) * renoBeta)
+ } else {
+ c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow)
+ }
+ if minCwnd := c.minCongestionWindow(); c.congestionWindow < minCwnd {
+ c.congestionWindow = minCwnd
+ }
+ c.slowStartThreshold = c.congestionWindow
+ c.largestSentAtLastCutback = c.largestSentPacketNumber
+ // reset packet count from congestion avoidance mode. We start
+ // counting again when we're out of recovery.
+ c.numAckedPackets = 0
+}
+
+// Called when we receive an ack. Normal TCP tracks how many packets one ack
+// represents, but quic has a separate ack for each packet.
+func (c *cubicSender) maybeIncreaseCwnd(
+ _ protocol.PacketNumber,
+ ackedBytes protocol.ByteCount,
+ priorInFlight protocol.ByteCount,
+ eventTime monotime.Time,
+) {
+ // Do not increase the congestion window unless the sender is close to using
+ // the current window.
+ if !c.isCwndLimited(priorInFlight) {
+ c.cubic.OnApplicationLimited()
+ c.maybeQlogStateChange(qlog.CongestionStateApplicationLimited)
+ return
+ }
+ if c.congestionWindow >= c.maxCongestionWindow() {
+ return
+ }
+ if c.InSlowStart() {
+ // TCP slow start, exponential growth, increase by one for each ACK.
+ c.congestionWindow += c.maxDatagramSize
+ c.maybeQlogStateChange(qlog.CongestionStateSlowStart)
+ return
+ }
+ // Congestion avoidance
+ c.maybeQlogStateChange(qlog.CongestionStateCongestionAvoidance)
+ if c.reno {
+ // Classic Reno congestion avoidance.
+ c.numAckedPackets++
+ if c.numAckedPackets >= uint64(c.congestionWindow/c.maxDatagramSize) {
+ c.congestionWindow += c.maxDatagramSize
+ c.numAckedPackets = 0
+ }
+ } else {
+ c.congestionWindow = min(
+ c.maxCongestionWindow(),
+ c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime),
+ )
+ }
+}
+
+func (c *cubicSender) isCwndLimited(bytesInFlight protocol.ByteCount) bool {
+ congestionWindow := c.GetCongestionWindow()
+ if bytesInFlight >= congestionWindow {
+ return true
+ }
+ availableBytes := congestionWindow - bytesInFlight
+ slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2
+ return slowStartLimited || availableBytes <= maxBurstPackets*c.maxDatagramSize
+}
+
+// BandwidthEstimate returns the current bandwidth estimate
+func (c *cubicSender) BandwidthEstimate() Bandwidth {
+ srtt := c.rttStats.SmoothedRTT()
+ if srtt == 0 {
+ // This should never happen, but if it does, avoid division by zero.
+ srtt = protocol.TimerGranularity
+ }
+ return BandwidthFromDelta(c.GetCongestionWindow(), srtt)
+}
+
+// OnRetransmissionTimeout is called on an retransmission timeout
+func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
+ c.largestSentAtLastCutback = protocol.InvalidPacketNumber
+ if !packetsRetransmitted {
+ return
+ }
+ c.hybridSlowStart.Restart()
+ c.cubic.Reset()
+ c.slowStartThreshold = c.congestionWindow / 2
+ c.congestionWindow = c.minCongestionWindow()
+}
+
+// OnConnectionMigration is called when the connection is migrated (?)
+func (c *cubicSender) OnConnectionMigration() {
+ c.hybridSlowStart.Restart()
+ c.largestSentPacketNumber = protocol.InvalidPacketNumber
+ c.largestAckedPacketNumber = protocol.InvalidPacketNumber
+ c.largestSentAtLastCutback = protocol.InvalidPacketNumber
+ c.lastCutbackExitedSlowstart = false
+ c.cubic.Reset()
+ c.numAckedPackets = 0
+ c.congestionWindow = c.initialCongestionWindow
+ c.slowStartThreshold = c.initialMaxCongestionWindow
+}
+
+func (c *cubicSender) maybeQlogStateChange(new qlog.CongestionState) {
+ if c.qlogger == nil || new == c.lastState {
+ return
+ }
+ c.qlogger.RecordEvent(qlog.CongestionStateUpdated{State: new})
+ c.lastState = new
+}
+
+func (c *cubicSender) SetMaxDatagramSize(s protocol.ByteCount) {
+ if s < c.maxDatagramSize {
+ panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s))
+ }
+ cwndIsMinCwnd := c.congestionWindow == c.minCongestionWindow()
+ c.maxDatagramSize = s
+ if cwndIsMinCwnd {
+ c.congestionWindow = c.minCongestionWindow()
+ }
+ c.pacer.SetMaxDatagramSize(s)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/hybrid_slow_start.go b/vendor/github.com/quic-go/quic-go/internal/congestion/hybrid_slow_start.go
new file mode 100644
index 00000000..9679d9e4
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/hybrid_slow_start.go
@@ -0,0 +1,112 @@
+package congestion
+
+import (
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// Note(pwestin): the magic clamping numbers come from the original code in
+// tcp_cubic.c.
+const hybridStartLowWindow = protocol.ByteCount(16)
+
+// Number of delay samples for detecting the increase of delay.
+const hybridStartMinSamples = uint32(8)
+
+// Exit slow start if the min rtt has increased by more than 1/8th.
+const hybridStartDelayFactorExp = 3 // 2^3 = 8
+// The original paper specifies 2 and 8ms, but those have changed over time.
+const (
+ hybridStartDelayMinThresholdUs = int64(4000)
+ hybridStartDelayMaxThresholdUs = int64(16000)
+)
+
+// HybridSlowStart implements the TCP hybrid slow start algorithm
+type HybridSlowStart struct {
+ endPacketNumber protocol.PacketNumber
+ lastSentPacketNumber protocol.PacketNumber
+ started bool
+ currentMinRTT time.Duration
+ rttSampleCount uint32
+ hystartFound bool
+}
+
+// StartReceiveRound is called for the start of each receive round (burst) in the slow start phase.
+func (s *HybridSlowStart) StartReceiveRound(lastSent protocol.PacketNumber) {
+ s.endPacketNumber = lastSent
+ s.currentMinRTT = 0
+ s.rttSampleCount = 0
+ s.started = true
+}
+
+// IsEndOfRound returns true if this ack is the last packet number of our current slow start round.
+func (s *HybridSlowStart) IsEndOfRound(ack protocol.PacketNumber) bool {
+ return s.endPacketNumber < ack
+}
+
+// ShouldExitSlowStart should be called on every new ack frame, since a new
+// RTT measurement can be made then.
+// rtt: the RTT for this ack packet.
+// minRTT: is the lowest delay (RTT) we have seen during the session.
+// congestionWindow: the congestion window in packets.
+func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT time.Duration, congestionWindow protocol.ByteCount) bool {
+ if !s.started {
+ // Time to start the hybrid slow start.
+ s.StartReceiveRound(s.lastSentPacketNumber)
+ }
+ if s.hystartFound {
+ return true
+ }
+ // Second detection parameter - delay increase detection.
+ // Compare the minimum delay (s.currentMinRTT) of the current
+ // burst of packets relative to the minimum delay during the session.
+ // Note: we only look at the first few(8) packets in each burst, since we
+ // only want to compare the lowest RTT of the burst relative to previous
+ // bursts.
+ s.rttSampleCount++
+ if s.rttSampleCount <= hybridStartMinSamples {
+ if s.currentMinRTT == 0 || s.currentMinRTT > latestRTT {
+ s.currentMinRTT = latestRTT
+ }
+ }
+ // We only need to check this once per round.
+ if s.rttSampleCount == hybridStartMinSamples {
+ // Divide minRTT by 8 to get a rtt increase threshold for exiting.
+ minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp)
+ // Ensure the rtt threshold is never less than 2ms or more than 16ms.
+ minRTTincreaseThresholdUs = min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs)
+ minRTTincreaseThreshold := time.Duration(max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond
+
+ if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) {
+ s.hystartFound = true
+ }
+ }
+ // Exit from slow start if the cwnd is greater than 16 and
+ // increasing delay is found.
+ return congestionWindow >= hybridStartLowWindow && s.hystartFound
+}
+
+// OnPacketSent is called when a packet was sent
+func (s *HybridSlowStart) OnPacketSent(packetNumber protocol.PacketNumber) {
+ s.lastSentPacketNumber = packetNumber
+}
+
+// OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end
+// the round when the final packet of the burst is received and start it on
+// the next incoming ack.
+func (s *HybridSlowStart) OnPacketAcked(ackedPacketNumber protocol.PacketNumber) {
+ if s.IsEndOfRound(ackedPacketNumber) {
+ s.started = false
+ }
+}
+
+// Started returns true if started
+func (s *HybridSlowStart) Started() bool {
+ return s.started
+}
+
+// Restart the slow start phase
+func (s *HybridSlowStart) Restart() {
+ s.started = false
+ s.hystartFound = false
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/interface.go b/vendor/github.com/quic-go/quic-go/internal/congestion/interface.go
new file mode 100644
index 00000000..996907c6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/interface.go
@@ -0,0 +1,27 @@
+package congestion
+
+import (
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// A SendAlgorithm performs congestion control
+type SendAlgorithm interface {
+ TimeUntilSend(bytesInFlight protocol.ByteCount) monotime.Time
+ HasPacingBudget(now monotime.Time) bool
+ OnPacketSent(sentTime monotime.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool)
+ CanSend(bytesInFlight protocol.ByteCount) bool
+ MaybeExitSlowStart()
+ OnPacketAcked(number protocol.PacketNumber, ackedBytes protocol.ByteCount, priorInFlight protocol.ByteCount, eventTime monotime.Time)
+ OnCongestionEvent(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount)
+ OnRetransmissionTimeout(packetsRetransmitted bool)
+ SetMaxDatagramSize(protocol.ByteCount)
+}
+
+// A SendAlgorithmWithDebugInfos is a SendAlgorithm that exposes some debug infos
+type SendAlgorithmWithDebugInfos interface {
+ SendAlgorithm
+ InSlowStart() bool
+ InRecovery() bool
+ GetCongestionWindow() protocol.ByteCount
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go b/vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
new file mode 100644
index 00000000..7656f529
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
@@ -0,0 +1,110 @@
+package congestion
+
+import (
+ "math"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+const maxBurstSizePackets = 10
+
+// The pacer implements a token bucket pacing algorithm.
+type pacer struct {
+ budgetAtLastSent protocol.ByteCount
+ maxDatagramSize protocol.ByteCount
+ lastSentTime monotime.Time
+ adjustedBandwidth func() uint64 // in bytes/s
+}
+
+func newPacer(getBandwidth func() Bandwidth) *pacer {
+ p := &pacer{
+ maxDatagramSize: initialMaxDatagramSize,
+ adjustedBandwidth: func() uint64 {
+ // Bandwidth is in bits/s. We need the value in bytes/s.
+ bw := uint64(getBandwidth() / BytesPerSecond)
+ // Use a slightly higher value than the actual measured bandwidth.
+ // RTT variations then won't result in under-utilization of the congestion window.
+ // Ultimately, this will result in sending packets as acknowledgments are received rather than when timers fire,
+ // provided the congestion window is fully utilized and acknowledgments arrive at regular intervals.
+ return bw * 5 / 4
+ },
+ }
+ p.budgetAtLastSent = p.maxBurstSize()
+ return p
+}
+
+func (p *pacer) SentPacket(sendTime monotime.Time, size protocol.ByteCount) {
+ budget := p.Budget(sendTime)
+ if size >= budget {
+ p.budgetAtLastSent = 0
+ } else {
+ p.budgetAtLastSent = budget - size
+ }
+ p.lastSentTime = sendTime
+}
+
+func (p *pacer) Budget(now monotime.Time) protocol.ByteCount {
+ if p.lastSentTime.IsZero() {
+ return p.maxBurstSize()
+ }
+ delta := now.Sub(p.lastSentTime)
+ var added protocol.ByteCount
+ if delta > 0 {
+ added = p.timeScaledBandwidth(uint64(delta.Nanoseconds()))
+ }
+ budget := p.budgetAtLastSent + added
+ if added > 0 && budget < p.budgetAtLastSent {
+ budget = protocol.MaxByteCount
+ }
+ return min(p.maxBurstSize(), budget)
+}
+
+func (p *pacer) maxBurstSize() protocol.ByteCount {
+ return max(
+ p.timeScaledBandwidth(uint64((protocol.MinPacingDelay + protocol.TimerGranularity).Nanoseconds())),
+ maxBurstSizePackets*p.maxDatagramSize,
+ )
+}
+
+// timeScaledBandwidth calculates the number of bytes that may be sent within
+// a given time interval (ns nanoseconds), based on the current bandwidth estimate.
+// It caps the scaled value to the maximum allowed burst and handles overflows.
+func (p *pacer) timeScaledBandwidth(ns uint64) protocol.ByteCount {
+ bw := p.adjustedBandwidth()
+ if bw == 0 {
+ return 0
+ }
+ const nsPerSecond = 1e9
+ maxBurst := maxBurstSizePackets * p.maxDatagramSize
+ var scaled protocol.ByteCount
+ if ns > math.MaxUint64/bw {
+ scaled = maxBurst
+ } else {
+ scaled = protocol.ByteCount(bw * ns / nsPerSecond)
+ }
+ return scaled
+}
+
+// TimeUntilSend returns when the next packet should be sent.
+// It returns zero if a packet can be sent immediately.
+func (p *pacer) TimeUntilSend() monotime.Time {
+ if p.budgetAtLastSent >= p.maxDatagramSize {
+ return 0
+ }
+ diff := 1e9 * uint64(p.maxDatagramSize-p.budgetAtLastSent)
+ bw := p.adjustedBandwidth()
+ // We might need to round up this value.
+ // Otherwise, we might have a budget (slightly) smaller than the datagram size when the timer expires.
+ d := diff / bw
+ // this is effectively a math.Ceil, but using only integer math
+ if diff%bw > 0 {
+ d++
+ }
+ return p.lastSentTime.Add(max(protocol.MinPacingDelay, time.Duration(d)*time.Nanosecond))
+}
+
+func (p *pacer) SetMaxDatagramSize(s protocol.ByteCount) {
+ p.maxDatagramSize = s
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/base_flow_controller.go b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/base_flow_controller.go
new file mode 100644
index 00000000..04a9f98e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/base_flow_controller.go
@@ -0,0 +1,122 @@
+package flowcontrol
+
+import (
+ "sync"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+type baseFlowController struct {
+ // for sending data
+ bytesSent protocol.ByteCount
+ sendWindow protocol.ByteCount
+ lastBlockedAt protocol.ByteCount
+
+ // for receiving data
+ //nolint:structcheck // The mutex is used both by the stream and the connection flow controller
+ mutex sync.Mutex
+ bytesRead protocol.ByteCount
+ highestReceived protocol.ByteCount
+ receiveWindow protocol.ByteCount
+ receiveWindowSize protocol.ByteCount
+ maxReceiveWindowSize protocol.ByteCount
+
+ allowWindowIncrease func(size protocol.ByteCount) bool
+
+ epochStartTime monotime.Time
+ epochStartOffset protocol.ByteCount
+ rttStats *utils.RTTStats
+
+ logger utils.Logger
+}
+
+// IsNewlyBlocked says if it is newly blocked by flow control.
+// For every offset, it only returns true once.
+// If it is blocked, the offset is returned.
+func (c *baseFlowController) IsNewlyBlocked() (bool, protocol.ByteCount) {
+ if c.SendWindowSize() != 0 || c.sendWindow == c.lastBlockedAt {
+ return false, 0
+ }
+ c.lastBlockedAt = c.sendWindow
+ return true, c.sendWindow
+}
+
+func (c *baseFlowController) AddBytesSent(n protocol.ByteCount) {
+ c.bytesSent += n
+}
+
+// UpdateSendWindow is called after receiving a MAX_{STREAM_}DATA frame.
+func (c *baseFlowController) UpdateSendWindow(offset protocol.ByteCount) (updated bool) {
+ if offset > c.sendWindow {
+ c.sendWindow = offset
+ return true
+ }
+ return false
+}
+
+func (c *baseFlowController) SendWindowSize() protocol.ByteCount {
+ // this only happens during connection establishment, when data is sent before we receive the peer's transport parameters
+ if c.bytesSent > c.sendWindow {
+ return 0
+ }
+ return c.sendWindow - c.bytesSent
+}
+
+// needs to be called with locked mutex
+func (c *baseFlowController) addBytesRead(n protocol.ByteCount) {
+ c.bytesRead += n
+}
+
+func (c *baseFlowController) hasWindowUpdate() bool {
+ bytesRemaining := c.receiveWindow - c.bytesRead
+ // update the window when more than the threshold was consumed
+ return bytesRemaining <= protocol.ByteCount(float64(c.receiveWindowSize)*(1-protocol.WindowUpdateThreshold))
+}
+
+// getWindowUpdate updates the receive window, if necessary
+// it returns the new offset
+func (c *baseFlowController) getWindowUpdate(now monotime.Time) protocol.ByteCount {
+ if !c.hasWindowUpdate() {
+ return 0
+ }
+
+ c.maybeAdjustWindowSize(now)
+ c.receiveWindow = c.bytesRead + c.receiveWindowSize
+ return c.receiveWindow
+}
+
+// maybeAdjustWindowSize increases the receiveWindowSize if we're sending updates too often.
+// For details about auto-tuning, see https://docs.google.com/document/d/1SExkMmGiz8VYzV3s9E35JQlJ73vhzCekKkDi85F1qCE/edit?usp=sharing.
+func (c *baseFlowController) maybeAdjustWindowSize(now monotime.Time) {
+ bytesReadInEpoch := c.bytesRead - c.epochStartOffset
+ // don't do anything if less than half the window has been consumed
+ if bytesReadInEpoch <= c.receiveWindowSize/2 {
+ return
+ }
+ rtt := c.rttStats.SmoothedRTT()
+ if rtt == 0 {
+ return
+ }
+
+ fraction := float64(bytesReadInEpoch) / float64(c.receiveWindowSize)
+ if now.Sub(c.epochStartTime) < time.Duration(4*fraction*float64(rtt)) {
+ // window is consumed too fast, try to increase the window size
+ newSize := min(2*c.receiveWindowSize, c.maxReceiveWindowSize)
+ if newSize > c.receiveWindowSize && (c.allowWindowIncrease == nil || c.allowWindowIncrease(newSize-c.receiveWindowSize)) {
+ c.receiveWindowSize = newSize
+ }
+ }
+ c.startNewAutoTuningEpoch(now)
+}
+
+func (c *baseFlowController) startNewAutoTuningEpoch(now monotime.Time) {
+ c.epochStartTime = now
+ c.epochStartOffset = c.bytesRead
+}
+
+func (c *baseFlowController) checkFlowControlViolation() bool {
+ return c.highestReceived > c.receiveWindow
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go
new file mode 100644
index 00000000..0c74dcc9
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go
@@ -0,0 +1,113 @@
+package flowcontrol
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+type connectionFlowController struct {
+ baseFlowController
+}
+
+var _ ConnectionFlowController = &connectionFlowController{}
+
+// NewConnectionFlowController gets a new flow controller for the connection
+// It is created before we receive the peer's transport parameters, thus it starts with a sendWindow of 0.
+func NewConnectionFlowController(
+ receiveWindow protocol.ByteCount,
+ maxReceiveWindow protocol.ByteCount,
+ allowWindowIncrease func(size protocol.ByteCount) bool,
+ rttStats *utils.RTTStats,
+ logger utils.Logger,
+) *connectionFlowController {
+ return &connectionFlowController{
+ baseFlowController: baseFlowController{
+ rttStats: rttStats,
+ receiveWindow: receiveWindow,
+ receiveWindowSize: receiveWindow,
+ maxReceiveWindowSize: maxReceiveWindow,
+ allowWindowIncrease: allowWindowIncrease,
+ logger: logger,
+ },
+ }
+}
+
+// IncrementHighestReceived adds an increment to the highestReceived value
+func (c *connectionFlowController) IncrementHighestReceived(increment protocol.ByteCount, now monotime.Time) error {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ // If this is the first frame received on this connection, start flow-control auto-tuning.
+ if c.highestReceived == 0 {
+ c.startNewAutoTuningEpoch(now)
+ }
+ c.highestReceived += increment
+
+ if c.checkFlowControlViolation() {
+ return &qerr.TransportError{
+ ErrorCode: qerr.FlowControlError,
+ ErrorMessage: fmt.Sprintf("received %d bytes for the connection, allowed %d bytes", c.highestReceived, c.receiveWindow),
+ }
+ }
+ return nil
+}
+
+func (c *connectionFlowController) AddBytesRead(n protocol.ByteCount) (hasWindowUpdate bool) {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ c.addBytesRead(n)
+ return c.hasWindowUpdate()
+}
+
+func (c *connectionFlowController) GetWindowUpdate(now monotime.Time) protocol.ByteCount {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ oldWindowSize := c.receiveWindowSize
+ offset := c.getWindowUpdate(now)
+ if c.logger.Debug() && oldWindowSize < c.receiveWindowSize {
+ c.logger.Debugf("Increasing receive flow control window for the connection to %d kB", c.receiveWindowSize/(1<<10))
+ }
+ return offset
+}
+
+// EnsureMinimumWindowSize sets a minimum window size
+// it should make sure that the connection-level window is increased when a stream-level window grows
+func (c *connectionFlowController) EnsureMinimumWindowSize(inc protocol.ByteCount, now monotime.Time) {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ if inc <= c.receiveWindowSize {
+ return
+ }
+ newSize := min(inc, c.maxReceiveWindowSize)
+ if delta := newSize - c.receiveWindowSize; delta > 0 && c.allowWindowIncrease(delta) {
+ c.receiveWindowSize = newSize
+ if c.logger.Debug() {
+ c.logger.Debugf("Increasing receive flow control window for the connection to %d, in response to stream flow control window increase", newSize)
+ }
+ }
+ c.startNewAutoTuningEpoch(now)
+}
+
+// Reset rests the flow controller. This happens when 0-RTT is rejected.
+// All stream data is invalidated, it's as if we had never opened a stream and never sent any data.
+// At that point, we only have sent stream data, but we didn't have the keys to open 1-RTT keys yet.
+func (c *connectionFlowController) Reset() error {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ if c.bytesRead > 0 || c.highestReceived > 0 || !c.epochStartTime.IsZero() {
+ return errors.New("flow controller reset after reading data")
+ }
+ c.bytesSent = 0
+ c.lastBlockedAt = 0
+ c.sendWindow = 0
+ return nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/interface.go b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/interface.go
new file mode 100644
index 00000000..e95c65d9
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/interface.go
@@ -0,0 +1,46 @@
+package flowcontrol
+
+import (
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+type flowController interface {
+ // for sending
+ SendWindowSize() protocol.ByteCount
+ UpdateSendWindow(protocol.ByteCount) (updated bool)
+ AddBytesSent(protocol.ByteCount)
+ // for receiving
+ GetWindowUpdate(monotime.Time) protocol.ByteCount // returns 0 if no update is necessary
+}
+
+// A StreamFlowController is a flow controller for a QUIC stream.
+type StreamFlowController interface {
+ flowController
+ AddBytesRead(protocol.ByteCount) (hasStreamWindowUpdate, hasConnWindowUpdate bool)
+ // UpdateHighestReceived is called when a new highest offset is received
+ // final has to be to true if this is the final offset of the stream,
+ // as contained in a STREAM frame with FIN bit, and the RESET_STREAM frame
+ UpdateHighestReceived(offset protocol.ByteCount, final bool, now monotime.Time) error
+ // Abandon is called when reading from the stream is aborted early,
+ // and there won't be any further calls to AddBytesRead.
+ Abandon()
+ IsNewlyBlocked() bool
+}
+
+// The ConnectionFlowController is the flow controller for the connection.
+type ConnectionFlowController interface {
+ flowController
+ AddBytesRead(protocol.ByteCount) (hasWindowUpdate bool)
+ Reset() error
+ IsNewlyBlocked() (bool, protocol.ByteCount)
+}
+
+type connectionFlowControllerI interface {
+ ConnectionFlowController
+ // The following two methods are not supposed to be called from outside this packet, but are needed internally
+ // for sending
+ EnsureMinimumWindowSize(protocol.ByteCount, monotime.Time)
+ // for receiving
+ IncrementHighestReceived(protocol.ByteCount, monotime.Time) error
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go
new file mode 100644
index 00000000..ccbfe9cd
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go
@@ -0,0 +1,154 @@
+package flowcontrol
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+type streamFlowController struct {
+ baseFlowController
+
+ streamID protocol.StreamID
+
+ connection connectionFlowControllerI
+
+ receivedFinalOffset bool
+}
+
+var _ StreamFlowController = &streamFlowController{}
+
+// NewStreamFlowController gets a new flow controller for a stream
+func NewStreamFlowController(
+ streamID protocol.StreamID,
+ cfc ConnectionFlowController,
+ receiveWindow protocol.ByteCount,
+ maxReceiveWindow protocol.ByteCount,
+ initialSendWindow protocol.ByteCount,
+ rttStats *utils.RTTStats,
+ logger utils.Logger,
+) StreamFlowController {
+ return &streamFlowController{
+ streamID: streamID,
+ connection: cfc.(connectionFlowControllerI),
+ baseFlowController: baseFlowController{
+ rttStats: rttStats,
+ receiveWindow: receiveWindow,
+ receiveWindowSize: receiveWindow,
+ maxReceiveWindowSize: maxReceiveWindow,
+ sendWindow: initialSendWindow,
+ logger: logger,
+ },
+ }
+}
+
+// UpdateHighestReceived updates the highestReceived value, if the offset is higher.
+func (c *streamFlowController) UpdateHighestReceived(offset protocol.ByteCount, final bool, now monotime.Time) error {
+ // If the final offset for this stream is already known, check for consistency.
+ if c.receivedFinalOffset {
+ // If we receive another final offset, check that it's the same.
+ if final && offset != c.highestReceived {
+ return &qerr.TransportError{
+ ErrorCode: qerr.FinalSizeError,
+ ErrorMessage: fmt.Sprintf("received inconsistent final offset for stream %d (old: %d, new: %d bytes)", c.streamID, c.highestReceived, offset),
+ }
+ }
+ // Check that the offset is below the final offset.
+ if offset > c.highestReceived {
+ return &qerr.TransportError{
+ ErrorCode: qerr.FinalSizeError,
+ ErrorMessage: fmt.Sprintf("received offset %d for stream %d, but final offset was already received at %d", offset, c.streamID, c.highestReceived),
+ }
+ }
+ }
+
+ if final {
+ c.receivedFinalOffset = true
+ }
+ if offset == c.highestReceived {
+ return nil
+ }
+ // A higher offset was received before. This can happen due to reordering.
+ if offset < c.highestReceived {
+ if final {
+ return &qerr.TransportError{
+ ErrorCode: qerr.FinalSizeError,
+ ErrorMessage: fmt.Sprintf("received final offset %d for stream %d, but already received offset %d before", offset, c.streamID, c.highestReceived),
+ }
+ }
+ return nil
+ }
+
+ // If this is the first frame received for this stream, start flow-control auto-tuning.
+ if c.highestReceived == 0 {
+ c.startNewAutoTuningEpoch(now)
+ }
+ increment := offset - c.highestReceived
+ c.highestReceived = offset
+
+ if c.checkFlowControlViolation() {
+ return &qerr.TransportError{
+ ErrorCode: qerr.FlowControlError,
+ ErrorMessage: fmt.Sprintf("received %d bytes on stream %d, allowed %d bytes", offset, c.streamID, c.receiveWindow),
+ }
+ }
+ return c.connection.IncrementHighestReceived(increment, now)
+}
+
+func (c *streamFlowController) AddBytesRead(n protocol.ByteCount) (hasStreamWindowUpdate, hasConnWindowUpdate bool) {
+ c.mutex.Lock()
+ c.addBytesRead(n)
+ hasStreamWindowUpdate = c.shouldQueueWindowUpdate()
+ c.mutex.Unlock()
+ hasConnWindowUpdate = c.connection.AddBytesRead(n)
+ return
+}
+
+func (c *streamFlowController) Abandon() {
+ c.mutex.Lock()
+ unread := c.highestReceived - c.bytesRead
+ c.bytesRead = c.highestReceived
+ c.mutex.Unlock()
+ if unread > 0 {
+ c.connection.AddBytesRead(unread)
+ }
+}
+
+func (c *streamFlowController) AddBytesSent(n protocol.ByteCount) {
+ c.baseFlowController.AddBytesSent(n)
+ c.connection.AddBytesSent(n)
+}
+
+func (c *streamFlowController) SendWindowSize() protocol.ByteCount {
+ return min(c.baseFlowController.SendWindowSize(), c.connection.SendWindowSize())
+}
+
+func (c *streamFlowController) IsNewlyBlocked() bool {
+ blocked, _ := c.baseFlowController.IsNewlyBlocked()
+ return blocked
+}
+
+func (c *streamFlowController) shouldQueueWindowUpdate() bool {
+ return !c.receivedFinalOffset && c.hasWindowUpdate()
+}
+
+func (c *streamFlowController) GetWindowUpdate(now monotime.Time) protocol.ByteCount {
+ // If we already received the final offset for this stream, the peer won't need any additional flow control credit.
+ if c.receivedFinalOffset {
+ return 0
+ }
+
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ oldWindowSize := c.receiveWindowSize
+ offset := c.getWindowUpdate(now)
+ if c.receiveWindowSize > oldWindowSize { // auto-tuning enlarged the window size
+ c.logger.Debugf("Increasing receive flow control window for stream %d to %d", c.streamID, c.receiveWindowSize)
+ c.connection.EnsureMinimumWindowSize(protocol.ByteCount(float64(c.receiveWindowSize)*protocol.ConnectionFlowControlMultiplier), now)
+ }
+ return offset
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/aead.go b/vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
new file mode 100644
index 00000000..f12c932a
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
@@ -0,0 +1,91 @@
+package handshake
+
+import (
+ "crypto/cipher"
+ "encoding/binary"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+func createAEAD(suite cipherSuite, trafficSecret []byte, v protocol.Version) cipher.AEAD {
+ keyLabel := hkdfLabelKeyV1
+ ivLabel := hkdfLabelIVV1
+ if v == protocol.Version2 {
+ keyLabel = hkdfLabelKeyV2
+ ivLabel = hkdfLabelIVV2
+ }
+ key := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, keyLabel, suite.KeyLen)
+ iv := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, ivLabel, suite.IVLen())
+ return suite.AEAD(key, iv)
+}
+
+type longHeaderSealer struct {
+ aead cipher.AEAD
+ headerProtector headerProtector
+ nonceBuf [8]byte
+}
+
+var _ LongHeaderSealer = &longHeaderSealer{}
+
+func newLongHeaderSealer(aead cipher.AEAD, headerProtector headerProtector) LongHeaderSealer {
+ if aead.NonceSize() != 8 {
+ panic("unexpected nonce size")
+ }
+ return &longHeaderSealer{
+ aead: aead,
+ headerProtector: headerProtector,
+ }
+}
+
+func (s *longHeaderSealer) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte {
+ binary.BigEndian.PutUint64(s.nonceBuf[:], uint64(pn))
+ return s.aead.Seal(dst, s.nonceBuf[:], src, ad)
+}
+
+func (s *longHeaderSealer) EncryptHeader(sample []byte, firstByte *byte, pnBytes []byte) {
+ s.headerProtector.EncryptHeader(sample, firstByte, pnBytes)
+}
+
+func (s *longHeaderSealer) Overhead() int {
+ return s.aead.Overhead()
+}
+
+type longHeaderOpener struct {
+ aead cipher.AEAD
+ headerProtector headerProtector
+ highestRcvdPN protocol.PacketNumber // highest packet number received (which could be successfully unprotected)
+
+ // use a single array to avoid allocations
+ nonceBuf [8]byte
+}
+
+var _ LongHeaderOpener = &longHeaderOpener{}
+
+func newLongHeaderOpener(aead cipher.AEAD, headerProtector headerProtector) LongHeaderOpener {
+ if aead.NonceSize() != 8 {
+ panic("unexpected nonce size")
+ }
+ return &longHeaderOpener{
+ aead: aead,
+ headerProtector: headerProtector,
+ }
+}
+
+func (o *longHeaderOpener) DecodePacketNumber(wirePN protocol.PacketNumber, wirePNLen protocol.PacketNumberLen) protocol.PacketNumber {
+ return protocol.DecodePacketNumber(wirePNLen, o.highestRcvdPN, wirePN)
+}
+
+func (o *longHeaderOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []byte) ([]byte, error) {
+ binary.BigEndian.PutUint64(o.nonceBuf[:], uint64(pn))
+ dec, err := o.aead.Open(dst, o.nonceBuf[:], src, ad)
+ if err == nil {
+ o.highestRcvdPN = max(o.highestRcvdPN, pn)
+ } else {
+ err = ErrDecryptionFailed
+ }
+ return dec, err
+}
+
+func (o *longHeaderOpener) DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte) {
+ o.headerProtector.DecryptHeader(sample, firstByte, pnBytes)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go b/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
new file mode 100644
index 00000000..98112a81
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
@@ -0,0 +1,114 @@
+package handshake
+
+import (
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/fips140"
+ "crypto/tls"
+ "fmt"
+
+ "golang.org/x/crypto/chacha20poly1305"
+)
+
+// These cipher suite implementations are copied from the standard library crypto/tls package.
+
+const aeadNonceLength = 12
+
+type cipherSuite struct {
+ ID uint16
+ Hash crypto.Hash
+ KeyLen int
+ AEAD func(key, nonceMask []byte) cipher.AEAD
+}
+
+func (s cipherSuite) IVLen() int { return aeadNonceLength }
+
+func getCipherSuite(id uint16) cipherSuite {
+ switch id {
+ case tls.TLS_AES_128_GCM_SHA256:
+ return cipherSuite{ID: tls.TLS_AES_128_GCM_SHA256, Hash: crypto.SHA256, KeyLen: 16, AEAD: aeadAESGCMTLS13}
+ case tls.TLS_CHACHA20_POLY1305_SHA256:
+ // The usual convention is to only panic on fips140.Enforced (and not on fips140.Enabled),
+ // but this function panics in the default case anyway, so we might as well panic here.
+ if fips140.Enabled() {
+ panic("tls: TLS_CHACHA20_POLY1305_SHA256 is not allowed in FIPS 140-3 mode")
+ }
+ return cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
+ case tls.TLS_AES_256_GCM_SHA384:
+ return cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
+ default:
+ panic(fmt.Sprintf("unknown cypher suite: %d", id))
+ }
+}
+
+func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD {
+ if fips140.Enabled() {
+ return aeadAESGCMTLS13FIPS140(key, nonceMask)
+ }
+
+ if len(nonceMask) != aeadNonceLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aes, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+ aead, err := cipher.NewGCM(aes)
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], nonceMask)
+ return ret
+}
+
+func aeadChaCha20Poly1305(key, nonceMask []byte) cipher.AEAD {
+ if len(nonceMask) != aeadNonceLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aead, err := chacha20poly1305.New(key)
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], nonceMask)
+ return ret
+}
+
+// xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
+// before each call.
+type xorNonceAEAD struct {
+ nonceMask [aeadNonceLength]byte
+ aead cipher.AEAD
+}
+
+func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
+func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
+
+func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result
+}
+
+func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result, err
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite_fips140.go b/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite_fips140.go
new file mode 100644
index 00000000..2248cbad
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite_fips140.go
@@ -0,0 +1,48 @@
+package handshake
+
+import (
+ "crypto/cipher"
+ _ "unsafe" // for go:linkname
+)
+
+// Reaching into crypto/tls is a bit of a hack, but it's the only way to get the FIPS 140
+// compliant AEAD, because the standard library doesn't yet expose the NewGCMForQUIC constructor
+// added in https://go-review.googlesource.com/c/go/+/723760.
+// See https://github.com/golang/go/issues/79219 for details.
+//
+// Once the standard library exposes the necessary constructors, we can use a shared code path
+// for both FIPS 140 and non-FIPS 140 modes.
+//
+//go:linkname cryptoTLSAEAD_AESGCMTLS13 crypto/tls.aeadAESGCMTLS13
+func cryptoTLSAEAD_AESGCMTLS13(key, nonceMask []byte) cipher.AEAD
+
+func aeadAESGCMTLS13FIPS140(key, nonceMask []byte) cipher.AEAD {
+ return &tls13AESGCMAEADFIPS140{aead: cryptoTLSAEAD_AESGCMTLS13(key, nonceMask)}
+}
+
+type tls13AESGCMAEADFIPS140 struct {
+ aead cipher.AEAD
+ primedSeal bool
+}
+
+func (f *tls13AESGCMAEADFIPS140) NonceSize() int { return f.aead.NonceSize() }
+func (f *tls13AESGCMAEADFIPS140) Overhead() int { return f.aead.Overhead() }
+
+func (f *tls13AESGCMAEADFIPS140) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ if !f.primedSeal {
+ f.primedSeal = true
+ if nonce[0]|nonce[1]|nonce[2]|nonce[3]|nonce[4]|nonce[5]|nonce[6]|nonce[7] != 0 {
+ // Go's TLS 1.3 AES-GCM AEAD learns the XOR mask from the first Seal
+ // call and enforces monotonically increasing packet numbers after that.
+ // QUIC packet numbers don't reset on key updates, so prime it with
+ // packet number 0 before the first real, non-zero packet number.
+ var zeroNonce [8]byte
+ f.aead.Seal(nil, zeroNonce[:], nil, nil)
+ }
+ }
+ return f.aead.Seal(out, nonce, plaintext, additionalData)
+}
+
+func (f *tls13AESGCMAEADFIPS140) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ return f.aead.Open(out, nonce, ciphertext, additionalData)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go b/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
new file mode 100644
index 00000000..cc93dc1a
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
@@ -0,0 +1,722 @@
+package handshake
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "net"
+ "strings"
+ "sync/atomic"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+type quicVersionContextKey struct{}
+
+var QUICVersionContextKey = &quicVersionContextKey{}
+
+const clientSessionStateRevision = 5
+
+type cryptoSetup struct {
+ tlsConf *tls.Config
+ conn *tls.QUICConn
+
+ events []Event
+
+ version protocol.Version
+
+ ourParams *wire.TransportParameters
+ peerParams *wire.TransportParameters
+
+ zeroRTTParameters *wire.TransportParameters
+ allow0RTT bool
+
+ rttStats *utils.RTTStats
+
+ qlogger qlogwriter.Recorder
+ logger utils.Logger
+
+ perspective protocol.Perspective
+
+ handshakeCompleteTime time.Time
+
+ zeroRTTOpener LongHeaderOpener // only set for the server
+ zeroRTTSealer LongHeaderSealer // only set for the client
+
+ initialOpener LongHeaderOpener
+ initialSealer LongHeaderSealer
+
+ handshakeOpener LongHeaderOpener
+ handshakeSealer LongHeaderSealer
+
+ used0RTT atomic.Bool
+
+ aead *updatableAEAD
+ has1RTTSealer bool
+ has1RTTOpener bool
+}
+
+var _ CryptoSetup = &cryptoSetup{}
+
+// NewCryptoSetupClient creates a new crypto setup for the client
+func NewCryptoSetupClient(
+ connID protocol.ConnectionID,
+ tp *wire.TransportParameters,
+ tlsConf *tls.Config,
+ enable0RTT bool,
+ rttStats *utils.RTTStats,
+ qlogger qlogwriter.Recorder,
+ logger utils.Logger,
+ version protocol.Version,
+) CryptoSetup {
+ cs := newCryptoSetup(
+ connID,
+ tp,
+ rttStats,
+ qlogger,
+ logger,
+ protocol.PerspectiveClient,
+ version,
+ )
+
+ tlsConf = tlsConf.Clone()
+ tlsConf.MinVersion = tls.VersionTLS13
+ cs.tlsConf = tlsConf
+ cs.allow0RTT = enable0RTT
+
+ cs.conn = tls.QUICClient(&tls.QUICConfig{
+ TLSConfig: tlsConf,
+ EnableSessionEvents: true,
+ })
+ cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient))
+
+ return cs
+}
+
+// NewCryptoSetupServer creates a new crypto setup for the server
+func NewCryptoSetupServer(
+ connID protocol.ConnectionID,
+ localAddr, remoteAddr net.Addr,
+ tp *wire.TransportParameters,
+ tlsConf *tls.Config,
+ allow0RTT bool,
+ rttStats *utils.RTTStats,
+ qlogger qlogwriter.Recorder,
+ logger utils.Logger,
+ version protocol.Version,
+) CryptoSetup {
+ cs := newCryptoSetup(
+ connID,
+ tp,
+ rttStats,
+ qlogger,
+ logger,
+ protocol.PerspectiveServer,
+ version,
+ )
+ cs.allow0RTT = allow0RTT
+
+ tlsConf = setupConfigForServer(tlsConf, localAddr, remoteAddr)
+
+ cs.tlsConf = tlsConf
+ cs.conn = tls.QUICServer(&tls.QUICConfig{
+ TLSConfig: tlsConf,
+ EnableSessionEvents: true,
+ })
+ return cs
+}
+
+func newCryptoSetup(
+ connID protocol.ConnectionID,
+ tp *wire.TransportParameters,
+ rttStats *utils.RTTStats,
+ qlogger qlogwriter.Recorder,
+ logger utils.Logger,
+ perspective protocol.Perspective,
+ version protocol.Version,
+) *cryptoSetup {
+ initialSealer, initialOpener := NewInitialAEAD(connID, perspective, version)
+ if qlogger != nil {
+ qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveClient),
+ })
+ qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveServer),
+ })
+ }
+ return &cryptoSetup{
+ initialSealer: initialSealer,
+ initialOpener: initialOpener,
+ aead: newUpdatableAEAD(rttStats, qlogger, logger, version),
+ events: make([]Event, 0, 16),
+ ourParams: tp,
+ rttStats: rttStats,
+ qlogger: qlogger,
+ logger: logger,
+ perspective: perspective,
+ version: version,
+ }
+}
+
+func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) {
+ initialSealer, initialOpener := NewInitialAEAD(id, h.perspective, h.version)
+ h.initialSealer = initialSealer
+ h.initialOpener = initialOpener
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveClient),
+ })
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveServer),
+ })
+ }
+}
+
+func (h *cryptoSetup) SetLargest1RTTAcked(pn protocol.PacketNumber) error {
+ return h.aead.SetLargestAcked(pn)
+}
+
+func (h *cryptoSetup) StartHandshake(ctx context.Context) error {
+ err := h.conn.Start(context.WithValue(ctx, QUICVersionContextKey, h.version))
+ if err != nil {
+ return wrapError(err)
+ }
+ for {
+ ev := h.conn.NextEvent()
+ if err := h.handleEvent(ev); err != nil {
+ return wrapError(err)
+ }
+ if ev.Kind == tls.QUICNoEvent {
+ break
+ }
+ }
+ if h.perspective == protocol.PerspectiveClient {
+ if h.zeroRTTSealer != nil && h.zeroRTTParameters != nil {
+ h.logger.Debugf("Doing 0-RTT.")
+ h.events = append(h.events, Event{Kind: EventRestoredTransportParameters, TransportParameters: h.zeroRTTParameters})
+ } else {
+ h.logger.Debugf("Not doing 0-RTT. Has sealer: %t, has params: %t", h.zeroRTTSealer != nil, h.zeroRTTParameters != nil)
+ }
+ }
+ return nil
+}
+
+// Close closes the crypto setup.
+// It aborts the handshake, if it is still running.
+func (h *cryptoSetup) Close() error {
+ return h.conn.Close()
+}
+
+// HandleMessage handles a TLS handshake message.
+// It is called by the crypto streams when a new message is available.
+func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
+ if err := h.handleMessage(data, encLevel); err != nil {
+ return wrapError(err)
+ }
+ return nil
+}
+
+func (h *cryptoSetup) handleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
+ if err := h.conn.HandleData(encLevel.ToTLSEncryptionLevel(), data); err != nil {
+ return err
+ }
+ for {
+ ev := h.conn.NextEvent()
+ if err := h.handleEvent(ev); err != nil {
+ return err
+ }
+ if ev.Kind == tls.QUICNoEvent {
+ return nil
+ }
+ }
+}
+
+func (h *cryptoSetup) handleEvent(ev tls.QUICEvent) (err error) {
+ switch ev.Kind {
+ case tls.QUICNoEvent:
+ return nil
+ case tls.QUICSetReadSecret:
+ h.setReadKey(ev.Level, ev.Suite, ev.Data)
+ return nil
+ case tls.QUICSetWriteSecret:
+ h.setWriteKey(ev.Level, ev.Suite, ev.Data)
+ return nil
+ case tls.QUICTransportParameters:
+ return h.handleTransportParameters(ev.Data)
+ case tls.QUICTransportParametersRequired:
+ h.conn.SetTransportParameters(h.ourParams.Marshal(h.perspective))
+ return nil
+ case tls.QUICRejectedEarlyData:
+ h.rejected0RTT()
+ return nil
+ case tls.QUICWriteData:
+ h.writeRecord(ev.Level, ev.Data)
+ return nil
+ case tls.QUICHandshakeDone:
+ h.handshakeComplete()
+ return nil
+ case tls.QUICStoreSession:
+ if h.perspective == protocol.PerspectiveServer {
+ panic("cryptoSetup BUG: unexpected QUICStoreSession event for the server")
+ }
+ ev.SessionState.Extra = append(
+ ev.SessionState.Extra,
+ addSessionStateExtraPrefix(h.marshalDataForSessionState(ev.SessionState.EarlyData)),
+ )
+ return h.conn.StoreSession(ev.SessionState)
+ case tls.QUICResumeSession:
+ var allowEarlyData bool
+ switch h.perspective {
+ case protocol.PerspectiveClient:
+ // for clients, this event occurs when a session ticket is selected
+ allowEarlyData = h.handleDataFromSessionState(
+ findSessionStateExtraData(ev.SessionState.Extra),
+ ev.SessionState.EarlyData,
+ )
+ case protocol.PerspectiveServer:
+ // for servers, this event occurs when receiving the client's session ticket
+ allowEarlyData = h.handleSessionTicket(
+ findSessionStateExtraData(ev.SessionState.Extra),
+ ev.SessionState.EarlyData,
+ )
+ }
+ if ev.SessionState.EarlyData {
+ ev.SessionState.EarlyData = allowEarlyData
+ }
+ return nil
+ case quicErrorEvent:
+ return extractQUICEventError(ev)
+ default:
+ // Unknown events should be ignored.
+ // crypto/tls will ensure that this is safe to do.
+ // See the discussion following https://github.com/golang/go/issues/68124#issuecomment-2187042510 for details.
+ return nil
+ }
+}
+
+func (h *cryptoSetup) NextEvent() Event {
+ if len(h.events) == 0 {
+ return Event{Kind: EventNoEvent}
+ }
+ ev := h.events[0]
+ h.events = h.events[1:]
+ return ev
+}
+
+func (h *cryptoSetup) handleTransportParameters(data []byte) error {
+ var tp wire.TransportParameters
+ if err := tp.Unmarshal(data, h.perspective.Opposite()); err != nil {
+ return err
+ }
+ h.peerParams = &tp
+ h.events = append(h.events, Event{Kind: EventReceivedTransportParameters, TransportParameters: h.peerParams})
+ return nil
+}
+
+// must be called after receiving the transport parameters
+func (h *cryptoSetup) marshalDataForSessionState(earlyData bool) []byte {
+ b := make([]byte, 0, 256)
+ b = quicvarint.Append(b, clientSessionStateRevision)
+ if earlyData {
+ // only save the transport parameters for 0-RTT enabled session tickets
+ return h.peerParams.MarshalForSessionTicket(b)
+ }
+ return b
+}
+
+func (h *cryptoSetup) handleDataFromSessionState(data []byte, earlyData bool) (allowEarlyData bool) {
+ tp, err := decodeDataFromSessionState(data, earlyData)
+ if err != nil {
+ h.logger.Debugf("Restoring of transport parameters from session ticket failed: %s", err.Error())
+ return
+ }
+ // The session ticket might have been saved from a connection that allowed 0-RTT,
+ // and therefore contain transport parameters.
+ // Only use them if 0-RTT is actually used on the new connection.
+ if tp != nil && h.allow0RTT {
+ h.zeroRTTParameters = tp
+ return true
+ }
+ return false
+}
+
+func decodeDataFromSessionState(b []byte, earlyData bool) (*wire.TransportParameters, error) {
+ ver, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, err
+ }
+ b = b[l:]
+ if ver != clientSessionStateRevision {
+ return nil, fmt.Errorf("mismatching version. Got %d, expected %d", ver, clientSessionStateRevision)
+ }
+ if !earlyData {
+ return nil, nil
+ }
+ var tp wire.TransportParameters
+ if err := tp.UnmarshalFromSessionTicket(b); err != nil {
+ return nil, err
+ }
+ return &tp, nil
+}
+
+func (h *cryptoSetup) getDataForSessionTicket() []byte {
+ return (&sessionTicket{
+ Parameters: h.ourParams,
+ }).Marshal()
+}
+
+// GetSessionTicket generates a new session ticket.
+// Due to limitations in crypto/tls, it's only possible to generate a single session ticket per connection.
+// It is only valid for the server.
+func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
+ if err := h.conn.SendSessionTicket(tls.QUICSessionTicketOptions{
+ EarlyData: h.allow0RTT,
+ Extra: [][]byte{addSessionStateExtraPrefix(h.getDataForSessionTicket())},
+ }); err != nil {
+ // Session tickets might be disabled by tls.Config.SessionTicketsDisabled.
+ // We can't check h.tlsConfig here, since the actual config might have been obtained from
+ // the GetConfigForClient callback.
+ // See https://github.com/golang/go/issues/62032.
+ // This error assertion can be removed once we drop support for Go 1.25.
+ if strings.Contains(err.Error(), "session ticket keys unavailable") {
+ return nil, nil
+ }
+ return nil, err
+ }
+ // If session tickets are disabled, NextEvent will immediately return QUICNoEvent,
+ // and we will return a nil ticket.
+ var ticket []byte
+ for {
+ ev := h.conn.NextEvent()
+ if ev.Kind == tls.QUICNoEvent {
+ break
+ }
+ if ev.Kind == tls.QUICWriteData && ev.Level == tls.QUICEncryptionLevelApplication {
+ if ticket != nil {
+ h.logger.Errorf("unexpected multiple session tickets")
+ continue
+ }
+ ticket = ev.Data
+ } else {
+ h.logger.Errorf("unexpected event: %v", ev.Kind)
+ }
+ }
+ return ticket, nil
+}
+
+// handleSessionTicket is called for the server when receiving the client's session ticket.
+// It reads parameters from the session ticket and checks whether to accept 0-RTT if the session ticket enabled 0-RTT.
+// Note that the fact that the session ticket allows 0-RTT doesn't mean that the actual TLS handshake enables 0-RTT:
+// A client may use a 0-RTT enabled session to resume a TLS session without using 0-RTT.
+func (h *cryptoSetup) handleSessionTicket(data []byte, using0RTT bool) (allowEarlyData bool) {
+ var t sessionTicket
+ if err := t.Unmarshal(data); err != nil {
+ h.logger.Debugf("Unmarshalling session ticket failed: %s", err.Error())
+ return false
+ }
+ if !using0RTT {
+ return false
+ }
+ valid := h.ourParams.ValidFor0RTT(t.Parameters)
+ if !valid {
+ h.logger.Debugf("Transport parameters changed. Rejecting 0-RTT.")
+ return false
+ }
+ if !h.allow0RTT {
+ h.logger.Debugf("0-RTT not allowed. Rejecting 0-RTT.")
+ return false
+ }
+ return true
+}
+
+// rejected0RTT is called for the client when the server rejects 0-RTT.
+func (h *cryptoSetup) rejected0RTT() {
+ h.logger.Debugf("0-RTT was rejected. Dropping 0-RTT keys.")
+
+ had0RTTKeys := h.zeroRTTSealer != nil
+ h.zeroRTTSealer = nil
+
+ if had0RTTKeys {
+ h.events = append(h.events, Event{Kind: EventDiscard0RTTKeys})
+ }
+}
+
+func (h *cryptoSetup) setReadKey(el tls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
+ suite := getCipherSuite(suiteID)
+ //nolint:exhaustive // The TLS stack doesn't export Initial keys.
+ switch el {
+ case tls.QUICEncryptionLevelEarly:
+ if h.perspective == protocol.PerspectiveClient {
+ panic("Received 0-RTT read key for the client")
+ }
+ h.zeroRTTOpener = newLongHeaderOpener(
+ createAEAD(suite, trafficSecret, h.version),
+ newHeaderProtector(suite, trafficSecret, true, h.version),
+ )
+ h.used0RTT.Store(true)
+ if h.logger.Debug() {
+ h.logger.Debugf("Installed 0-RTT Read keys (using %s)", tls.CipherSuiteName(suite.ID))
+ }
+ case tls.QUICEncryptionLevelHandshake:
+ h.handshakeOpener = newLongHeaderOpener(
+ createAEAD(suite, trafficSecret, h.version),
+ newHeaderProtector(suite, trafficSecret, true, h.version),
+ )
+ if h.logger.Debug() {
+ h.logger.Debugf("Installed Handshake Read keys (using %s)", tls.CipherSuiteName(suite.ID))
+ }
+ case tls.QUICEncryptionLevelApplication:
+ h.aead.SetReadKey(suite, trafficSecret)
+ h.has1RTTOpener = true
+ if h.logger.Debug() {
+ h.logger.Debugf("Installed 1-RTT Read keys (using %s)", tls.CipherSuiteName(suite.ID))
+ }
+ default:
+ panic("unexpected read encryption level")
+ }
+ h.events = append(h.events, Event{Kind: EventReceivedReadKeys})
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.FromTLSEncryptionLevel(el), h.perspective.Opposite()),
+ })
+ }
+}
+
+func (h *cryptoSetup) setWriteKey(el tls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
+ suite := getCipherSuite(suiteID)
+ //nolint:exhaustive // The TLS stack doesn't export Initial keys.
+ switch el {
+ case tls.QUICEncryptionLevelEarly:
+ if h.perspective == protocol.PerspectiveServer {
+ panic("Received 0-RTT write key for the server")
+ }
+ h.zeroRTTSealer = newLongHeaderSealer(
+ createAEAD(suite, trafficSecret, h.version),
+ newHeaderProtector(suite, trafficSecret, true, h.version),
+ )
+ if h.logger.Debug() {
+ h.logger.Debugf("Installed 0-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
+ }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.Encryption0RTT, h.perspective),
+ })
+ }
+ // don't set used0RTT here. 0-RTT might still get rejected.
+ return
+ case tls.QUICEncryptionLevelHandshake:
+ h.handshakeSealer = newLongHeaderSealer(
+ createAEAD(suite, trafficSecret, h.version),
+ newHeaderProtector(suite, trafficSecret, true, h.version),
+ )
+ if h.logger.Debug() {
+ h.logger.Debugf("Installed Handshake Write keys (using %s)", tls.CipherSuiteName(suite.ID))
+ }
+ case tls.QUICEncryptionLevelApplication:
+ h.aead.SetWriteKey(suite, trafficSecret)
+ h.has1RTTSealer = true
+ if h.logger.Debug() {
+ h.logger.Debugf("Installed 1-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
+ }
+ if h.zeroRTTSealer != nil {
+ // Once we receive handshake keys, we know that 0-RTT was not rejected.
+ h.used0RTT.Store(true)
+ h.zeroRTTSealer = nil
+ h.logger.Debugf("Dropping 0-RTT keys.")
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClient0RTT})
+ }
+ }
+ default:
+ panic("unexpected write encryption level")
+ }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.FromTLSEncryptionLevel(el), h.perspective),
+ })
+ }
+}
+
+// writeRecord is called when TLS writes data
+func (h *cryptoSetup) writeRecord(encLevel tls.QUICEncryptionLevel, p []byte) {
+ //nolint:exhaustive // handshake records can only be written for Initial and Handshake.
+ switch encLevel {
+ case tls.QUICEncryptionLevelInitial:
+ h.events = append(h.events, Event{Kind: EventWriteInitialData, Data: p})
+ case tls.QUICEncryptionLevelHandshake:
+ h.events = append(h.events, Event{Kind: EventWriteHandshakeData, Data: p})
+ case tls.QUICEncryptionLevelApplication:
+ panic("unexpected write")
+ default:
+ panic(fmt.Sprintf("unexpected write encryption level: %s", encLevel))
+ }
+}
+
+func (h *cryptoSetup) DiscardInitialKeys() {
+ dropped := h.initialOpener != nil
+ h.initialOpener = nil
+ h.initialSealer = nil
+ if dropped {
+ h.logger.Debugf("Dropping Initial keys.")
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClientInitial})
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeServerInitial})
+ }
+ }
+}
+
+func (h *cryptoSetup) handshakeComplete() {
+ h.handshakeCompleteTime = time.Now()
+ h.events = append(h.events, Event{Kind: EventHandshakeComplete})
+}
+
+func (h *cryptoSetup) SetHandshakeConfirmed() {
+ h.aead.SetHandshakeConfirmed()
+ // drop Handshake keys
+ var dropped bool
+ if h.handshakeOpener != nil {
+ h.handshakeOpener = nil
+ h.handshakeSealer = nil
+ dropped = true
+ }
+ if dropped {
+ h.logger.Debugf("Dropping Handshake keys.")
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClientHandshake})
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeServerHandshake})
+ }
+ }
+}
+
+func (h *cryptoSetup) GetInitialSealer() (LongHeaderSealer, error) {
+ if h.initialSealer == nil {
+ return nil, ErrKeysDropped
+ }
+ return h.initialSealer, nil
+}
+
+func (h *cryptoSetup) Get0RTTSealer() (LongHeaderSealer, error) {
+ if h.zeroRTTSealer == nil {
+ return nil, ErrKeysDropped
+ }
+ return h.zeroRTTSealer, nil
+}
+
+func (h *cryptoSetup) GetHandshakeSealer() (LongHeaderSealer, error) {
+ if h.handshakeSealer == nil {
+ if h.initialSealer == nil {
+ return nil, ErrKeysDropped
+ }
+ return nil, ErrKeysNotYetAvailable
+ }
+ return h.handshakeSealer, nil
+}
+
+func (h *cryptoSetup) Get1RTTSealer() (ShortHeaderSealer, error) {
+ if !h.has1RTTSealer {
+ return nil, ErrKeysNotYetAvailable
+ }
+ return h.aead, nil
+}
+
+func (h *cryptoSetup) GetInitialOpener() (LongHeaderOpener, error) {
+ if h.initialOpener == nil {
+ return nil, ErrKeysDropped
+ }
+ return h.initialOpener, nil
+}
+
+func (h *cryptoSetup) Get0RTTOpener() (LongHeaderOpener, error) {
+ if h.zeroRTTOpener == nil {
+ if h.initialOpener != nil {
+ return nil, ErrKeysNotYetAvailable
+ }
+ // if the initial opener is also not available, the keys were already dropped
+ return nil, ErrKeysDropped
+ }
+ return h.zeroRTTOpener, nil
+}
+
+func (h *cryptoSetup) GetHandshakeOpener() (LongHeaderOpener, error) {
+ if h.handshakeOpener == nil {
+ if h.initialOpener != nil {
+ return nil, ErrKeysNotYetAvailable
+ }
+ // if the initial opener is also not available, the keys were already dropped
+ return nil, ErrKeysDropped
+ }
+ return h.handshakeOpener, nil
+}
+
+func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
+ if h.zeroRTTOpener != nil && time.Since(h.handshakeCompleteTime) > 3*h.rttStats.PTO(true) {
+ h.zeroRTTOpener = nil
+ h.logger.Debugf("Dropping 0-RTT keys.")
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClient0RTT})
+ }
+ }
+
+ if !h.has1RTTOpener {
+ return nil, ErrKeysNotYetAvailable
+ }
+ return h.aead, nil
+}
+
+func (h *cryptoSetup) ConnectionState() ConnectionState {
+ return ConnectionState{
+ ConnectionState: h.conn.ConnectionState(),
+ Used0RTT: h.used0RTT.Load(),
+ }
+}
+
+func wrapError(err error) error {
+ if alertErr := tls.AlertError(0); errors.As(err, &alertErr) {
+ return qerr.NewLocalCryptoError(uint8(alertErr), err)
+ }
+ return &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: err.Error()}
+}
+
+func encLevelToKeyType(encLevel protocol.EncryptionLevel, pers protocol.Perspective) qlog.KeyType {
+ if pers == protocol.PerspectiveServer {
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return qlog.KeyTypeServerInitial
+ case protocol.EncryptionHandshake:
+ return qlog.KeyTypeServerHandshake
+ case protocol.Encryption0RTT:
+ return qlog.KeyTypeServer0RTT
+ case protocol.Encryption1RTT:
+ return qlog.KeyTypeServer1RTT
+ default:
+ return ""
+ }
+ }
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return qlog.KeyTypeClientInitial
+ case protocol.EncryptionHandshake:
+ return qlog.KeyTypeClientHandshake
+ case protocol.Encryption0RTT:
+ return qlog.KeyTypeClient0RTT
+ case protocol.Encryption1RTT:
+ return qlog.KeyTypeClient1RTT
+ default:
+ return ""
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/fake_conn.go b/vendor/github.com/quic-go/quic-go/internal/handshake/fake_conn.go
new file mode 100644
index 00000000..54af823b
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/fake_conn.go
@@ -0,0 +1,21 @@
+package handshake
+
+import (
+ "net"
+ "time"
+)
+
+type conn struct {
+ localAddr, remoteAddr net.Addr
+}
+
+var _ net.Conn = &conn{}
+
+func (c *conn) Read([]byte) (int, error) { return 0, nil }
+func (c *conn) Write([]byte) (int, error) { return 0, nil }
+func (c *conn) Close() error { return nil }
+func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
+func (c *conn) LocalAddr() net.Addr { return c.localAddr }
+func (c *conn) SetReadDeadline(time.Time) error { return nil }
+func (c *conn) SetWriteDeadline(time.Time) error { return nil }
+func (c *conn) SetDeadline(time.Time) error { return nil }
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/fips140_go126.go b/vendor/github.com/quic-go/quic-go/internal/handshake/fips140_go126.go
new file mode 100644
index 00000000..4241794c
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/fips140_go126.go
@@ -0,0 +1,9 @@
+//go:build go1.26
+
+package handshake
+
+import "crypto/fips140"
+
+func withoutFIPSEnforcement(f func()) {
+ fips140.WithoutEnforcement(f)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/fips140_legacy.go b/vendor/github.com/quic-go/quic-go/internal/handshake/fips140_legacy.go
new file mode 100644
index 00000000..bc8e639a
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/fips140_legacy.go
@@ -0,0 +1,7 @@
+//go:build !go1.26
+
+package handshake
+
+func withoutFIPSEnforcement(f func()) {
+ f()
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go b/vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
new file mode 100644
index 00000000..3ea7caf1
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
@@ -0,0 +1,134 @@
+package handshake
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/tls"
+ "encoding/binary"
+ "fmt"
+
+ "golang.org/x/crypto/chacha20"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+type headerProtector interface {
+ EncryptHeader(sample []byte, firstByte *byte, hdrBytes []byte)
+ DecryptHeader(sample []byte, firstByte *byte, hdrBytes []byte)
+}
+
+func hkdfHeaderProtectionLabel(v protocol.Version) string {
+ if v == protocol.Version2 {
+ return "quicv2 hp"
+ }
+ return "quic hp"
+}
+
+func newHeaderProtector(suite cipherSuite, trafficSecret []byte, isLongHeader bool, v protocol.Version) headerProtector {
+ hkdfLabel := hkdfHeaderProtectionLabel(v)
+ switch suite.ID {
+ case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
+ return newAESHeaderProtector(suite, trafficSecret, isLongHeader, hkdfLabel)
+ case tls.TLS_CHACHA20_POLY1305_SHA256:
+ return newChaChaHeaderProtector(suite, trafficSecret, isLongHeader, hkdfLabel)
+ default:
+ panic(fmt.Sprintf("Invalid cipher suite id: %d", suite.ID))
+ }
+}
+
+type aesHeaderProtector struct {
+ mask [16]byte // AES always has a 16 byte block size
+ block cipher.Block
+ isLongHeader bool
+}
+
+var _ headerProtector = &aesHeaderProtector{}
+
+func newAESHeaderProtector(suite cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
+ hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
+ block, err := aes.NewCipher(hpKey)
+ if err != nil {
+ panic(fmt.Sprintf("error creating new AES cipher: %s", err))
+ }
+ return &aesHeaderProtector{
+ block: block,
+ isLongHeader: isLongHeader,
+ }
+}
+
+func (p *aesHeaderProtector) DecryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
+ p.apply(sample, firstByte, hdrBytes)
+}
+
+func (p *aesHeaderProtector) EncryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
+ p.apply(sample, firstByte, hdrBytes)
+}
+
+func (p *aesHeaderProtector) apply(sample []byte, firstByte *byte, hdrBytes []byte) {
+ if len(sample) != len(p.mask) {
+ panic("invalid sample size")
+ }
+ p.block.Encrypt(p.mask[:], sample)
+ if p.isLongHeader {
+ *firstByte ^= p.mask[0] & 0xf
+ } else {
+ *firstByte ^= p.mask[0] & 0x1f
+ }
+ for i := range hdrBytes {
+ hdrBytes[i] ^= p.mask[i+1]
+ }
+}
+
+type chachaHeaderProtector struct {
+ mask [5]byte
+
+ key [32]byte
+ isLongHeader bool
+}
+
+var _ headerProtector = &chachaHeaderProtector{}
+
+func newChaChaHeaderProtector(suite cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
+ hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
+
+ p := &chachaHeaderProtector{
+ isLongHeader: isLongHeader,
+ }
+ copy(p.key[:], hpKey)
+ return p
+}
+
+func (p *chachaHeaderProtector) DecryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
+ p.apply(sample, firstByte, hdrBytes)
+}
+
+func (p *chachaHeaderProtector) EncryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
+ p.apply(sample, firstByte, hdrBytes)
+}
+
+func (p *chachaHeaderProtector) apply(sample []byte, firstByte *byte, hdrBytes []byte) {
+ if len(sample) != 16 {
+ panic("invalid sample size")
+ }
+ for i := range 5 {
+ p.mask[i] = 0
+ }
+ cipher, err := chacha20.NewUnauthenticatedCipher(p.key[:], sample[4:])
+ if err != nil {
+ panic(err)
+ }
+ cipher.SetCounter(binary.LittleEndian.Uint32(sample[:4]))
+ cipher.XORKeyStream(p.mask[:], p.mask[:])
+ p.applyMask(firstByte, hdrBytes)
+}
+
+func (p *chachaHeaderProtector) applyMask(firstByte *byte, hdrBytes []byte) {
+ if p.isLongHeader {
+ *firstByte ^= p.mask[0] & 0xf
+ } else {
+ *firstByte ^= p.mask[0] & 0x1f
+ }
+ for i := range hdrBytes {
+ hdrBytes[i] ^= p.mask[i+1]
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/hkdf.go b/vendor/github.com/quic-go/quic-go/internal/handshake/hkdf.go
new file mode 100644
index 00000000..b28c1f1d
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/hkdf.go
@@ -0,0 +1,26 @@
+package handshake
+
+import (
+ "crypto"
+ "crypto/hkdf"
+ "encoding/binary"
+ "fmt"
+)
+
+// hkdfExpandLabel HKDF expands a label as defined in RFC 8446, section 7.1.
+func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
+ b := make([]byte, 3, 3+6+len(label)+1+len(context))
+ binary.BigEndian.PutUint16(b, uint16(length))
+ b[2] = uint8(6 + len(label))
+ b = append(b, []byte("tls13 ")...)
+ b = append(b, []byte(label)...)
+ b = b[:3+6+len(label)+1]
+ b[3+6+len(label)] = uint8(len(context))
+ b = append(b, context...)
+
+ expanded, err := hkdf.Expand(hash.New, secret, string(b), length)
+ if err != nil {
+ panic(fmt.Errorf("quic: HKDF-Expand-Label invocation failed unexpectedly: %v", err))
+ }
+ return expanded
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go b/vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go
new file mode 100644
index 00000000..ff8e377a
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go
@@ -0,0 +1,80 @@
+package handshake
+
+import (
+ "crypto"
+ "crypto/hkdf"
+ "crypto/tls"
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+var (
+ quicSaltV1 = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}
+ quicSaltV2 = []byte{0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9}
+)
+
+const (
+ hkdfLabelKeyV1 = "quic key"
+ hkdfLabelKeyV2 = "quicv2 key"
+ hkdfLabelIVV1 = "quic iv"
+ hkdfLabelIVV2 = "quicv2 iv"
+)
+
+var initialSuite = getCipherSuite(tls.TLS_AES_128_GCM_SHA256)
+
+// NewInitialAEAD creates a new AEAD for Initial encryption / decryption.
+func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective, v protocol.Version) (LongHeaderSealer, LongHeaderOpener) {
+ var sealer LongHeaderSealer
+ var opener LongHeaderOpener
+ // The keys for the Initial AEAD are derived from the connection ID and constants defined in RFC 9001, Section 5.2.
+ // By design, the Initial encryption level provides no confidentiality against any attacker who has read the RFC.
+ // Its sole purpose is integrity protection. The Initial encryption level is therefore out of scope for FIPS 140.
+ // See also this thread on the IETF QUIC mailing list: https://mailarchive.ietf.org/arch/msg/quic/k2kl2W_n5WDEZBbt3O31Ef2XBbM.
+ withoutFIPSEnforcement(func() {
+ clientSecret, serverSecret := computeSecrets(connID, v)
+ var mySecret, otherSecret []byte
+ if pers == protocol.PerspectiveClient {
+ mySecret = clientSecret
+ otherSecret = serverSecret
+ } else {
+ mySecret = serverSecret
+ otherSecret = clientSecret
+ }
+ myKey, myIV := computeInitialKeyAndIV(mySecret, v)
+ otherKey, otherIV := computeInitialKeyAndIV(otherSecret, v)
+
+ encrypter := initialSuite.AEAD(myKey, myIV)
+ decrypter := initialSuite.AEAD(otherKey, otherIV)
+
+ sealer = newLongHeaderSealer(encrypter, newHeaderProtector(initialSuite, mySecret, true, v))
+ opener = newLongHeaderOpener(decrypter, newHeaderProtector(initialSuite, otherSecret, true, v))
+ })
+ return sealer, opener
+}
+
+func computeSecrets(connID protocol.ConnectionID, v protocol.Version) (clientSecret, serverSecret []byte) {
+ salt := quicSaltV1
+ if v == protocol.Version2 {
+ salt = quicSaltV2
+ }
+ initialSecret, err := hkdf.Extract(crypto.SHA256.New, connID.Bytes(), salt)
+ if err != nil {
+ panic(fmt.Errorf("quic: HKDF-Extract invocation failed unexpectedly: %v", err))
+ }
+ clientSecret = hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size())
+ serverSecret = hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "server in", crypto.SHA256.Size())
+ return
+}
+
+func computeInitialKeyAndIV(secret []byte, v protocol.Version) (key, iv []byte) {
+ keyLabel := hkdfLabelKeyV1
+ ivLabel := hkdfLabelIVV1
+ if v == protocol.Version2 {
+ keyLabel = hkdfLabelKeyV2
+ ivLabel = hkdfLabelIVV2
+ }
+ key = hkdfExpandLabel(crypto.SHA256, secret, []byte{}, keyLabel, 16)
+ iv = hkdfExpandLabel(crypto.SHA256, secret, []byte{}, ivLabel, 12)
+ return
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/interface.go b/vendor/github.com/quic-go/quic-go/internal/handshake/interface.go
new file mode 100644
index 00000000..d9227339
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/interface.go
@@ -0,0 +1,140 @@
+package handshake
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+var (
+ // ErrKeysNotYetAvailable is returned when an opener or a sealer is requested for an encryption level,
+ // but the corresponding opener has not yet been initialized
+ // This can happen when packets arrive out of order.
+ ErrKeysNotYetAvailable = errors.New("CryptoSetup: keys at this encryption level not yet available")
+ // ErrKeysDropped is returned when an opener or a sealer is requested for an encryption level,
+ // but the corresponding keys have already been dropped.
+ ErrKeysDropped = errors.New("CryptoSetup: keys were already dropped")
+ // ErrDecryptionFailed is returned when the AEAD fails to open the packet.
+ ErrDecryptionFailed = errors.New("decryption failed")
+)
+
+type headerDecryptor interface {
+ DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte)
+}
+
+// LongHeaderOpener opens a long header packet
+type LongHeaderOpener interface {
+ headerDecryptor
+ DecodePacketNumber(wirePN protocol.PacketNumber, wirePNLen protocol.PacketNumberLen) protocol.PacketNumber
+ Open(dst, src []byte, pn protocol.PacketNumber, associatedData []byte) ([]byte, error)
+}
+
+// ShortHeaderOpener opens a short header packet
+type ShortHeaderOpener interface {
+ headerDecryptor
+ DecodePacketNumber(wirePN protocol.PacketNumber, wirePNLen protocol.PacketNumberLen) protocol.PacketNumber
+ Open(dst, src []byte, rcvTime monotime.Time, pn protocol.PacketNumber, kp protocol.KeyPhaseBit, associatedData []byte) ([]byte, error)
+}
+
+// LongHeaderSealer seals a long header packet
+type LongHeaderSealer interface {
+ Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte
+ EncryptHeader(sample []byte, firstByte *byte, pnBytes []byte)
+ Overhead() int
+}
+
+// ShortHeaderSealer seals a short header packet
+type ShortHeaderSealer interface {
+ LongHeaderSealer
+ KeyPhase() protocol.KeyPhaseBit
+}
+
+type ConnectionState struct {
+ tls.ConnectionState
+ Used0RTT bool
+}
+
+// EventKind is the kind of handshake event.
+type EventKind uint8
+
+const (
+ // EventNoEvent signals that there are no new handshake events
+ EventNoEvent EventKind = iota + 1
+ // EventWriteInitialData contains new CRYPTO data to send at the Initial encryption level
+ EventWriteInitialData
+ // EventWriteHandshakeData contains new CRYPTO data to send at the Handshake encryption level
+ EventWriteHandshakeData
+ // EventReceivedReadKeys signals that new decryption keys are available.
+ // It doesn't say which encryption level those keys are for.
+ EventReceivedReadKeys
+ // EventDiscard0RTTKeys signals that the Handshake keys were discarded.
+ EventDiscard0RTTKeys
+ // EventReceivedTransportParameters contains the transport parameters sent by the peer.
+ EventReceivedTransportParameters
+ // EventRestoredTransportParameters contains the transport parameters restored from the session ticket.
+ // It is only used for the client.
+ EventRestoredTransportParameters
+ // EventHandshakeComplete signals that the TLS handshake was completed.
+ EventHandshakeComplete
+)
+
+func (k EventKind) String() string {
+ switch k {
+ case EventNoEvent:
+ return "EventNoEvent"
+ case EventWriteInitialData:
+ return "EventWriteInitialData"
+ case EventWriteHandshakeData:
+ return "EventWriteHandshakeData"
+ case EventReceivedReadKeys:
+ return "EventReceivedReadKeys"
+ case EventDiscard0RTTKeys:
+ return "EventDiscard0RTTKeys"
+ case EventReceivedTransportParameters:
+ return "EventReceivedTransportParameters"
+ case EventRestoredTransportParameters:
+ return "EventRestoredTransportParameters"
+ case EventHandshakeComplete:
+ return "EventHandshakeComplete"
+ default:
+ return "Unknown EventKind"
+ }
+}
+
+// Event is a handshake event.
+type Event struct {
+ Kind EventKind
+ Data []byte
+ TransportParameters *wire.TransportParameters
+}
+
+// CryptoSetup handles the handshake and protecting / unprotecting packets
+type CryptoSetup interface {
+ StartHandshake(context.Context) error
+ io.Closer
+ ChangeConnectionID(protocol.ConnectionID)
+ GetSessionTicket() ([]byte, error)
+
+ HandleMessage([]byte, protocol.EncryptionLevel) error
+ NextEvent() Event
+
+ SetLargest1RTTAcked(protocol.PacketNumber) error
+ DiscardInitialKeys()
+ SetHandshakeConfirmed()
+ ConnectionState() ConnectionState
+
+ GetInitialOpener() (LongHeaderOpener, error)
+ GetHandshakeOpener() (LongHeaderOpener, error)
+ Get0RTTOpener() (LongHeaderOpener, error)
+ Get1RTTOpener() (ShortHeaderOpener, error)
+
+ GetInitialSealer() (LongHeaderSealer, error)
+ GetHandshakeSealer() (LongHeaderSealer, error)
+ Get0RTTSealer() (LongHeaderSealer, error)
+ Get1RTTSealer() (ShortHeaderSealer, error)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go125.go b/vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go125.go
new file mode 100644
index 00000000..e9553972
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go125.go
@@ -0,0 +1,11 @@
+//go:build go1.25 && !go1.26
+
+package handshake
+
+import "crypto/tls"
+
+const quicErrorEvent tls.QUICEventKind = -1
+
+func extractQUICEventError(tls.QUICEvent) error {
+ return nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go126.go b/vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go126.go
new file mode 100644
index 00000000..734778e0
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/quic_event_go126.go
@@ -0,0 +1,11 @@
+//go:build go1.26
+
+package handshake
+
+import "crypto/tls"
+
+const quicErrorEvent tls.QUICEventKind = tls.QUICErrorEvent
+
+func extractQUICEventError(ev tls.QUICEvent) error {
+ return ev.Err
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/retry_go125.go b/vendor/github.com/quic-go/quic-go/internal/handshake/retry_go125.go
new file mode 100644
index 00000000..8c525625
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/retry_go125.go
@@ -0,0 +1,68 @@
+//go:build !go1.26
+
+package handshake
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "fmt"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// Instead of using an init function, the AEADs are created lazily.
+// For more details see https://github.com/quic-go/quic-go/issues/4894.
+var (
+ retryAEADv1 cipher.AEAD // used for QUIC v1 (RFC 9000)
+ retryAEADv2 cipher.AEAD // used for QUIC v2 (RFC 9369)
+)
+
+func initAEAD(key [16]byte) cipher.AEAD {
+ aes, err := aes.NewCipher(key[:])
+ if err != nil {
+ panic(err)
+ }
+ aead, err := cipher.NewGCM(aes)
+ if err != nil {
+ panic(err)
+ }
+ return aead
+}
+
+var (
+ retryBuf bytes.Buffer
+ retryMutex sync.Mutex
+ retryNonceV1 = [12]byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
+ retryNonceV2 = [12]byte{0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a}
+)
+
+// GetRetryIntegrityTag calculates the integrity tag on a Retry packet
+func GetRetryIntegrityTag(retry []byte, origDestConnID protocol.ConnectionID, version protocol.Version) *[16]byte {
+ retryMutex.Lock()
+ defer retryMutex.Unlock()
+
+ retryBuf.WriteByte(uint8(origDestConnID.Len()))
+ retryBuf.Write(origDestConnID.Bytes())
+ retryBuf.Write(retry)
+ defer retryBuf.Reset()
+
+ var tag [16]byte
+ var sealed []byte
+ if version == protocol.Version2 {
+ if retryAEADv2 == nil {
+ retryAEADv2 = initAEAD([16]byte{0x8f, 0xb4, 0xb0, 0x1b, 0x56, 0xac, 0x48, 0xe2, 0x60, 0xfb, 0xcb, 0xce, 0xad, 0x7c, 0xcc, 0x92})
+ }
+ sealed = retryAEADv2.Seal(tag[:0], retryNonceV2[:], nil, retryBuf.Bytes())
+ } else {
+ if retryAEADv1 == nil {
+ retryAEADv1 = initAEAD([16]byte{0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e})
+ }
+ sealed = retryAEADv1.Seal(tag[:0], retryNonceV1[:], nil, retryBuf.Bytes())
+ }
+ if len(sealed) != 16 {
+ panic(fmt.Sprintf("unexpected Retry integrity tag length: %d", len(sealed)))
+ }
+ return &tag
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/retry_go126.go b/vendor/github.com/quic-go/quic-go/internal/handshake/retry_go126.go
new file mode 100644
index 00000000..bf95697e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/retry_go126.go
@@ -0,0 +1,70 @@
+//go:build go1.26
+
+package handshake
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/fips140"
+ "fmt"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// used for QUIC v1 (RFC 9000)
+var retryAEADv1 = initAEAD([16]byte{0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e})
+
+// used for QUIC v2 (RFC 9369)
+var retryAEADv2 = initAEAD([16]byte{0x8f, 0xb4, 0xb0, 0x1b, 0x56, 0xac, 0x48, 0xe2, 0x60, 0xfb, 0xcb, 0xce, 0xad, 0x7c, 0xcc, 0x92})
+
+func initAEAD(key [16]byte) cipher.AEAD {
+ aes, err := aes.NewCipher(key[:])
+ if err != nil {
+ panic(err)
+ }
+ var aead cipher.AEAD
+ // Retry packet authentication uses the fixed key and nonce specified by RFC 9000.
+ // It acts as an integrity tag for the Retry packet itself, protecting against
+ // accidental modification and making injection harder. It is not used to encrypt
+ // packet contents and therefore outside the scope of FIPS 140 enforcement.
+ fips140.WithoutEnforcement(func() {
+ var err error
+ aead, err = cipher.NewGCM(aes)
+ if err != nil {
+ panic(err)
+ }
+ })
+ return aead
+}
+
+var (
+ retryBuf bytes.Buffer
+ retryMutex sync.Mutex
+ retryNonceV1 = [12]byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
+ retryNonceV2 = [12]byte{0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a}
+)
+
+// GetRetryIntegrityTag calculates the integrity tag on a Retry packet
+func GetRetryIntegrityTag(retry []byte, origDestConnID protocol.ConnectionID, version protocol.Version) *[16]byte {
+ retryMutex.Lock()
+ defer retryMutex.Unlock()
+
+ retryBuf.WriteByte(uint8(origDestConnID.Len()))
+ retryBuf.Write(origDestConnID.Bytes())
+ retryBuf.Write(retry)
+ defer retryBuf.Reset()
+
+ var tag [16]byte
+ var sealed []byte
+ if version == protocol.Version2 {
+ sealed = retryAEADv2.Seal(tag[:0], retryNonceV2[:], nil, retryBuf.Bytes())
+ } else {
+ sealed = retryAEADv1.Seal(tag[:0], retryNonceV1[:], nil, retryBuf.Bytes())
+ }
+ if len(sealed) != 16 {
+ panic(fmt.Sprintf("unexpected Retry integrity tag length: %d", len(sealed)))
+ }
+ return &tag
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go b/vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
new file mode 100644
index 00000000..875b0d84
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
@@ -0,0 +1,56 @@
+package handshake
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+const sessionTicketRevision = 5
+
+type sessionTicket struct {
+ Parameters *wire.TransportParameters
+}
+
+func (t *sessionTicket) Marshal() []byte {
+ b := make([]byte, 0, 256)
+ b = quicvarint.Append(b, sessionTicketRevision)
+ return t.Parameters.MarshalForSessionTicket(b)
+}
+
+func (t *sessionTicket) Unmarshal(b []byte) error {
+ rev, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return errors.New("failed to read session ticket revision")
+ }
+ b = b[l:]
+ if rev != sessionTicketRevision {
+ return fmt.Errorf("unknown session ticket revision: %d", rev)
+ }
+ var tp wire.TransportParameters
+ if err := tp.UnmarshalFromSessionTicket(b); err != nil {
+ return fmt.Errorf("unmarshaling transport parameters from session ticket failed: %s", err.Error())
+ }
+ t.Parameters = &tp
+ return nil
+}
+
+const extraPrefix = "quic-go1"
+
+func addSessionStateExtraPrefix(b []byte) []byte {
+ return append([]byte(extraPrefix), b...)
+}
+
+func findSessionStateExtraData(extras [][]byte) []byte {
+ prefix := []byte(extraPrefix)
+ for _, extra := range extras {
+ if len(extra) < len(prefix) || !bytes.Equal(prefix, extra[:len(prefix)]) {
+ continue
+ }
+ return extra[len(prefix):]
+ }
+ return nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/tls_config.go b/vendor/github.com/quic-go/quic-go/internal/handshake/tls_config.go
new file mode 100644
index 00000000..c4c0d22d
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/tls_config.go
@@ -0,0 +1,39 @@
+package handshake
+
+import (
+ "crypto/tls"
+ "net"
+)
+
+func setupConfigForServer(conf *tls.Config, localAddr, remoteAddr net.Addr) *tls.Config {
+ // Workaround for https://github.com/golang/go/issues/60506.
+ // This initializes the session tickets _before_ cloning the config.
+ _, _ = conf.DecryptTicket(nil, tls.ConnectionState{})
+
+ conf = conf.Clone()
+ conf.MinVersion = tls.VersionTLS13
+
+ // The tls.Config contains two callbacks that pass in a tls.ClientHelloInfo.
+ // Since crypto/tls doesn't do it, we need to make sure to set the Conn field with a fake net.Conn
+ // that allows the caller to get the local and the remote address.
+ if conf.GetConfigForClient != nil {
+ gcfc := conf.GetConfigForClient
+ conf.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) {
+ info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
+ c, err := gcfc(info)
+ if c != nil {
+ // we're returning a tls.Config here, so we need to apply this recursively
+ c = setupConfigForServer(c, localAddr, remoteAddr)
+ }
+ return c, err
+ }
+ }
+ if conf.GetCertificate != nil {
+ gc := conf.GetCertificate
+ conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
+ return gc(info)
+ }
+ }
+ return conf
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go b/vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go
new file mode 100644
index 00000000..933670dd
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go
@@ -0,0 +1,126 @@
+package handshake
+
+import (
+ "bytes"
+ "encoding/asn1"
+ "fmt"
+ "net"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+const (
+ tokenPrefixIP byte = iota
+ tokenPrefixString
+)
+
+// A Token is derived from the client address and can be used to verify the ownership of this address.
+type Token struct {
+ IsRetryToken bool
+ SentTime time.Time
+ encodedRemoteAddr []byte
+ // only set for tokens sent in NEW_TOKEN frames
+ RTT time.Duration
+ // only set for retry tokens
+ OriginalDestConnectionID protocol.ConnectionID
+ RetrySrcConnectionID protocol.ConnectionID
+}
+
+// ValidateRemoteAddr validates the address, but does not check expiration
+func (t *Token) ValidateRemoteAddr(addr net.Addr) bool {
+ return bytes.Equal(encodeRemoteAddr(addr), t.encodedRemoteAddr)
+}
+
+// token is the struct that is used for ASN1 serialization and deserialization
+type token struct {
+ IsRetryToken bool
+ RemoteAddr []byte
+ Timestamp int64
+ RTT int64 // in mus
+ OriginalDestConnectionID []byte
+ RetrySrcConnectionID []byte
+}
+
+// A TokenGenerator generates tokens
+type TokenGenerator struct {
+ tokenProtector tokenProtector
+}
+
+// NewTokenGenerator initializes a new TokenGenerator
+func NewTokenGenerator(key TokenProtectorKey) *TokenGenerator {
+ return &TokenGenerator{tokenProtector: *newTokenProtector(key)}
+}
+
+// NewRetryToken generates a new token for a Retry for a given source address
+func (g *TokenGenerator) NewRetryToken(
+ raddr net.Addr,
+ origDestConnID protocol.ConnectionID,
+ retrySrcConnID protocol.ConnectionID,
+) ([]byte, error) {
+ data, err := asn1.Marshal(token{
+ IsRetryToken: true,
+ RemoteAddr: encodeRemoteAddr(raddr),
+ OriginalDestConnectionID: origDestConnID.Bytes(),
+ RetrySrcConnectionID: retrySrcConnID.Bytes(),
+ Timestamp: time.Now().UnixNano(),
+ })
+ if err != nil {
+ return nil, err
+ }
+ return g.tokenProtector.NewToken(data)
+}
+
+// NewToken generates a new token to be sent in a NEW_TOKEN frame
+func (g *TokenGenerator) NewToken(raddr net.Addr, rtt time.Duration) ([]byte, error) {
+ data, err := asn1.Marshal(token{
+ RemoteAddr: encodeRemoteAddr(raddr),
+ Timestamp: time.Now().UnixNano(),
+ RTT: rtt.Microseconds(),
+ })
+ if err != nil {
+ return nil, err
+ }
+ return g.tokenProtector.NewToken(data)
+}
+
+// DecodeToken decodes a token
+func (g *TokenGenerator) DecodeToken(encrypted []byte) (*Token, error) {
+ // if the client didn't send any token, DecodeToken will be called with a nil-slice
+ if len(encrypted) == 0 {
+ return nil, nil
+ }
+
+ data, err := g.tokenProtector.DecodeToken(encrypted)
+ if err != nil {
+ return nil, err
+ }
+ t := &token{}
+ rest, err := asn1.Unmarshal(data, t)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) != 0 {
+ return nil, fmt.Errorf("rest when unpacking token: %d", len(rest))
+ }
+ token := &Token{
+ IsRetryToken: t.IsRetryToken,
+ SentTime: time.Unix(0, t.Timestamp),
+ encodedRemoteAddr: t.RemoteAddr,
+ }
+ if t.IsRetryToken {
+ token.OriginalDestConnectionID = protocol.ParseConnectionID(t.OriginalDestConnectionID)
+ token.RetrySrcConnectionID = protocol.ParseConnectionID(t.RetrySrcConnectionID)
+ } else {
+ token.RTT = time.Duration(t.RTT) * time.Microsecond
+ }
+ return token, nil
+}
+
+// encodeRemoteAddr encodes a remote address such that it can be saved in the token
+func encodeRemoteAddr(remoteAddr net.Addr) []byte {
+ if udpAddr, ok := remoteAddr.(*net.UDPAddr); ok {
+ return append([]byte{tokenPrefixIP}, udpAddr.IP...)
+ }
+ return append([]byte{tokenPrefixString}, []byte(remoteAddr.String())...)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go b/vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go
new file mode 100644
index 00000000..74cd7d7b
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go
@@ -0,0 +1,78 @@
+package handshake
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hkdf"
+ "crypto/rand"
+ "crypto/sha256"
+ "fmt"
+)
+
+// TokenProtectorKey is the key used to encrypt both Retry and session resumption tokens.
+type TokenProtectorKey [32]byte
+
+const tokenSaltSize = 32
+
+// tokenProtector is used to create and verify a token
+type tokenProtector struct {
+ key TokenProtectorKey
+}
+
+// newTokenProtector creates a source for source address tokens
+func newTokenProtector(key TokenProtectorKey) *tokenProtector {
+ return &tokenProtector{key: key}
+}
+
+// NewToken encodes data into a new token.
+func (s *tokenProtector) NewToken(data []byte) ([]byte, error) {
+ var salt [tokenSaltSize]byte
+ if _, err := rand.Read(salt[:]); err != nil {
+ return nil, err
+ }
+ aead, err := s.createAEAD(salt[:])
+ if err != nil {
+ return nil, err
+ }
+ return append(salt[:], aead.Seal(nil, nil, data, nil)...), nil
+}
+
+// DecodeToken decodes a token.
+func (s *tokenProtector) DecodeToken(p []byte) ([]byte, error) {
+ if len(p) < tokenSaltSize {
+ return nil, fmt.Errorf("token too short: %d", len(p))
+ }
+ salt := p[:tokenSaltSize]
+ aead, err := s.createAEAD(salt)
+ if err != nil {
+ return nil, err
+ }
+ if len(p[tokenSaltSize:]) < aead.Overhead() {
+ return nil, fmt.Errorf("token too short: %d", len(p))
+ }
+ return aead.Open(nil, nil, p[tokenSaltSize:], nil)
+}
+
+const tokenProtectorHKDFInfo = "quic-go token source"
+
+func (s *tokenProtector) createAEAD(salt []byte) (cipher.AEAD, error) {
+ prk, err := hkdf.Extract(sha256.New, s.key[:], salt)
+ if err != nil {
+ return nil, err
+ }
+
+ key, err := hkdf.Expand(sha256.New, prk, tokenProtectorHKDFInfo, 32)
+ if err != nil {
+ return nil, err
+ }
+
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ aead, err := cipher.NewGCMWithRandomNonce(c)
+ if err != nil {
+ return nil, err
+ }
+ return aead, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go b/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
new file mode 100644
index 00000000..f88f76ad
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
@@ -0,0 +1,372 @@
+package handshake
+
+import (
+ "crypto"
+ "crypto/cipher"
+ "crypto/tls"
+ "encoding/binary"
+ "fmt"
+ "sync/atomic"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+var keyUpdateInterval atomic.Uint64
+
+func init() {
+ keyUpdateInterval.Store(protocol.KeyUpdateInterval)
+}
+
+func SetKeyUpdateInterval(v uint64) (reset func()) {
+ old := keyUpdateInterval.Swap(v)
+ return func() { keyUpdateInterval.Store(old) }
+}
+
+// FirstKeyUpdateInterval is the maximum number of packets we send or receive before initiating the first key update.
+// It's a package-level variable to allow modifying it for testing purposes.
+var FirstKeyUpdateInterval uint64 = 100
+
+type updatableAEAD struct {
+ suite cipherSuite
+
+ keyPhase protocol.KeyPhase
+ largestAcked protocol.PacketNumber
+ firstPacketNumber protocol.PacketNumber
+ handshakeConfirmed bool
+
+ invalidPacketLimit uint64
+ invalidPacketCount uint64
+
+ // Time when the keys should be dropped. Keys are dropped on the next call to Open().
+ prevRcvAEADExpiry monotime.Time
+ prevRcvAEAD cipher.AEAD
+
+ firstRcvdWithCurrentKey protocol.PacketNumber
+ firstSentWithCurrentKey protocol.PacketNumber
+ highestRcvdPN protocol.PacketNumber // highest packet number received (which could be successfully unprotected)
+ numRcvdWithCurrentKey uint64
+ numSentWithCurrentKey uint64
+ rcvAEAD cipher.AEAD
+ sendAEAD cipher.AEAD
+ // caches cipher.AEAD.Overhead(). This speeds up calls to Overhead().
+ aeadOverhead int
+
+ nextRcvAEAD cipher.AEAD
+ nextSendAEAD cipher.AEAD
+ nextRcvTrafficSecret []byte
+ nextSendTrafficSecret []byte
+
+ headerDecrypter headerProtector
+ headerEncrypter headerProtector
+
+ rttStats *utils.RTTStats
+
+ qlogger qlogwriter.Recorder
+ logger utils.Logger
+ version protocol.Version
+
+ // use a single slice to avoid allocations
+ nonceBuf []byte
+}
+
+var (
+ _ ShortHeaderOpener = &updatableAEAD{}
+ _ ShortHeaderSealer = &updatableAEAD{}
+)
+
+func newUpdatableAEAD(rttStats *utils.RTTStats, qlogger qlogwriter.Recorder, logger utils.Logger, version protocol.Version) *updatableAEAD {
+ return &updatableAEAD{
+ firstPacketNumber: protocol.InvalidPacketNumber,
+ largestAcked: protocol.InvalidPacketNumber,
+ firstRcvdWithCurrentKey: protocol.InvalidPacketNumber,
+ firstSentWithCurrentKey: protocol.InvalidPacketNumber,
+ rttStats: rttStats,
+ qlogger: qlogger,
+ logger: logger,
+ version: version,
+ }
+}
+
+func (a *updatableAEAD) rollKeys() {
+ if a.prevRcvAEAD != nil {
+ a.logger.Debugf("Dropping key phase %d ahead of scheduled time. Drop time was: %s", a.keyPhase-1, a.prevRcvAEADExpiry)
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
+ }
+ a.prevRcvAEADExpiry = 0
+ }
+
+ a.keyPhase++
+ a.firstRcvdWithCurrentKey = protocol.InvalidPacketNumber
+ a.firstSentWithCurrentKey = protocol.InvalidPacketNumber
+ a.numRcvdWithCurrentKey = 0
+ a.numSentWithCurrentKey = 0
+ a.prevRcvAEAD = a.rcvAEAD
+ a.rcvAEAD = a.nextRcvAEAD
+ a.sendAEAD = a.nextSendAEAD
+
+ a.nextRcvTrafficSecret = a.getNextTrafficSecret(a.suite.Hash, a.nextRcvTrafficSecret)
+ a.nextSendTrafficSecret = a.getNextTrafficSecret(a.suite.Hash, a.nextSendTrafficSecret)
+ a.nextRcvAEAD = createAEAD(a.suite, a.nextRcvTrafficSecret, a.version)
+ a.nextSendAEAD = createAEAD(a.suite, a.nextSendTrafficSecret, a.version)
+}
+
+func (a *updatableAEAD) startKeyDropTimer(now monotime.Time) {
+ d := 3 * a.rttStats.PTO(true)
+ a.logger.Debugf("Starting key drop timer to drop key phase %d (in %s)", a.keyPhase-1, d)
+ a.prevRcvAEADExpiry = now.Add(d)
+}
+
+func (a *updatableAEAD) getNextTrafficSecret(hash crypto.Hash, ts []byte) []byte {
+ return hkdfExpandLabel(hash, ts, []byte{}, "quic ku", hash.Size())
+}
+
+// SetReadKey sets the read key.
+// For the client, this function is called before SetWriteKey.
+// For the server, this function is called after SetWriteKey.
+func (a *updatableAEAD) SetReadKey(suite cipherSuite, trafficSecret []byte) {
+ a.rcvAEAD = createAEAD(suite, trafficSecret, a.version)
+ a.headerDecrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
+ if a.suite.ID == 0 { // suite is not set yet
+ a.setAEADParameters(a.rcvAEAD, suite)
+ }
+
+ a.nextRcvTrafficSecret = a.getNextTrafficSecret(suite.Hash, trafficSecret)
+ a.nextRcvAEAD = createAEAD(suite, a.nextRcvTrafficSecret, a.version)
+}
+
+// SetWriteKey sets the write key.
+// For the client, this function is called after SetReadKey.
+// For the server, this function is called before SetReadKey.
+func (a *updatableAEAD) SetWriteKey(suite cipherSuite, trafficSecret []byte) {
+ a.sendAEAD = createAEAD(suite, trafficSecret, a.version)
+ a.headerEncrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
+ if a.suite.ID == 0 { // suite is not set yet
+ a.setAEADParameters(a.sendAEAD, suite)
+ }
+
+ a.nextSendTrafficSecret = a.getNextTrafficSecret(suite.Hash, trafficSecret)
+ a.nextSendAEAD = createAEAD(suite, a.nextSendTrafficSecret, a.version)
+}
+
+func (a *updatableAEAD) setAEADParameters(aead cipher.AEAD, suite cipherSuite) {
+ a.nonceBuf = make([]byte, aead.NonceSize())
+ a.aeadOverhead = aead.Overhead()
+ a.suite = suite
+ switch suite.ID {
+ case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
+ a.invalidPacketLimit = protocol.InvalidPacketLimitAES
+ case tls.TLS_CHACHA20_POLY1305_SHA256:
+ a.invalidPacketLimit = protocol.InvalidPacketLimitChaCha
+ default:
+ panic(fmt.Sprintf("unknown cipher suite %d", suite.ID))
+ }
+}
+
+func (a *updatableAEAD) DecodePacketNumber(wirePN protocol.PacketNumber, wirePNLen protocol.PacketNumberLen) protocol.PacketNumber {
+ return protocol.DecodePacketNumber(wirePNLen, a.highestRcvdPN, wirePN)
+}
+
+func (a *updatableAEAD) Open(dst, src []byte, rcvTime monotime.Time, pn protocol.PacketNumber, kp protocol.KeyPhaseBit, ad []byte) ([]byte, error) {
+ dec, err := a.open(dst, src, rcvTime, pn, kp, ad)
+ if err == ErrDecryptionFailed {
+ a.invalidPacketCount++
+ if a.invalidPacketCount >= a.invalidPacketLimit {
+ return nil, &qerr.TransportError{ErrorCode: qerr.AEADLimitReached}
+ }
+ }
+ if err == nil {
+ a.highestRcvdPN = max(a.highestRcvdPN, pn)
+ }
+ return dec, err
+}
+
+func (a *updatableAEAD) open(dst, src []byte, rcvTime monotime.Time, pn protocol.PacketNumber, kp protocol.KeyPhaseBit, ad []byte) ([]byte, error) {
+ if a.prevRcvAEAD != nil && !a.prevRcvAEADExpiry.IsZero() && rcvTime.After(a.prevRcvAEADExpiry) {
+ a.prevRcvAEAD = nil
+ a.logger.Debugf("Dropping key phase %d", a.keyPhase-1)
+ a.prevRcvAEADExpiry = 0
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
+ }
+ }
+ binary.BigEndian.PutUint64(a.nonceBuf[len(a.nonceBuf)-8:], uint64(pn))
+ if kp != a.keyPhase.Bit() {
+ if a.keyPhase > 0 && a.firstRcvdWithCurrentKey == protocol.InvalidPacketNumber || pn < a.firstRcvdWithCurrentKey {
+ if a.prevRcvAEAD == nil {
+ return nil, ErrKeysDropped
+ }
+ // we updated the key, but the peer hasn't updated yet
+ dec, err := a.prevRcvAEAD.Open(dst, a.nonceBuf, src, ad)
+ if err != nil {
+ err = ErrDecryptionFailed
+ }
+ return dec, err
+ }
+ // try opening the packet with the next key phase
+ dec, err := a.nextRcvAEAD.Open(dst, a.nonceBuf, src, ad)
+ if err != nil {
+ return nil, ErrDecryptionFailed
+ }
+ // Opening succeeded. Check if the peer was allowed to update.
+ if a.keyPhase > 0 && a.firstSentWithCurrentKey == protocol.InvalidPacketNumber {
+ return nil, &qerr.TransportError{
+ ErrorCode: qerr.KeyUpdateError,
+ ErrorMessage: "keys updated too quickly",
+ }
+ }
+ a.rollKeys()
+ a.logger.Debugf("Peer updated keys to %d", a.keyPhase)
+ // The peer initiated this key update. It's safe to drop the keys for the previous generation now.
+ // Start a timer to drop the previous key generation.
+ a.startKeyDropTimer(rcvTime)
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateRemote,
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase,
+ })
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateRemote,
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase,
+ })
+ }
+ a.firstRcvdWithCurrentKey = pn
+ return dec, err
+ }
+ // The AEAD we're using here will be the qtls.aeadAESGCM13.
+ // It uses the nonce provided here and XOR it with the IV.
+ dec, err := a.rcvAEAD.Open(dst, a.nonceBuf, src, ad)
+ if err != nil {
+ return dec, ErrDecryptionFailed
+ }
+ a.numRcvdWithCurrentKey++
+ if a.firstRcvdWithCurrentKey == protocol.InvalidPacketNumber {
+ // We initiated the key updated, and now we received the first packet protected with the new key phase.
+ // Therefore, we are certain that the peer rolled its keys as well. Start a timer to drop the old keys.
+ if a.keyPhase > 0 {
+ a.logger.Debugf("Peer confirmed key update to phase %d", a.keyPhase)
+ a.startKeyDropTimer(rcvTime)
+ }
+ a.firstRcvdWithCurrentKey = pn
+ }
+ return dec, err
+}
+
+func (a *updatableAEAD) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte {
+ if a.firstSentWithCurrentKey == protocol.InvalidPacketNumber {
+ a.firstSentWithCurrentKey = pn
+ }
+ if a.firstPacketNumber == protocol.InvalidPacketNumber {
+ a.firstPacketNumber = pn
+ }
+ a.numSentWithCurrentKey++
+ binary.BigEndian.PutUint64(a.nonceBuf[len(a.nonceBuf)-8:], uint64(pn))
+ // The AEAD we're using here will be the qtls.aeadAESGCM13.
+ // It uses the nonce provided here and XOR it with the IV.
+ return a.sendAEAD.Seal(dst, a.nonceBuf, src, ad)
+}
+
+func (a *updatableAEAD) SetLargestAcked(pn protocol.PacketNumber) error {
+ if a.firstSentWithCurrentKey != protocol.InvalidPacketNumber &&
+ pn >= a.firstSentWithCurrentKey && a.numRcvdWithCurrentKey == 0 {
+ return &qerr.TransportError{
+ ErrorCode: qerr.KeyUpdateError,
+ ErrorMessage: fmt.Sprintf("received ACK for key phase %d, but peer didn't update keys", a.keyPhase),
+ }
+ }
+ a.largestAcked = pn
+ return nil
+}
+
+func (a *updatableAEAD) SetHandshakeConfirmed() {
+ a.handshakeConfirmed = true
+}
+
+func (a *updatableAEAD) updateAllowed() bool {
+ if !a.handshakeConfirmed {
+ return false
+ }
+ // the first key update is allowed as soon as the handshake is confirmed
+ return a.keyPhase == 0 ||
+ // subsequent key updates as soon as a packet sent with that key phase has been acknowledged
+ (a.firstSentWithCurrentKey != protocol.InvalidPacketNumber &&
+ a.largestAcked != protocol.InvalidPacketNumber &&
+ a.largestAcked >= a.firstSentWithCurrentKey)
+}
+
+func (a *updatableAEAD) shouldInitiateKeyUpdate() bool {
+ if !a.updateAllowed() {
+ return false
+ }
+ // Initiate the first key update shortly after the handshake, in order to exercise the key update mechanism.
+ if a.keyPhase == 0 {
+ if a.numRcvdWithCurrentKey >= FirstKeyUpdateInterval || a.numSentWithCurrentKey >= FirstKeyUpdateInterval {
+ return true
+ }
+ }
+ if a.numRcvdWithCurrentKey >= keyUpdateInterval.Load() {
+ a.logger.Debugf("Received %d packets with current key phase. Initiating key update to the next key phase: %d", a.numRcvdWithCurrentKey, a.keyPhase+1)
+ return true
+ }
+ if a.numSentWithCurrentKey >= keyUpdateInterval.Load() {
+ a.logger.Debugf("Sent %d packets with current key phase. Initiating key update to the next key phase: %d", a.numSentWithCurrentKey, a.keyPhase+1)
+ return true
+ }
+ return false
+}
+
+func (a *updatableAEAD) KeyPhase() protocol.KeyPhaseBit {
+ if a.shouldInitiateKeyUpdate() {
+ a.rollKeys()
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateLocal,
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase,
+ })
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateLocal,
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase,
+ })
+ }
+ }
+ return a.keyPhase.Bit()
+}
+
+func (a *updatableAEAD) Overhead() int {
+ return a.aeadOverhead
+}
+
+func (a *updatableAEAD) EncryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
+ a.headerEncrypter.EncryptHeader(sample, firstByte, hdrBytes)
+}
+
+func (a *updatableAEAD) DecryptHeader(sample []byte, firstByte *byte, hdrBytes []byte) {
+ a.headerDecrypter.DecryptHeader(sample, firstByte, hdrBytes)
+}
+
+func (a *updatableAEAD) FirstPacketNumber() protocol.PacketNumber {
+ return a.firstPacketNumber
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/monotime/time.go b/vendor/github.com/quic-go/quic-go/internal/monotime/time.go
new file mode 100644
index 00000000..eda61dc6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/monotime/time.go
@@ -0,0 +1,90 @@
+// Package monotime provides a monotonic time representation that is useful for
+// measuring elapsed time.
+// It is designed as a memory optimized drop-in replacement for time.Time, with
+// a monotime.Time consuming just 8 bytes instead of 24 bytes.
+package monotime
+
+import (
+ "time"
+)
+
+// The absolute value doesn't matter, but it should be in the past,
+// so that every timestamp obtained with Now() is non-zero,
+// even on systems with low timer resolutions (e.g. Windows).
+var start = time.Now().Add(-time.Hour)
+
+// A Time represents an instant in monotonic time.
+// Times can be compared using the comparison operators, but the specific
+// value is implementation-dependent and should not be relied upon.
+// The zero value of Time doesn't have any specific meaning.
+type Time int64
+
+// Now returns the current monotonic time.
+func Now() Time {
+ return Time(time.Since(start).Nanoseconds())
+}
+
+// Sub returns the duration t-t2. If the result exceeds the maximum (or minimum)
+// value that can be stored in a Duration, the maximum (or minimum) duration
+// will be returned.
+// To compute t-d for a duration d, use t.Add(-d).
+func (t Time) Sub(t2 Time) time.Duration {
+ return time.Duration(t - t2)
+}
+
+// Add returns the time t+d.
+func (t Time) Add(d time.Duration) Time {
+ return Time(int64(t) + d.Nanoseconds())
+}
+
+// After reports whether the time instant t is after t2.
+func (t Time) After(t2 Time) bool {
+ return t > t2
+}
+
+// Before reports whether the time instant t is before t2.
+func (t Time) Before(t2 Time) bool {
+ return t < t2
+}
+
+// IsZero reports whether t represents the zero time instant.
+func (t Time) IsZero() bool {
+ return t == 0
+}
+
+// Equal reports whether t and t2 represent the same time instant.
+func (t Time) Equal(t2 Time) bool {
+ return t == t2
+}
+
+// ToTime converts the monotonic time to a time.Time value.
+// The returned time.Time will have the same instant as the monotonic time,
+// but may be subject to clock adjustments.
+func (t Time) ToTime() time.Time {
+ if t.IsZero() {
+ return time.Time{}
+ }
+ return start.Add(time.Duration(t))
+}
+
+// Since returns the time elapsed since t. It is shorthand for Now().Sub(t).
+func Since(t Time) time.Duration {
+ return Now().Sub(t)
+}
+
+// Until returns the duration until t.
+// It is shorthand for t.Sub(Now()).
+// If t is in the past, the returned duration will be negative.
+func Until(t Time) time.Duration {
+ return time.Duration(t - Now())
+}
+
+// FromTime converts a time.Time to a monotonic Time.
+// The conversion is relative to the package's start time and may lose
+// precision if the time.Time is far from the start time.
+func FromTime(t time.Time) Time {
+ if t.IsZero() {
+ return 0
+ }
+ return Time(t.Sub(start).Nanoseconds())
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/connection_id.go b/vendor/github.com/quic-go/quic-go/internal/protocol/connection_id.go
new file mode 100644
index 00000000..ce3171fc
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/connection_id.go
@@ -0,0 +1,116 @@
+package protocol
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+ "errors"
+ "io"
+)
+
+var ErrInvalidConnectionIDLen = errors.New("invalid Connection ID length")
+
+// An ArbitraryLenConnectionID is a QUIC Connection ID able to represent Connection IDs according to RFC 8999.
+// Future QUIC versions might allow connection ID lengths up to 255 bytes, while QUIC v1
+// restricts the length to 20 bytes.
+type ArbitraryLenConnectionID []byte
+
+func (c ArbitraryLenConnectionID) Len() int {
+ return len(c)
+}
+
+func (c ArbitraryLenConnectionID) Bytes() []byte {
+ return c
+}
+
+func (c ArbitraryLenConnectionID) String() string {
+ if c.Len() == 0 {
+ return "(empty)"
+ }
+ return hex.EncodeToString(c.Bytes())
+}
+
+const maxConnectionIDLen = 20
+
+// A ConnectionID in QUIC
+type ConnectionID struct {
+ b [20]byte
+ l uint8
+}
+
+// GenerateConnectionID generates a connection ID using cryptographic random
+func GenerateConnectionID(l int) (ConnectionID, error) {
+ var c ConnectionID
+ c.l = uint8(l)
+ _, err := rand.Read(c.b[:l])
+ return c, err
+}
+
+// ParseConnectionID interprets b as a Connection ID.
+// It panics if b is longer than 20 bytes.
+func ParseConnectionID(b []byte) ConnectionID {
+ if len(b) > maxConnectionIDLen {
+ panic("invalid conn id length")
+ }
+ var c ConnectionID
+ c.l = uint8(len(b))
+ copy(c.b[:c.l], b)
+ return c
+}
+
+// GenerateConnectionIDForInitial generates a connection ID for the Initial packet.
+// It uses a length randomly chosen between 8 and 20 bytes.
+func GenerateConnectionIDForInitial() (ConnectionID, error) {
+ r := make([]byte, 1)
+ if _, err := rand.Read(r); err != nil {
+ return ConnectionID{}, err
+ }
+ l := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1)
+ return GenerateConnectionID(l)
+}
+
+// ReadConnectionID reads a connection ID of length len from the given io.Reader.
+// It returns io.EOF if there are not enough bytes to read.
+func ReadConnectionID(r io.Reader, l int) (ConnectionID, error) {
+ var c ConnectionID
+ if l == 0 {
+ return c, nil
+ }
+ if l > maxConnectionIDLen {
+ return c, ErrInvalidConnectionIDLen
+ }
+ c.l = uint8(l)
+ _, err := io.ReadFull(r, c.b[:l])
+ if err == io.ErrUnexpectedEOF {
+ return c, io.EOF
+ }
+ return c, err
+}
+
+// Len returns the length of the connection ID in bytes
+func (c ConnectionID) Len() int {
+ return int(c.l)
+}
+
+// Bytes returns the byte representation
+func (c ConnectionID) Bytes() []byte {
+ return c.b[:c.l]
+}
+
+func (c ConnectionID) String() string {
+ if c.Len() == 0 {
+ return "(empty)"
+ }
+ return hex.EncodeToString(c.Bytes())
+}
+
+type DefaultConnectionIDGenerator struct {
+ ConnLen int
+}
+
+func (d *DefaultConnectionIDGenerator) GenerateConnectionID() (ConnectionID, error) {
+ return GenerateConnectionID(d.ConnLen)
+}
+
+func (d *DefaultConnectionIDGenerator) ConnectionIDLen() int {
+ return d.ConnLen
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/encryption_level.go b/vendor/github.com/quic-go/quic-go/internal/protocol/encryption_level.go
new file mode 100644
index 00000000..40aa331a
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/encryption_level.go
@@ -0,0 +1,65 @@
+package protocol
+
+import (
+ "crypto/tls"
+ "fmt"
+)
+
+// EncryptionLevel is the encryption level
+// Default value is Unencrypted
+type EncryptionLevel uint8
+
+const (
+ // EncryptionInitial is the Initial encryption level
+ EncryptionInitial EncryptionLevel = 1 + iota
+ // EncryptionHandshake is the Handshake encryption level
+ EncryptionHandshake
+ // Encryption0RTT is the 0-RTT encryption level
+ Encryption0RTT
+ // Encryption1RTT is the 1-RTT encryption level
+ Encryption1RTT
+)
+
+func (e EncryptionLevel) String() string {
+ switch e {
+ case EncryptionInitial:
+ return "Initial"
+ case EncryptionHandshake:
+ return "Handshake"
+ case Encryption0RTT:
+ return "0-RTT"
+ case Encryption1RTT:
+ return "1-RTT"
+ }
+ return "unknown"
+}
+
+func (e EncryptionLevel) ToTLSEncryptionLevel() tls.QUICEncryptionLevel {
+ switch e {
+ case EncryptionInitial:
+ return tls.QUICEncryptionLevelInitial
+ case EncryptionHandshake:
+ return tls.QUICEncryptionLevelHandshake
+ case Encryption1RTT:
+ return tls.QUICEncryptionLevelApplication
+ case Encryption0RTT:
+ return tls.QUICEncryptionLevelEarly
+ default:
+ panic(fmt.Sprintf("unexpected encryption level: %s", e))
+ }
+}
+
+func FromTLSEncryptionLevel(e tls.QUICEncryptionLevel) EncryptionLevel {
+ switch e {
+ case tls.QUICEncryptionLevelInitial:
+ return EncryptionInitial
+ case tls.QUICEncryptionLevelHandshake:
+ return EncryptionHandshake
+ case tls.QUICEncryptionLevelApplication:
+ return Encryption1RTT
+ case tls.QUICEncryptionLevelEarly:
+ return Encryption0RTT
+ default:
+ panic(fmt.Sprintf("unexpect encryption level: %s", e))
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/key_phase.go b/vendor/github.com/quic-go/quic-go/internal/protocol/key_phase.go
new file mode 100644
index 00000000..edd740cf
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/key_phase.go
@@ -0,0 +1,36 @@
+package protocol
+
+// KeyPhase is the key phase
+type KeyPhase uint64
+
+// Bit determines the key phase bit
+func (p KeyPhase) Bit() KeyPhaseBit {
+ if p%2 == 0 {
+ return KeyPhaseZero
+ }
+ return KeyPhaseOne
+}
+
+// KeyPhaseBit is the key phase bit
+type KeyPhaseBit uint8
+
+const (
+ // KeyPhaseUndefined is an undefined key phase
+ KeyPhaseUndefined KeyPhaseBit = iota
+ // KeyPhaseZero is key phase 0
+ KeyPhaseZero
+ // KeyPhaseOne is key phase 1
+ KeyPhaseOne
+)
+
+func (p KeyPhaseBit) String() string {
+ //nolint:exhaustive
+ switch p {
+ case KeyPhaseZero:
+ return "0"
+ case KeyPhaseOne:
+ return "1"
+ default:
+ return "undefined"
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/packet_number.go b/vendor/github.com/quic-go/quic-go/internal/protocol/packet_number.go
new file mode 100644
index 00000000..9422db92
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/packet_number.go
@@ -0,0 +1,57 @@
+package protocol
+
+// A PacketNumber in QUIC
+type PacketNumber int64
+
+// InvalidPacketNumber is a packet number that is never sent.
+// In QUIC, 0 is a valid packet number.
+const InvalidPacketNumber PacketNumber = -1
+
+// PacketNumberLen is the length of the packet number in bytes
+type PacketNumberLen uint8
+
+const (
+ // PacketNumberLen1 is a packet number length of 1 byte
+ PacketNumberLen1 PacketNumberLen = 1
+ // PacketNumberLen2 is a packet number length of 2 bytes
+ PacketNumberLen2 PacketNumberLen = 2
+ // PacketNumberLen3 is a packet number length of 3 bytes
+ PacketNumberLen3 PacketNumberLen = 3
+ // PacketNumberLen4 is a packet number length of 4 bytes
+ PacketNumberLen4 PacketNumberLen = 4
+)
+
+// DecodePacketNumber calculates the packet number based its length and the last seen packet number
+// This function is taken from https://www.rfc-editor.org/rfc/rfc9000.html#section-a.3.
+func DecodePacketNumber(length PacketNumberLen, largest PacketNumber, truncated PacketNumber) PacketNumber {
+ expected := largest + 1
+ win := PacketNumber(1 << (length * 8))
+ hwin := win / 2
+ mask := win - 1
+ candidate := (expected & ^mask) | truncated
+ if candidate <= expected-hwin && candidate < 1<<62-win {
+ return candidate + win
+ }
+ if candidate > expected+hwin && candidate >= win {
+ return candidate - win
+ }
+ return candidate
+}
+
+// PacketNumberLengthForHeader gets the length of the packet number for the public header
+// it never chooses a PacketNumberLen of 1 byte, since this is too short under certain circumstances
+func PacketNumberLengthForHeader(pn, largestAcked PacketNumber) PacketNumberLen {
+ var numUnacked PacketNumber
+ if largestAcked == InvalidPacketNumber {
+ numUnacked = pn + 1
+ } else {
+ numUnacked = pn - largestAcked
+ }
+ if numUnacked < 1<<(16-1) {
+ return PacketNumberLen2
+ }
+ if numUnacked < 1<<(24-1) {
+ return PacketNumberLen3
+ }
+ return PacketNumberLen4
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/params.go b/vendor/github.com/quic-go/quic-go/internal/protocol/params.go
new file mode 100644
index 00000000..0861d57f
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/params.go
@@ -0,0 +1,169 @@
+package protocol
+
+import "time"
+
+// DesiredReceiveBufferSize is the kernel UDP receive buffer size that we'd like to use.
+const DesiredReceiveBufferSize = (1 << 20) * 7 // 7 MB
+
+// DesiredSendBufferSize is the kernel UDP send buffer size that we'd like to use.
+const DesiredSendBufferSize = (1 << 20) * 7 // 7 MB
+
+// InitialPacketSize is the initial (before Path MTU discovery) maximum packet size used.
+const InitialPacketSize = 1280
+
+// MaxCongestionWindowPackets is the maximum congestion window in packet.
+const MaxCongestionWindowPackets = 10000
+
+// MaxUndecryptablePackets limits the number of undecryptable packets that are queued in the connection.
+const MaxUndecryptablePackets = 32
+
+// ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window
+// This is the value that Chromium is using
+const ConnectionFlowControlMultiplier = 1.5
+
+// DefaultInitialMaxStreamData is the default initial stream-level flow control window for receiving data
+const DefaultInitialMaxStreamData = (1 << 10) * 512 // 512 kb
+
+// DefaultInitialMaxData is the connection-level flow control window for receiving data
+const DefaultInitialMaxData = ConnectionFlowControlMultiplier * DefaultInitialMaxStreamData
+
+// DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data
+const DefaultMaxReceiveStreamFlowControlWindow = 6 * (1 << 20) // 6 MB
+
+// DefaultMaxReceiveConnectionFlowControlWindow is the default connection-level flow control window for receiving data
+const DefaultMaxReceiveConnectionFlowControlWindow = 15 * (1 << 20) // 15 MB
+
+// WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client
+const WindowUpdateThreshold = 0.25
+
+// DefaultMaxIncomingStreams is the maximum number of streams that a peer may open
+const DefaultMaxIncomingStreams = 100
+
+// DefaultMaxIncomingUniStreams is the maximum number of unidirectional streams that a peer may open
+const DefaultMaxIncomingUniStreams = 100
+
+// MaxServerUnprocessedPackets is the max number of packets stored in the server that are not yet processed.
+const MaxServerUnprocessedPackets = 1024
+
+// MaxConnUnprocessedPackets is the max number of packets stored in each connection that are not yet processed.
+const MaxConnUnprocessedPackets = 256
+
+// SkipPacketInitialPeriod is the initial period length used for packet number skipping to prevent an Optimistic ACK attack.
+// Every time a packet number is skipped, the period is doubled, up to SkipPacketMaxPeriod.
+const SkipPacketInitialPeriod PacketNumber = 256
+
+// SkipPacketMaxPeriod is the maximum period length used for packet number skipping.
+const SkipPacketMaxPeriod PacketNumber = 128 * 1024
+
+// MaxAcceptQueueSize is the maximum number of connections that the server queues for accepting.
+// If the queue is full, new connection attempts will be rejected.
+const MaxAcceptQueueSize = 32
+
+// TokenValidity is the duration that a (non-retry) token is considered valid
+const TokenValidity = 24 * time.Hour
+
+// MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
+// When reached, it imposes a soft limit on sending new packets:
+// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent.
+const MaxOutstandingSentPackets = 2 * MaxCongestionWindowPackets
+
+// MaxTrackedSentPackets is maximum number of sent packets saved for retransmission.
+// When reached, no more packets will be sent.
+// This value *must* be larger than MaxOutstandingSentPackets.
+const MaxTrackedSentPackets = MaxOutstandingSentPackets * 5 / 4
+
+// MaxNonAckElicitingAcks is the maximum number of packets containing an ACK,
+// but no ack-eliciting frames, that we send in a row
+const MaxNonAckElicitingAcks = 19
+
+// MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames
+// prevents DoS attacks against the streamFrameSorter
+const MaxStreamFrameSorterGaps = 1000
+
+// MinStreamFrameBufferSize is the minimum data length of a received STREAM frame
+// that we use the buffer for. This protects against a DoS where an attacker would send us
+// very small STREAM frames to consume a lot of memory.
+const MinStreamFrameBufferSize = 128
+
+// MinCoalescedPacketSize is the minimum size of a coalesced packet that we pack.
+// If a packet has less than this number of bytes, we won't coalesce any more packets onto it.
+const MinCoalescedPacketSize = 128
+
+// MaxCryptoStreamOffset is the maximum offset allowed on any of the crypto streams.
+// This limits the size of the ClientHello and Certificates that can be received.
+const MaxCryptoStreamOffset = 16 * (1 << 10)
+
+// MinRemoteIdleTimeout is the minimum value that we accept for the remote idle timeout
+const MinRemoteIdleTimeout = 5 * time.Second
+
+// DefaultIdleTimeout is the default idle timeout
+const DefaultIdleTimeout = 30 * time.Second
+
+// DefaultHandshakeIdleTimeout is the default idle timeout used before handshake completion.
+const DefaultHandshakeIdleTimeout = 5 * time.Second
+
+// MinStreamFrameSize is the minimum size that has to be left in a packet, so that we add another STREAM frame.
+// This avoids splitting up STREAM frames into small pieces, which has 2 advantages:
+// 1. it reduces the framing overhead
+// 2. it reduces the head-of-line blocking, when a packet is lost
+const MinStreamFrameSize ByteCount = 128
+
+// MaxPostHandshakeCryptoFrameSize is the maximum size of CRYPTO frames
+// we send after the handshake completes.
+const MaxPostHandshakeCryptoFrameSize = 1000
+
+// MaxNumAckRanges is the maximum number of ACK ranges that we send in an ACK frame.
+// It also serves as a limit for the packet history.
+// If at any point we keep track of more ranges, old ranges are discarded.
+//
+// This value also guarantees that ACK Range Count value in the ACK frame can be encoded
+// in a single byte varint.
+const MaxNumAckRanges = 64
+
+// MinPacingDelay is the minimum duration that is used for packet pacing
+// If the packet packing frequency is higher, multiple packets might be sent at once.
+// Example: For a packet pacing delay of 200μs, we would send 5 packets at once, wait for 1ms, and so forth.
+const MinPacingDelay = time.Millisecond
+
+// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections
+// if no other value is configured.
+const DefaultConnectionIDLength = 4
+
+// MaxActiveConnectionIDs is the number of connection IDs that we're storing.
+const MaxActiveConnectionIDs = 4
+
+// MaxIssuedConnectionIDs is the maximum number of connection IDs that we're issuing at the same time.
+const MaxIssuedConnectionIDs = 6
+
+// PacketsPerConnectionID is the number of packets we send using one connection ID.
+// If the peer provices us with enough new connection IDs, we switch to a new connection ID.
+const PacketsPerConnectionID = 10000
+
+// AckDelayExponent is the ack delay exponent used when sending ACKs.
+const AckDelayExponent = 3
+
+// Estimated timer granularity.
+// The loss detection timer will not be set to a value smaller than granularity.
+const TimerGranularity = time.Millisecond
+
+// MaxAckDelay is the maximum time by which we delay sending ACKs.
+const MaxAckDelay = 25 * time.Millisecond
+
+// MaxAckDelayInclGranularity is the max_ack_delay including the timer granularity.
+// This is the value that should be advertised to the peer.
+const MaxAckDelayInclGranularity = MaxAckDelay + TimerGranularity
+
+// KeyUpdateInterval is the maximum number of packets we send or receive before initiating a key update.
+const KeyUpdateInterval = 100 * 1000
+
+// Max0RTTQueueingDuration is the maximum time that we store 0-RTT packets in order to wait for the corresponding Initial to be received.
+const Max0RTTQueueingDuration = 100 * time.Millisecond
+
+// Max0RTTQueues is the maximum number of connections that we buffer 0-RTT packets for.
+const Max0RTTQueues = 32
+
+// Max0RTTQueueLen is the maximum number of 0-RTT packets that we buffer for each connection.
+// When a new connection is created, all buffered packets are passed to the connection immediately.
+// To avoid blocking, this value has to be smaller than MaxConnUnprocessedPackets.
+// To avoid packets being dropped as undecryptable by the connection, this value has to be smaller than MaxUndecryptablePackets.
+const Max0RTTQueueLen = 31
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/perspective.go b/vendor/github.com/quic-go/quic-go/internal/protocol/perspective.go
new file mode 100644
index 00000000..5a29d3ce
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/perspective.go
@@ -0,0 +1,26 @@
+package protocol
+
+// Perspective determines if we're acting as a server or a client
+type Perspective int
+
+// the perspectives
+const (
+ PerspectiveServer Perspective = 1
+ PerspectiveClient Perspective = 2
+)
+
+// Opposite returns the perspective of the peer
+func (p Perspective) Opposite() Perspective {
+ return 3 - p
+}
+
+func (p Perspective) String() string {
+ switch p {
+ case PerspectiveServer:
+ return "server"
+ case PerspectiveClient:
+ return "client"
+ default:
+ return "invalid perspective"
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go b/vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
new file mode 100644
index 00000000..a8813a66
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
@@ -0,0 +1,159 @@
+package protocol
+
+import (
+ "fmt"
+ "sync/atomic"
+ "time"
+)
+
+// The PacketType is the Long Header Type
+type PacketType uint8
+
+const (
+ // PacketTypeInitial is the packet type of an Initial packet
+ PacketTypeInitial PacketType = 1 + iota
+ // PacketTypeRetry is the packet type of a Retry packet
+ PacketTypeRetry
+ // PacketTypeHandshake is the packet type of a Handshake packet
+ PacketTypeHandshake
+ // PacketType0RTT is the packet type of a 0-RTT packet
+ PacketType0RTT
+)
+
+func (t PacketType) String() string {
+ switch t {
+ case PacketTypeInitial:
+ return "Initial"
+ case PacketTypeRetry:
+ return "Retry"
+ case PacketTypeHandshake:
+ return "Handshake"
+ case PacketType0RTT:
+ return "0-RTT Protected"
+ default:
+ return fmt.Sprintf("unknown packet type: %d", t)
+ }
+}
+
+type ECN uint8
+
+const (
+ ECNUnsupported ECN = iota
+ ECNNon // 00
+ ECT1 // 01
+ ECT0 // 10
+ ECNCE // 11
+)
+
+func ParseECNHeaderBits(bits byte) ECN {
+ switch bits {
+ case 0:
+ return ECNNon
+ case 0b00000010:
+ return ECT0
+ case 0b00000001:
+ return ECT1
+ case 0b00000011:
+ return ECNCE
+ default:
+ panic("invalid ECN bits")
+ }
+}
+
+func (e ECN) ToHeaderBits() byte {
+ //nolint:exhaustive // There are only 4 values.
+ switch e {
+ case ECNNon:
+ return 0
+ case ECT0:
+ return 0b00000010
+ case ECT1:
+ return 0b00000001
+ case ECNCE:
+ return 0b00000011
+ default:
+ panic("ECN unsupported")
+ }
+}
+
+func (e ECN) String() string {
+ switch e {
+ case ECNUnsupported:
+ return "ECN unsupported"
+ case ECNNon:
+ return "Not-ECT"
+ case ECT1:
+ return "ECT(1)"
+ case ECT0:
+ return "ECT(0)"
+ case ECNCE:
+ return "CE"
+ default:
+ return fmt.Sprintf("invalid ECN value: %d", e)
+ }
+}
+
+// A ByteCount in QUIC
+type ByteCount int64
+
+type AtomicByteCount atomic.Int64
+
+// MaxByteCount is the maximum value of a ByteCount
+const MaxByteCount = ByteCount(1<<62 - 1)
+
+// InvalidByteCount is an invalid byte count
+const InvalidByteCount ByteCount = -1
+
+// A StatelessResetToken is a stateless reset token.
+type StatelessResetToken [16]byte
+
+// MaxPacketBufferSize maximum packet size of any QUIC packet, based on
+// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
+// UDP adds an additional 8 bytes. This is a total overhead of 48 bytes.
+// Ethernet's max packet size is 1500 bytes, 1500 - 48 = 1452.
+const MaxPacketBufferSize = 1452
+
+// MaxLargePacketBufferSize is used when using GSO
+const MaxLargePacketBufferSize = 20 * 1024
+
+// MinInitialPacketSize is the minimum size an Initial packet is required to have.
+const MinInitialPacketSize = 1200
+
+// MinUnknownVersionPacketSize is the minimum size a packet with an unknown version
+// needs to have in order to trigger a Version Negotiation packet.
+const MinUnknownVersionPacketSize = MinInitialPacketSize
+
+// MinStatelessResetSize is the minimum size of a stateless reset packet that we send
+const MinStatelessResetSize = 1 /* first byte */ + 20 /* max. conn ID length */ + 4 /* max. packet number length */ + 1 /* min. payload length */ + 16 /* token */
+
+// MinReceivedStatelessResetSize is the minimum size of a received stateless reset,
+// as specified in section 10.3 of RFC 9000.
+const MinReceivedStatelessResetSize = 5 + 16
+
+// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet.
+const MinConnectionIDLenInitial = 8
+
+// DefaultAckDelayExponent is the default ack delay exponent
+const DefaultAckDelayExponent = 3
+
+// DefaultActiveConnectionIDLimit is the default active connection ID limit
+const DefaultActiveConnectionIDLimit = 2
+
+// MaxAckDelayExponent is the maximum ack delay exponent
+const MaxAckDelayExponent = 20
+
+// DefaultMaxAckDelay is the default max_ack_delay
+const DefaultMaxAckDelay = 25 * time.Millisecond
+
+// MaxMaxAckDelay is the maximum max_ack_delay
+const MaxMaxAckDelay = (1<<14 - 1) * time.Millisecond
+
+// MaxConnIDLen is the maximum length of the connection ID
+const MaxConnIDLen = 20
+
+// InvalidPacketLimitAES is the maximum number of packets that we can fail to decrypt when using
+// AEAD_AES_128_GCM or AEAD_AES_265_GCM.
+const InvalidPacketLimitAES = 1 << 52
+
+// InvalidPacketLimitChaCha is the maximum number of packets that we can fail to decrypt when using AEAD_CHACHA20_POLY1305.
+const InvalidPacketLimitChaCha = 1 << 36
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/stream.go b/vendor/github.com/quic-go/quic-go/internal/protocol/stream.go
new file mode 100644
index 00000000..6db4a95b
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/stream.go
@@ -0,0 +1,102 @@
+package protocol
+
+import "github.com/quic-go/quic-go/quicvarint"
+
+// StreamType encodes if this is a unidirectional or bidirectional stream
+type StreamType uint8
+
+const (
+ // StreamTypeUni is a unidirectional stream
+ StreamTypeUni StreamType = iota
+ // StreamTypeBidi is a bidirectional stream
+ StreamTypeBidi
+)
+
+// InvalidPacketNumber is a stream ID that is invalid.
+// The first valid stream ID in QUIC is 0.
+const InvalidStreamID StreamID = -1
+
+// StreamNum is the stream number
+type StreamNum int64
+
+const (
+ // InvalidStreamNum is an invalid stream number.
+ InvalidStreamNum = -1
+ // MaxStreamCount is the maximum stream count value that can be sent in MAX_STREAMS frames
+ // and as the stream count in the transport parameters
+ MaxStreamCount StreamNum = 1 << 60
+ // MaxStreamID is the maximum stream ID
+ MaxStreamID StreamID = quicvarint.Max
+)
+
+const (
+ // FirstOutgoingBidiStreamClient is the first bidirectional stream opened by the client
+ FirstOutgoingBidiStreamClient StreamID = 0
+ // FirstOutgoingUniStreamClient is the first unidirectional stream opened by the client
+ FirstOutgoingUniStreamClient StreamID = 2
+ // FirstOutgoingBidiStreamServer is the first bidirectional stream opened by the server
+ FirstOutgoingBidiStreamServer StreamID = 1
+ // FirstOutgoingUniStreamServer is the first unidirectional stream opened by the server
+ FirstOutgoingUniStreamServer StreamID = 3
+)
+
+const (
+ // FirstIncomingBidiStreamServer is the first bidirectional stream accepted by the server
+ FirstIncomingBidiStreamServer = FirstOutgoingBidiStreamClient
+ // FirstIncomingUniStreamServer is the first unidirectional stream accepted by the server
+ FirstIncomingUniStreamServer = FirstOutgoingUniStreamClient
+ // FirstIncomingBidiStreamClient is the first bidirectional stream accepted by the client
+ FirstIncomingBidiStreamClient = FirstOutgoingBidiStreamServer
+ // FirstIncomingUniStreamClient is the first unidirectional stream accepted by the client
+ FirstIncomingUniStreamClient = FirstOutgoingUniStreamServer
+)
+
+// StreamID calculates the stream ID.
+func (s StreamNum) StreamID(stype StreamType, pers Perspective) StreamID {
+ if s == 0 {
+ return InvalidStreamID
+ }
+ var first StreamID
+ switch stype {
+ case StreamTypeBidi:
+ switch pers {
+ case PerspectiveClient:
+ first = 0
+ case PerspectiveServer:
+ first = 1
+ }
+ case StreamTypeUni:
+ switch pers {
+ case PerspectiveClient:
+ first = 2
+ case PerspectiveServer:
+ first = 3
+ }
+ }
+ return first + 4*StreamID(s-1)
+}
+
+// A StreamID in QUIC
+type StreamID int64
+
+// InitiatedBy says if the stream was initiated by the client or by the server
+func (s StreamID) InitiatedBy() Perspective {
+ if s%2 == 0 {
+ return PerspectiveClient
+ }
+ return PerspectiveServer
+}
+
+// Type says if this is a unidirectional or bidirectional stream
+func (s StreamID) Type() StreamType {
+ if s%4 >= 2 {
+ return StreamTypeUni
+ }
+ return StreamTypeBidi
+}
+
+// StreamNum returns how many streams in total are below this
+// Example: for stream 9 it returns 3 (i.e. streams 1, 5 and 9)
+func (s StreamID) StreamNum() StreamNum {
+ return StreamNum(s/4) + 1
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/version.go b/vendor/github.com/quic-go/quic-go/internal/protocol/version.go
new file mode 100644
index 00000000..8abca506
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/version.go
@@ -0,0 +1,115 @@
+package protocol
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+ "math"
+ mrand "math/rand/v2"
+ "slices"
+ "sync"
+)
+
+// Version is a version number as int
+type Version uint32
+
+// gQUIC version range as defined in the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions
+const (
+ gquicVersion0 = 0x51303030
+ maxGquicVersion = 0x51303439
+)
+
+// The version numbers, making grepping easier
+const (
+ VersionUnknown Version = math.MaxUint32
+ versionDraft29 Version = 0xff00001d // draft-29 used to be a widely deployed version
+ Version1 Version = 0x1
+ Version2 Version = 0x6b3343cf
+)
+
+// SupportedVersions lists the versions that the server supports
+// must be in sorted descending order
+var SupportedVersions = []Version{Version1, Version2}
+
+// IsValidVersion says if the version is known to quic-go
+func IsValidVersion(v Version) bool {
+ return v == Version1 || IsSupportedVersion(SupportedVersions, v)
+}
+
+func (vn Version) String() string {
+ switch vn {
+ case VersionUnknown:
+ return "unknown"
+ case versionDraft29:
+ return "draft-29"
+ case Version1:
+ return "v1"
+ case Version2:
+ return "v2"
+ default:
+ if vn.isGQUIC() {
+ return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion())
+ }
+ return fmt.Sprintf("%#x", uint32(vn))
+ }
+}
+
+func (vn Version) isGQUIC() bool {
+ return vn > gquicVersion0 && vn <= maxGquicVersion
+}
+
+func (vn Version) toGQUICVersion() int {
+ return int(10*(vn-gquicVersion0)/0x100) + int(vn%0x10)
+}
+
+// IsSupportedVersion returns true if the server supports this version
+func IsSupportedVersion(supported []Version, v Version) bool {
+ return slices.Contains(supported, v)
+}
+
+// ChooseSupportedVersion finds the best version in the overlap of ours and theirs
+// ours is a slice of versions that we support, sorted by our preference (descending)
+// theirs is a slice of versions offered by the peer. The order does not matter.
+// The bool returned indicates if a matching version was found.
+func ChooseSupportedVersion(ours, theirs []Version) (Version, bool) {
+ for _, ourVer := range ours {
+ if slices.Contains(theirs, ourVer) {
+ return ourVer, true
+ }
+ }
+ return 0, false
+}
+
+var (
+ versionNegotiationMx sync.Mutex
+ versionNegotiationRand mrand.Rand
+)
+
+func init() {
+ var seed [16]byte
+ rand.Read(seed[:])
+ versionNegotiationRand = *mrand.New(mrand.NewPCG(
+ binary.BigEndian.Uint64(seed[:8]),
+ binary.BigEndian.Uint64(seed[8:]),
+ ))
+}
+
+// generateReservedVersion generates a reserved version (v & 0x0f0f0f0f == 0x0a0a0a0a)
+func generateReservedVersion() Version {
+ var b [4]byte
+ binary.BigEndian.PutUint32(b[:], versionNegotiationRand.Uint32())
+ return Version((binary.BigEndian.Uint32(b[:]) | 0x0a0a0a0a) & 0xfafafafa)
+}
+
+// GetGreasedVersions adds one reserved version number to a slice of version numbers, at a random position.
+// It doesn't modify the supported slice.
+func GetGreasedVersions(supported []Version) []Version {
+ versionNegotiationMx.Lock()
+ defer versionNegotiationMx.Unlock()
+ randPos := versionNegotiationRand.IntN(len(supported) + 1)
+ greased := make([]Version, len(supported)+1)
+ copy(greased, supported[:randPos])
+ greased[randPos] = generateReservedVersion()
+ copy(greased[randPos+1:], supported[randPos:])
+ return greased
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go b/vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go
new file mode 100644
index 00000000..00361308
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go
@@ -0,0 +1,87 @@
+package qerr
+
+import (
+ "crypto/tls"
+ "fmt"
+)
+
+// TransportErrorCode is a QUIC transport error.
+type TransportErrorCode uint64
+
+// The error codes defined by QUIC
+const (
+ NoError TransportErrorCode = 0x0
+ InternalError TransportErrorCode = 0x1
+ ConnectionRefused TransportErrorCode = 0x2
+ FlowControlError TransportErrorCode = 0x3
+ StreamLimitError TransportErrorCode = 0x4
+ StreamStateError TransportErrorCode = 0x5
+ FinalSizeError TransportErrorCode = 0x6
+ FrameEncodingError TransportErrorCode = 0x7
+ TransportParameterError TransportErrorCode = 0x8
+ ConnectionIDLimitError TransportErrorCode = 0x9
+ ProtocolViolation TransportErrorCode = 0xa
+ InvalidToken TransportErrorCode = 0xb
+ ApplicationErrorErrorCode TransportErrorCode = 0xc
+ CryptoBufferExceeded TransportErrorCode = 0xd
+ KeyUpdateError TransportErrorCode = 0xe
+ AEADLimitReached TransportErrorCode = 0xf
+ NoViablePathError TransportErrorCode = 0x10
+)
+
+func (e TransportErrorCode) IsCryptoError() bool {
+ return e >= 0x100 && e < 0x200
+}
+
+// Message is a description of the error.
+// It only returns a non-empty string for crypto errors.
+func (e TransportErrorCode) Message() string {
+ if !e.IsCryptoError() {
+ return ""
+ }
+ return tls.AlertError(e - 0x100).Error()
+}
+
+func (e TransportErrorCode) String() string {
+ switch e {
+ case NoError:
+ return "NO_ERROR"
+ case InternalError:
+ return "INTERNAL_ERROR"
+ case ConnectionRefused:
+ return "CONNECTION_REFUSED"
+ case FlowControlError:
+ return "FLOW_CONTROL_ERROR"
+ case StreamLimitError:
+ return "STREAM_LIMIT_ERROR"
+ case StreamStateError:
+ return "STREAM_STATE_ERROR"
+ case FinalSizeError:
+ return "FINAL_SIZE_ERROR"
+ case FrameEncodingError:
+ return "FRAME_ENCODING_ERROR"
+ case TransportParameterError:
+ return "TRANSPORT_PARAMETER_ERROR"
+ case ConnectionIDLimitError:
+ return "CONNECTION_ID_LIMIT_ERROR"
+ case ProtocolViolation:
+ return "PROTOCOL_VIOLATION"
+ case InvalidToken:
+ return "INVALID_TOKEN"
+ case ApplicationErrorErrorCode:
+ return "APPLICATION_ERROR"
+ case CryptoBufferExceeded:
+ return "CRYPTO_BUFFER_EXCEEDED"
+ case KeyUpdateError:
+ return "KEY_UPDATE_ERROR"
+ case AEADLimitReached:
+ return "AEAD_LIMIT_REACHED"
+ case NoViablePathError:
+ return "NO_VIABLE_PATH"
+ default:
+ if e.IsCryptoError() {
+ return fmt.Sprintf("CRYPTO_ERROR %#x", uint16(e))
+ }
+ return fmt.Sprintf("unknown error code: %#x", uint16(e))
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/qerr/errors.go b/vendor/github.com/quic-go/quic-go/internal/qerr/errors.go
new file mode 100644
index 00000000..7fe1c293
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/qerr/errors.go
@@ -0,0 +1,134 @@
+package qerr
+
+import (
+ "fmt"
+ "net"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+var (
+ ErrHandshakeTimeout = &HandshakeTimeoutError{}
+ ErrIdleTimeout = &IdleTimeoutError{}
+)
+
+type TransportError struct {
+ Remote bool
+ FrameType uint64
+ ErrorCode TransportErrorCode
+ ErrorMessage string
+ error error // only set for local errors, sometimes
+}
+
+var _ error = &TransportError{}
+
+// NewLocalCryptoError create a new TransportError instance for a crypto error
+func NewLocalCryptoError(tlsAlert uint8, err error) *TransportError {
+ return &TransportError{
+ ErrorCode: 0x100 + TransportErrorCode(tlsAlert),
+ error: err,
+ }
+}
+
+func (e *TransportError) Error() string {
+ str := fmt.Sprintf("%s (%s)", e.ErrorCode.String(), getRole(e.Remote))
+ if e.FrameType != 0 {
+ str += fmt.Sprintf(" (frame type: %#x)", e.FrameType)
+ }
+ msg := e.ErrorMessage
+ if len(msg) == 0 && e.error != nil {
+ msg = e.error.Error()
+ }
+ if len(msg) == 0 {
+ msg = e.ErrorCode.Message()
+ }
+ if len(msg) == 0 {
+ return str
+ }
+ return str + ": " + msg
+}
+
+func (e *TransportError) Unwrap() []error { return []error{net.ErrClosed, e.error} }
+
+func (e *TransportError) Is(target error) bool {
+ t, ok := target.(*TransportError)
+ return ok && e.ErrorCode == t.ErrorCode && e.FrameType == t.FrameType && e.Remote == t.Remote
+}
+
+// An ApplicationErrorCode is an application-defined error code.
+type ApplicationErrorCode uint64
+
+// A StreamErrorCode is an error code used to cancel streams.
+type StreamErrorCode uint64
+
+type ApplicationError struct {
+ Remote bool
+ ErrorCode ApplicationErrorCode
+ ErrorMessage string
+}
+
+var _ error = &ApplicationError{}
+
+func (e *ApplicationError) Error() string {
+ if len(e.ErrorMessage) == 0 {
+ return fmt.Sprintf("Application error %#x (%s)", e.ErrorCode, getRole(e.Remote))
+ }
+ return fmt.Sprintf("Application error %#x (%s): %s", e.ErrorCode, getRole(e.Remote), e.ErrorMessage)
+}
+
+func (e *ApplicationError) Unwrap() error { return net.ErrClosed }
+
+func (e *ApplicationError) Is(target error) bool {
+ t, ok := target.(*ApplicationError)
+ return ok && e.ErrorCode == t.ErrorCode && e.Remote == t.Remote
+}
+
+type IdleTimeoutError struct{}
+
+var _ error = &IdleTimeoutError{}
+
+func (e *IdleTimeoutError) Timeout() bool { return true }
+func (e *IdleTimeoutError) Temporary() bool { return false }
+func (e *IdleTimeoutError) Error() string { return "timeout: no recent network activity" }
+func (e *IdleTimeoutError) Unwrap() error { return net.ErrClosed }
+
+type HandshakeTimeoutError struct{}
+
+var _ error = &HandshakeTimeoutError{}
+
+func (e *HandshakeTimeoutError) Timeout() bool { return true }
+func (e *HandshakeTimeoutError) Temporary() bool { return false }
+func (e *HandshakeTimeoutError) Error() string { return "timeout: handshake did not complete in time" }
+func (e *HandshakeTimeoutError) Unwrap() error { return net.ErrClosed }
+
+// A VersionNegotiationError occurs when the client and the server can't agree on a QUIC version.
+type VersionNegotiationError struct {
+ Ours []protocol.Version
+ Theirs []protocol.Version
+}
+
+func (e *VersionNegotiationError) Error() string {
+ return fmt.Sprintf("no compatible QUIC version found (we support %s, server offered %s)", e.Ours, e.Theirs)
+}
+
+func (e *VersionNegotiationError) Unwrap() error { return net.ErrClosed }
+
+// A StatelessResetError occurs when we receive a stateless reset.
+type StatelessResetError struct{}
+
+var _ net.Error = &StatelessResetError{}
+
+func (e *StatelessResetError) Error() string {
+ return "received a stateless reset"
+}
+
+func (e *StatelessResetError) Unwrap() error { return net.ErrClosed }
+func (e *StatelessResetError) Timeout() bool { return false }
+func (e *StatelessResetError) Temporary() bool { return true }
+
+func getRole(remote bool) string {
+ if remote {
+ return "remote"
+ }
+ return "local"
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go b/vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go
new file mode 100644
index 00000000..80ebfecb
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go
@@ -0,0 +1,26 @@
+package utils
+
+import (
+ "bufio"
+ "io"
+)
+
+type bufferedWriteCloser struct {
+ *bufio.Writer
+ io.Closer
+}
+
+// NewBufferedWriteCloser creates an io.WriteCloser from a bufio.Writer and an io.Closer
+func NewBufferedWriteCloser(writer *bufio.Writer, closer io.Closer) io.WriteCloser {
+ return &bufferedWriteCloser{
+ Writer: writer,
+ Closer: closer,
+ }
+}
+
+func (h bufferedWriteCloser) Close() error {
+ if err := h.Flush(); err != nil {
+ return err
+ }
+ return h.Closer.Close()
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/connstats.go b/vendor/github.com/quic-go/quic-go/internal/utils/connstats.go
new file mode 100644
index 00000000..19d88312
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/connstats.go
@@ -0,0 +1,14 @@
+package utils
+
+import "sync/atomic"
+
+// ConnectionStats stores stats for the connection. See the public
+// ConnectionStats struct in connection.go for more information
+type ConnectionStats struct {
+ BytesSent atomic.Uint64
+ PacketsSent atomic.Uint64
+ BytesReceived atomic.Uint64
+ PacketsReceived atomic.Uint64
+ BytesLost atomic.Uint64
+ PacketsLost atomic.Uint64
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/README.md b/vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/README.md
new file mode 100644
index 00000000..66482f4f
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/README.md
@@ -0,0 +1,6 @@
+# Usage
+
+This is the Go standard library implementation of a linked list
+(https://golang.org/src/container/list/list.go), with the following modifications:
+* it uses Go generics
+* it allows passing in a `sync.Pool` (via the `NewWithPool` constructor) to reduce allocations of `Element` structs
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/linkedlist.go b/vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/linkedlist.go
new file mode 100644
index 00000000..804a3444
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/linkedlist/linkedlist.go
@@ -0,0 +1,264 @@
+// 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 list implements a doubly linked list.
+//
+// To iterate over a list (where l is a *List[T]):
+//
+// for e := l.Front(); e != nil; e = e.Next() {
+// // do something with e.Value
+// }
+package list
+
+import "sync"
+
+func NewPool[T any]() *sync.Pool {
+ return &sync.Pool{New: func() any { return &Element[T]{} }}
+}
+
+// Element is an element of a linked list.
+type Element[T any] struct {
+ // Next and previous pointers in the doubly-linked list of elements.
+ // To simplify the implementation, internally a list l is implemented
+ // as a ring, such that &l.root is both the next element of the last
+ // list element (l.Back()) and the previous element of the first list
+ // element (l.Front()).
+ next, prev *Element[T]
+
+ // The list to which this element belongs.
+ list *List[T]
+
+ // The value stored with this element.
+ Value T
+}
+
+// Next returns the next list element or nil.
+func (e *Element[T]) Next() *Element[T] {
+ if p := e.next; e.list != nil && p != &e.list.root {
+ return p
+ }
+ return nil
+}
+
+// Prev returns the previous list element or nil.
+func (e *Element[T]) Prev() *Element[T] {
+ if p := e.prev; e.list != nil && p != &e.list.root {
+ return p
+ }
+ return nil
+}
+
+func (e *Element[T]) List() *List[T] {
+ return e.list
+}
+
+// List represents a doubly linked list.
+// The zero value for List is an empty list ready to use.
+type List[T any] struct {
+ root Element[T] // sentinel list element, only &root, root.prev, and root.next are used
+ len int // current list length excluding (this) sentinel element
+
+ pool *sync.Pool
+}
+
+// Init initializes or clears list l.
+func (l *List[T]) Init() *List[T] {
+ l.root.next = &l.root
+ l.root.prev = &l.root
+ l.len = 0
+ return l
+}
+
+// New returns an initialized list.
+func New[T any]() *List[T] { return new(List[T]).Init() }
+
+// NewWithPool returns an initialized list, using a sync.Pool for list elements.
+func NewWithPool[T any](pool *sync.Pool) *List[T] {
+ l := &List[T]{pool: pool}
+ return l.Init()
+}
+
+// Len returns the number of elements of list l.
+// The complexity is O(1).
+func (l *List[T]) Len() int { return l.len }
+
+// Front returns the first element of list l or nil if the list is empty.
+func (l *List[T]) Front() *Element[T] {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.next
+}
+
+// Back returns the last element of list l or nil if the list is empty.
+func (l *List[T]) Back() *Element[T] {
+ if l.len == 0 {
+ return nil
+ }
+ return l.root.prev
+}
+
+// lazyInit lazily initializes a zero List value.
+func (l *List[T]) lazyInit() {
+ if l.root.next == nil {
+ l.Init()
+ }
+}
+
+// insert inserts e after at, increments l.len, and returns e.
+func (l *List[T]) insert(e, at *Element[T]) *Element[T] {
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+ e.list = l
+ l.len++
+ return e
+}
+
+// insertValue is a convenience wrapper for insert(&Element{Value: v}, at).
+func (l *List[T]) insertValue(v T, at *Element[T]) *Element[T] {
+ var e *Element[T]
+ if l.pool != nil {
+ e = l.pool.Get().(*Element[T])
+ } else {
+ e = &Element[T]{}
+ }
+ e.Value = v
+ return l.insert(e, at)
+}
+
+// remove removes e from its list, decrements l.len
+func (l *List[T]) remove(e *Element[T]) {
+ e.prev.next = e.next
+ e.next.prev = e.prev
+ e.next = nil // avoid memory leaks
+ e.prev = nil // avoid memory leaks
+ e.list = nil
+ if l.pool != nil {
+ l.pool.Put(e)
+ }
+ l.len--
+}
+
+// move moves e to next to at.
+func (l *List[T]) move(e, at *Element[T]) {
+ if e == at {
+ return
+ }
+ e.prev.next = e.next
+ e.next.prev = e.prev
+
+ e.prev = at
+ e.next = at.next
+ e.prev.next = e
+ e.next.prev = e
+}
+
+// Remove removes e from l if e is an element of list l.
+// It returns the element value e.Value.
+// The element must not be nil.
+func (l *List[T]) Remove(e *Element[T]) T {
+ v := e.Value
+ if e.list == l {
+ // if e.list == l, l must have been initialized when e was inserted
+ // in l or l == nil (e is a zero Element) and l.remove will crash
+ l.remove(e)
+ }
+ return v
+}
+
+// PushFront inserts a new element e with value v at the front of list l and returns e.
+func (l *List[T]) PushFront(v T) *Element[T] {
+ l.lazyInit()
+ return l.insertValue(v, &l.root)
+}
+
+// PushBack inserts a new element e with value v at the back of list l and returns e.
+func (l *List[T]) PushBack(v T) *Element[T] {
+ l.lazyInit()
+ return l.insertValue(v, l.root.prev)
+}
+
+// InsertBefore inserts a new element e with value v immediately before mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *List[T]) InsertBefore(v T, mark *Element[T]) *Element[T] {
+ if mark.list != l {
+ return nil
+ }
+ // see comment in List.Remove about initialization of l
+ return l.insertValue(v, mark.prev)
+}
+
+// InsertAfter inserts a new element e with value v immediately after mark and returns e.
+// If mark is not an element of l, the list is not modified.
+// The mark must not be nil.
+func (l *List[T]) InsertAfter(v T, mark *Element[T]) *Element[T] {
+ if mark.list != l {
+ return nil
+ }
+ // see comment in List.Remove about initialization of l
+ return l.insertValue(v, mark)
+}
+
+// MoveToFront moves element e to the front of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *List[T]) MoveToFront(e *Element[T]) {
+ if e.list != l || l.root.next == e {
+ return
+ }
+ // see comment in List.Remove about initialization of l
+ l.move(e, &l.root)
+}
+
+// MoveToBack moves element e to the back of list l.
+// If e is not an element of l, the list is not modified.
+// The element must not be nil.
+func (l *List[T]) MoveToBack(e *Element[T]) {
+ if e.list != l || l.root.prev == e {
+ return
+ }
+ // see comment in List.Remove about initialization of l
+ l.move(e, l.root.prev)
+}
+
+// MoveBefore moves element e to its new position before mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *List[T]) MoveBefore(e, mark *Element[T]) {
+ if e.list != l || e == mark || mark.list != l {
+ return
+ }
+ l.move(e, mark.prev)
+}
+
+// MoveAfter moves element e to its new position after mark.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
+// The element and mark must not be nil.
+func (l *List[T]) MoveAfter(e, mark *Element[T]) {
+ if e.list != l || e == mark || mark.list != l {
+ return
+ }
+ l.move(e, mark)
+}
+
+// PushBackList inserts a copy of another list at the back of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *List[T]) PushBackList(other *List[T]) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {
+ l.insertValue(e.Value, l.root.prev)
+ }
+}
+
+// PushFrontList inserts a copy of another list at the front of list l.
+// The lists l and other may be the same. They must not be nil.
+func (l *List[T]) PushFrontList(other *List[T]) {
+ l.lazyInit()
+ for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() {
+ l.insertValue(e.Value, &l.root)
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/log.go b/vendor/github.com/quic-go/quic-go/internal/utils/log.go
new file mode 100644
index 00000000..558803ef
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/log.go
@@ -0,0 +1,131 @@
+package utils
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "strings"
+ "time"
+)
+
+// LogLevel of quic-go
+type LogLevel uint8
+
+const (
+ // LogLevelNothing disables
+ LogLevelNothing LogLevel = iota
+ // LogLevelError enables err logs
+ LogLevelError
+ // LogLevelInfo enables info logs (e.g. packets)
+ LogLevelInfo
+ // LogLevelDebug enables debug logs (e.g. packet contents)
+ LogLevelDebug
+)
+
+const logEnv = "QUIC_GO_LOG_LEVEL"
+
+// A Logger logs.
+type Logger interface {
+ SetLogLevel(LogLevel)
+ SetLogTimeFormat(format string)
+ WithPrefix(prefix string) Logger
+ Debug() bool
+
+ Errorf(format string, args ...any)
+ Infof(format string, args ...any)
+ Debugf(format string, args ...any)
+}
+
+// DefaultLogger is used by quic-go for logging.
+var DefaultLogger Logger
+
+type defaultLogger struct {
+ prefix string
+
+ logLevel LogLevel
+ timeFormat string
+}
+
+var _ Logger = &defaultLogger{}
+
+// SetLogLevel sets the log level
+func (l *defaultLogger) SetLogLevel(level LogLevel) {
+ l.logLevel = level
+}
+
+// SetLogTimeFormat sets the format of the timestamp
+// an empty string disables the logging of timestamps
+func (l *defaultLogger) SetLogTimeFormat(format string) {
+ log.SetFlags(0) // disable timestamp logging done by the log package
+ l.timeFormat = format
+}
+
+// Debugf logs something
+func (l *defaultLogger) Debugf(format string, args ...any) {
+ if l.logLevel == LogLevelDebug {
+ l.logMessage(format, args...)
+ }
+}
+
+// Infof logs something
+func (l *defaultLogger) Infof(format string, args ...any) {
+ if l.logLevel >= LogLevelInfo {
+ l.logMessage(format, args...)
+ }
+}
+
+// Errorf logs something
+func (l *defaultLogger) Errorf(format string, args ...any) {
+ if l.logLevel >= LogLevelError {
+ l.logMessage(format, args...)
+ }
+}
+
+func (l *defaultLogger) logMessage(format string, args ...any) {
+ var pre string
+
+ if len(l.timeFormat) > 0 {
+ pre = time.Now().Format(l.timeFormat) + " "
+ }
+ if len(l.prefix) > 0 {
+ pre += l.prefix + " "
+ }
+ log.Printf(pre+format, args...)
+}
+
+func (l *defaultLogger) WithPrefix(prefix string) Logger {
+ if len(l.prefix) > 0 {
+ prefix = l.prefix + " " + prefix
+ }
+ return &defaultLogger{
+ logLevel: l.logLevel,
+ timeFormat: l.timeFormat,
+ prefix: prefix,
+ }
+}
+
+// Debug returns true if the log level is LogLevelDebug
+func (l *defaultLogger) Debug() bool {
+ return l.logLevel == LogLevelDebug
+}
+
+func init() {
+ DefaultLogger = &defaultLogger{}
+ DefaultLogger.SetLogLevel(readLoggingEnv())
+}
+
+func readLoggingEnv() LogLevel {
+ switch strings.ToLower(os.Getenv(logEnv)) {
+ case "":
+ return LogLevelNothing
+ case "debug":
+ return LogLevelDebug
+ case "info":
+ return LogLevelInfo
+ case "error":
+ return LogLevelError
+ default:
+ fmt.Fprintln(os.Stderr, "invalid quic-go log level, see https://github.com/quic-go/quic-go/wiki/Logging")
+ return LogLevelNothing
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/rand.go b/vendor/github.com/quic-go/quic-go/internal/utils/rand.go
new file mode 100644
index 00000000..30069144
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/rand.go
@@ -0,0 +1,29 @@
+package utils
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+)
+
+// Rand is a wrapper around crypto/rand that adds some convenience functions known from math/rand.
+type Rand struct {
+ buf [4]byte
+}
+
+func (r *Rand) Int31() int32 {
+ rand.Read(r.buf[:])
+ return int32(binary.BigEndian.Uint32(r.buf[:]) & ^uint32(1<<31))
+}
+
+// copied from the standard library math/rand implementation of Int63n
+func (r *Rand) Int31n(n int32) int32 {
+ if n&(n-1) == 0 { // n is power of two, can mask
+ return r.Int31() & (n - 1)
+ }
+ max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
+ v := r.Int31()
+ for v > max {
+ v = r.Int31()
+ }
+ return v % n
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go b/vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go
new file mode 100644
index 00000000..f9b2c797
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go
@@ -0,0 +1,96 @@
+package ringbuffer
+
+// A RingBuffer is a ring buffer.
+// It acts as a heap that doesn't cause any allocations.
+type RingBuffer[T any] struct {
+ ring []T
+ headPos, tailPos int
+ full bool
+}
+
+// Init preallocates a buffer with a certain size.
+func (r *RingBuffer[T]) Init(size int) {
+ r.ring = make([]T, size)
+}
+
+// Len returns the number of elements in the ring buffer.
+func (r *RingBuffer[T]) Len() int {
+ if r.full {
+ return len(r.ring)
+ }
+ if r.tailPos >= r.headPos {
+ return r.tailPos - r.headPos
+ }
+ return r.tailPos - r.headPos + len(r.ring)
+}
+
+// Empty says if the ring buffer is empty.
+func (r *RingBuffer[T]) Empty() bool {
+ return !r.full && r.headPos == r.tailPos
+}
+
+// PushBack adds a new element.
+// If the ring buffer is full, its capacity is increased first.
+func (r *RingBuffer[T]) PushBack(t T) {
+ if r.full || len(r.ring) == 0 {
+ r.grow()
+ }
+ r.ring[r.tailPos] = t
+ r.tailPos++
+ if r.tailPos == len(r.ring) {
+ r.tailPos = 0
+ }
+ if r.tailPos == r.headPos {
+ r.full = true
+ }
+}
+
+// PopFront returns the next element.
+// It must not be called when the buffer is empty, that means that
+// callers might need to check if there are elements in the buffer first.
+func (r *RingBuffer[T]) PopFront() T {
+ if r.Empty() {
+ panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: pop from an empty queue")
+ }
+ r.full = false
+ t := r.ring[r.headPos]
+ r.ring[r.headPos] = *new(T)
+ r.headPos++
+ if r.headPos == len(r.ring) {
+ r.headPos = 0
+ }
+ return t
+}
+
+// PeekFront returns the next element.
+// It must not be called when the buffer is empty, that means that
+// callers might need to check if there are elements in the buffer first.
+func (r *RingBuffer[T]) PeekFront() T {
+ if r.Empty() {
+ panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: peek from an empty queue")
+ }
+ return r.ring[r.headPos]
+}
+
+// Grow the maximum size of the queue.
+// This method assume the queue is full.
+func (r *RingBuffer[T]) grow() {
+ oldRing := r.ring
+ newSize := len(oldRing) * 2
+ if newSize == 0 {
+ newSize = 1
+ }
+ r.ring = make([]T, newSize)
+ headLen := copy(r.ring, oldRing[r.headPos:])
+ copy(r.ring[headLen:], oldRing[:r.headPos])
+ r.headPos, r.tailPos, r.full = 0, len(oldRing), false
+}
+
+// Clear removes all elements.
+func (r *RingBuffer[T]) Clear() {
+ var zeroValue T
+ for i := range r.ring {
+ r.ring[i] = zeroValue
+ }
+ r.headPos, r.tailPos, r.full = 0, 0, false
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go b/vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
new file mode 100644
index 00000000..27531307
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
@@ -0,0 +1,159 @@
+package utils
+
+import (
+ "sync/atomic"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+const (
+ rttAlpha = 0.125
+ oneMinusAlpha = 1 - rttAlpha
+ rttBeta = 0.25
+ oneMinusBeta = 1 - rttBeta
+)
+
+// The default RTT used before an RTT sample is taken
+const DefaultInitialRTT = 100 * time.Millisecond
+
+// RTTStats provides round-trip statistics
+type RTTStats struct {
+ hasMeasurement bool
+
+ minRTT atomic.Int64 // nanoseconds
+ latestRTT atomic.Int64 // nanoseconds
+ smoothedRTT atomic.Int64 // nanoseconds
+ meanDeviation atomic.Int64 // nanoseconds
+
+ maxAckDelay atomic.Int64 // nanoseconds
+}
+
+func NewRTTStats() *RTTStats {
+ var rttStats RTTStats
+ rttStats.minRTT.Store(DefaultInitialRTT.Nanoseconds())
+ rttStats.latestRTT.Store(DefaultInitialRTT.Nanoseconds())
+ rttStats.smoothedRTT.Store(DefaultInitialRTT.Nanoseconds())
+ return &rttStats
+}
+
+// MinRTT Returns the minRTT for the entire connection.
+// May return Zero if no valid updates have occurred.
+func (r *RTTStats) MinRTT() time.Duration {
+ return time.Duration(r.minRTT.Load())
+}
+
+// LatestRTT returns the most recent rtt measurement.
+// May return Zero if no valid updates have occurred.
+func (r *RTTStats) LatestRTT() time.Duration {
+ return time.Duration(r.latestRTT.Load())
+}
+
+// SmoothedRTT returns the smoothed RTT for the connection.
+// May return Zero if no valid updates have occurred.
+func (r *RTTStats) SmoothedRTT() time.Duration {
+ return time.Duration(r.smoothedRTT.Load())
+}
+
+// MeanDeviation gets the mean deviation
+func (r *RTTStats) MeanDeviation() time.Duration {
+ return time.Duration(r.meanDeviation.Load())
+}
+
+// MaxAckDelay gets the max_ack_delay advertised by the peer
+func (r *RTTStats) MaxAckDelay() time.Duration {
+ return time.Duration(r.maxAckDelay.Load())
+}
+
+// PTO gets the probe timeout duration.
+func (r *RTTStats) PTO(includeMaxAckDelay bool) time.Duration {
+ if !r.hasMeasurement {
+ return 2 * DefaultInitialRTT
+ }
+ pto := r.SmoothedRTT() + max(4*r.MeanDeviation(), protocol.TimerGranularity)
+ if includeMaxAckDelay {
+ pto += r.MaxAckDelay()
+ }
+ return pto
+}
+
+// UpdateRTT updates the RTT based on a new sample.
+func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration) {
+ if sendDelta <= 0 {
+ return
+ }
+
+ // Update r.minRTT first. r.minRTT does not use an rttSample corrected for
+ // ackDelay but the raw observed sendDelta, since poor clock granularity at
+ // the client may cause a high ackDelay to result in underestimation of the
+ // r.minRTT.
+ minRTT := time.Duration(r.minRTT.Load())
+ if !r.hasMeasurement || minRTT > sendDelta {
+ minRTT = sendDelta
+ r.minRTT.Store(sendDelta.Nanoseconds())
+ }
+
+ // Correct for ackDelay if information received from the peer results in a
+ // an RTT sample at least as large as minRTT. Otherwise, only use the
+ // sendDelta.
+ sample := sendDelta
+ if sample-minRTT >= ackDelay {
+ sample -= ackDelay
+ }
+ r.latestRTT.Store(sample.Nanoseconds())
+ // First time call.
+ if !r.hasMeasurement {
+ r.hasMeasurement = true
+ r.smoothedRTT.Store(sample.Nanoseconds())
+ r.meanDeviation.Store(sample.Nanoseconds() / 2)
+ } else {
+ smoothedRTT := r.SmoothedRTT()
+ meanDev := time.Duration(oneMinusBeta*float32(r.MeanDeviation()/time.Microsecond)+rttBeta*float32((smoothedRTT-sample).Abs()/time.Microsecond)) * time.Microsecond
+ newSmoothedRTT := time.Duration((float32(smoothedRTT/time.Microsecond)*oneMinusAlpha)+(float32(sample/time.Microsecond)*rttAlpha)) * time.Microsecond
+ r.meanDeviation.Store(meanDev.Nanoseconds())
+ r.smoothedRTT.Store(newSmoothedRTT.Nanoseconds())
+ }
+}
+
+func (r *RTTStats) HasMeasurement() bool {
+ return r.hasMeasurement
+}
+
+// SetMaxAckDelay sets the max_ack_delay
+func (r *RTTStats) SetMaxAckDelay(mad time.Duration) {
+ r.maxAckDelay.Store(int64(mad))
+}
+
+// SetInitialRTT sets the initial RTT.
+// It is used during handshake when restoring the RTT stats from the token.
+func (r *RTTStats) SetInitialRTT(t time.Duration) {
+ // On the server side, by the time we get to process the session ticket,
+ // we might already have obtained an RTT measurement.
+ // This can happen if we received the ClientHello in multiple pieces, and one of those pieces was lost.
+ // Discard the restored value. A fresh measurement is always better.
+ if r.hasMeasurement {
+ return
+ }
+ r.smoothedRTT.Store(int64(t))
+ r.latestRTT.Store(int64(t))
+}
+
+func (r *RTTStats) ResetForPathMigration() {
+ r.hasMeasurement = false
+ r.minRTT.Store(DefaultInitialRTT.Nanoseconds())
+ r.latestRTT.Store(DefaultInitialRTT.Nanoseconds())
+ r.smoothedRTT.Store(DefaultInitialRTT.Nanoseconds())
+ r.meanDeviation.Store(0)
+ // max_ack_delay remains valid
+}
+
+func (r *RTTStats) Clone() *RTTStats {
+ out := &RTTStats{}
+ out.hasMeasurement = r.hasMeasurement
+ out.minRTT.Store(r.minRTT.Load())
+ out.latestRTT.Store(r.latestRTT.Load())
+ out.smoothedRTT.Store(r.smoothedRTT.Load())
+ out.meanDeviation.Store(r.meanDeviation.Load())
+ out.maxAckDelay.Store(r.maxAckDelay.Load())
+ return out
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
new file mode 100644
index 00000000..191e1530
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
@@ -0,0 +1,298 @@
+package wire
+
+import (
+ "errors"
+ "math"
+ "sort"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+var errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges")
+
+// An AckFrame is an ACK frame
+type AckFrame struct {
+ AckRanges []AckRange // has to be ordered. The highest ACK range goes first, the lowest ACK range goes last
+ DelayTime time.Duration
+
+ ECT0, ECT1, ECNCE uint64
+}
+
+// parseAckFrame reads an ACK frame
+func parseAckFrame(frame *AckFrame, b []byte, typ FrameType, ackDelayExponent uint8, _ protocol.Version) (int, error) {
+ startLen := len(b)
+ ecn := typ == FrameTypeAckECN
+
+ la, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ largestAcked := protocol.PacketNumber(la)
+ delay, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+
+ delayTime := time.Duration(delay*1< largestAcked {
+ return 0, errors.New("invalid first ACK range")
+ }
+ smallest := largestAcked - ackBlock
+ frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largestAcked})
+
+ // read all the other ACK ranges
+ for range numBlocks {
+ g, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ gap := protocol.PacketNumber(g)
+ if smallest < gap+2 {
+ return 0, errInvalidAckRanges
+ }
+ largest := smallest - gap - 2
+
+ ab, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ ackBlock := protocol.PacketNumber(ab)
+
+ if ackBlock > largest {
+ return 0, errInvalidAckRanges
+ }
+ smallest = largest - ackBlock
+ frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largest})
+ }
+
+ if !frame.validateAckRanges() {
+ return 0, errInvalidAckRanges
+ }
+
+ if ecn {
+ ect0, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ frame.ECT0 = ect0
+ ect1, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ frame.ECT1 = ect1
+ ecnce, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ frame.ECNCE = ecnce
+ }
+
+ return startLen - len(b), nil
+}
+
+// Append appends an ACK frame.
+func (f *AckFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0
+ if hasECN {
+ b = append(b, byte(FrameTypeAckECN))
+ } else {
+ b = append(b, byte(FrameTypeAck))
+ }
+ b = quicvarint.Append(b, uint64(f.LargestAcked()))
+ b = quicvarint.Append(b, encodeAckDelay(f.DelayTime))
+
+ numRanges := min(len(f.AckRanges), protocol.MaxNumAckRanges)
+ b = quicvarint.Append(b, uint64(numRanges-1))
+
+ // write the first range
+ _, firstRange := f.encodeAckRange(0)
+ b = quicvarint.Append(b, firstRange)
+
+ // write all the other range
+ for i := 1; i < numRanges; i++ {
+ gap, len := f.encodeAckRange(i)
+ b = quicvarint.Append(b, gap)
+ b = quicvarint.Append(b, len)
+ }
+
+ if hasECN {
+ b = quicvarint.Append(b, f.ECT0)
+ b = quicvarint.Append(b, f.ECT1)
+ b = quicvarint.Append(b, f.ECNCE)
+ }
+ return b, nil
+}
+
+// Length of a written frame
+func (f *AckFrame) Length(_ protocol.Version) protocol.ByteCount {
+ largestAcked := f.AckRanges[0].Largest
+
+ // The number of ACK ranges is limited to 64, which guarantees that the
+ // ACK Range Count value can be encoded in a single byte varint.
+ length := 1 + quicvarint.Len(uint64(largestAcked)) + quicvarint.Len(encodeAckDelay(f.DelayTime)) + 1
+
+ lowestInFirstRange := f.AckRanges[0].Smallest
+ length += quicvarint.Len(uint64(largestAcked - lowestInFirstRange))
+
+ for i := 1; i < min(len(f.AckRanges), protocol.MaxNumAckRanges); i++ {
+ gap, len := f.encodeAckRange(i)
+ length += quicvarint.Len(gap)
+ length += quicvarint.Len(len)
+ }
+ if f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0 {
+ length += quicvarint.Len(f.ECT0) + quicvarint.Len(f.ECT1) + quicvarint.Len(f.ECNCE)
+ }
+ return protocol.ByteCount(length)
+}
+
+// Truncate truncates the ACK frame to fit into maxSize,
+// and to at most 64 ACK ranges.
+// maxSize must be large enough to fit at least one ACK range.
+func (f *AckFrame) Truncate(maxSize protocol.ByteCount, _ protocol.Version) {
+ f.AckRanges = f.AckRanges[:f.numEncodableAckRanges(maxSize)]
+}
+
+// gets the number of ACK ranges that can be encoded
+// such that the resulting frame is smaller than maxSize
+func (f *AckFrame) numEncodableAckRanges(maxSize protocol.ByteCount) int {
+ // Fast path: Most ACK frames are relatively small, and we don't need to calculate the exact length.
+ // We just assume the worst case scenario: every varint is encoded to 8 bytes.
+ // If the result is still smaller than the maximum ACK frame size, the actual ACK frame will definitely fit.
+ length := 1 + 8 /* largest acked */ + 8 /* delay */ + 1 /* ack range count */ + 8 /* first range */
+ if f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0 {
+ length += 8 + 8 + 8
+ }
+ numRanges := min(len(f.AckRanges), protocol.MaxNumAckRanges)
+ length += 2 * 8 * (numRanges - 1)
+ if protocol.ByteCount(length) <= maxSize {
+ return numRanges
+ }
+
+ // Slow path: Calculate the exact length of the ACK frame.
+ length = 1 + quicvarint.Len(uint64(f.LargestAcked())) + quicvarint.Len(encodeAckDelay(f.DelayTime)) + 1
+ _, firstRange := f.encodeAckRange(0)
+ length += quicvarint.Len(firstRange)
+ if f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0 {
+ length += quicvarint.Len(f.ECT0) + quicvarint.Len(f.ECT1) + quicvarint.Len(f.ECNCE)
+ }
+ for i := 1; i < numRanges; i++ {
+ gap, l := f.encodeAckRange(i)
+ rangeLen := quicvarint.Len(gap) + quicvarint.Len(l)
+ if protocol.ByteCount(length+rangeLen) > maxSize {
+ // Writing range i would exceed the maximum size,
+ // so encode one range less than that.
+ return i
+ }
+ length += rangeLen
+ }
+ return numRanges
+}
+
+func (f *AckFrame) encodeAckRange(i int) (gap, length uint64) {
+ if i == 0 {
+ return 0, uint64(f.AckRanges[0].Largest - f.AckRanges[0].Smallest)
+ }
+ return uint64(f.AckRanges[i-1].Smallest - f.AckRanges[i].Largest - 2),
+ uint64(f.AckRanges[i].Largest - f.AckRanges[i].Smallest)
+}
+
+// HasMissingRanges returns if this frame reports any missing packets
+func (f *AckFrame) HasMissingRanges() bool {
+ return len(f.AckRanges) > 1
+}
+
+func (f *AckFrame) validateAckRanges() bool {
+ if len(f.AckRanges) == 0 {
+ return false
+ }
+
+ // check the validity of every single ACK range
+ for _, ackRange := range f.AckRanges {
+ if ackRange.Smallest > ackRange.Largest {
+ return false
+ }
+ }
+
+ // check the consistency for ACK with multiple ACK ranges
+ for i, ackRange := range f.AckRanges {
+ if i == 0 {
+ continue
+ }
+ lastAckRange := f.AckRanges[i-1]
+ if lastAckRange.Smallest <= ackRange.Smallest {
+ return false
+ }
+ if lastAckRange.Smallest <= ackRange.Largest+1 {
+ return false
+ }
+ }
+
+ return true
+}
+
+// LargestAcked is the largest acked packet number
+func (f *AckFrame) LargestAcked() protocol.PacketNumber {
+ return f.AckRanges[0].Largest
+}
+
+// LowestAcked is the lowest acked packet number
+func (f *AckFrame) LowestAcked() protocol.PacketNumber {
+ return f.AckRanges[len(f.AckRanges)-1].Smallest
+}
+
+// AcksPacket determines if this ACK frame acks a certain packet number
+func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool {
+ if p < f.LowestAcked() || p > f.LargestAcked() {
+ return false
+ }
+
+ i := sort.Search(len(f.AckRanges), func(i int) bool {
+ return p >= f.AckRanges[i].Smallest
+ })
+ // i will always be < len(f.AckRanges), since we checked above that p is not bigger than the largest acked
+ return p <= f.AckRanges[i].Largest
+}
+
+func (f *AckFrame) Reset() {
+ f.DelayTime = 0
+ f.ECT0 = 0
+ f.ECT1 = 0
+ f.ECNCE = 0
+ for _, r := range f.AckRanges {
+ r.Largest = 0
+ r.Smallest = 0
+ }
+ f.AckRanges = f.AckRanges[:0]
+}
+
+func encodeAckDelay(delay time.Duration) uint64 {
+ return uint64(delay.Nanoseconds() / (1000 * (1 << protocol.AckDelayExponent)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/ack_frequency_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/ack_frequency_frame.go
new file mode 100644
index 00000000..0735d70b
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/ack_frequency_frame.go
@@ -0,0 +1,65 @@
+package wire
+
+import (
+ "math"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+type AckFrequencyFrame struct {
+ SequenceNumber uint64
+ AckElicitingThreshold uint64
+ RequestMaxAckDelay time.Duration
+ ReorderingThreshold protocol.PacketNumber
+}
+
+func parseAckFrequencyFrame(b []byte, _ protocol.Version) (*AckFrequencyFrame, int, error) {
+ startLen := len(b)
+ seq, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ aeth, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ mad, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ // prevents overflows if the peer sends a very large value
+ maxAckDelay := time.Duration(mad) * time.Microsecond
+ if maxAckDelay < 0 {
+ maxAckDelay = math.MaxInt64
+ }
+ b = b[l:]
+ rth, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+
+ return &AckFrequencyFrame{
+ SequenceNumber: seq,
+ AckElicitingThreshold: aeth,
+ RequestMaxAckDelay: maxAckDelay,
+ ReorderingThreshold: protocol.PacketNumber(rth),
+ }, startLen - len(b), nil
+}
+
+func (f *AckFrequencyFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = quicvarint.Append(b, uint64(FrameTypeAckFrequency))
+ b = quicvarint.Append(b, f.SequenceNumber)
+ b = quicvarint.Append(b, f.AckElicitingThreshold)
+ b = quicvarint.Append(b, uint64(f.RequestMaxAckDelay/time.Microsecond))
+ return quicvarint.Append(b, uint64(f.ReorderingThreshold)), nil
+}
+
+func (f *AckFrequencyFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return protocol.ByteCount(2 + quicvarint.Len(f.SequenceNumber) + quicvarint.Len(f.AckElicitingThreshold) +
+ quicvarint.Len(uint64(f.RequestMaxAckDelay/time.Microsecond)) + quicvarint.Len(uint64(f.ReorderingThreshold)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/ack_range.go b/vendor/github.com/quic-go/quic-go/internal/wire/ack_range.go
new file mode 100644
index 00000000..03a1235e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/ack_range.go
@@ -0,0 +1,14 @@
+package wire
+
+import "github.com/quic-go/quic-go/internal/protocol"
+
+// AckRange is an ACK range
+type AckRange struct {
+ Smallest protocol.PacketNumber
+ Largest protocol.PacketNumber
+}
+
+// Len returns the number of packets contained in this ACK range
+func (r AckRange) Len() protocol.PacketNumber {
+ return r.Largest - r.Smallest + 1
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/connection_close_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/connection_close_frame.go
new file mode 100644
index 00000000..6c71aab6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/connection_close_frame.go
@@ -0,0 +1,75 @@
+package wire
+
+import (
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A ConnectionCloseFrame is a CONNECTION_CLOSE frame
+type ConnectionCloseFrame struct {
+ IsApplicationError bool
+ ErrorCode uint64
+ FrameType uint64
+ ReasonPhrase string
+}
+
+func parseConnectionCloseFrame(b []byte, typ FrameType, _ protocol.Version) (*ConnectionCloseFrame, int, error) {
+ startLen := len(b)
+ f := &ConnectionCloseFrame{IsApplicationError: typ == FrameTypeApplicationClose}
+ ec, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ f.ErrorCode = ec
+ // read the Frame Type, if this is not an application error
+ if !f.IsApplicationError {
+ ft, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ f.FrameType = ft
+ }
+ var reasonPhraseLen uint64
+ reasonPhraseLen, l, err = quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ if int(reasonPhraseLen) > len(b) {
+ return nil, 0, io.EOF
+ }
+
+ reasonPhrase := make([]byte, reasonPhraseLen)
+ copy(reasonPhrase, b)
+ f.ReasonPhrase = string(reasonPhrase)
+ return f, startLen - len(b) + int(reasonPhraseLen), nil
+}
+
+// Length of a written frame
+func (f *ConnectionCloseFrame) Length(protocol.Version) protocol.ByteCount {
+ length := 1 + protocol.ByteCount(quicvarint.Len(f.ErrorCode)+quicvarint.Len(uint64(len(f.ReasonPhrase)))) + protocol.ByteCount(len(f.ReasonPhrase))
+ if !f.IsApplicationError {
+ length += protocol.ByteCount(quicvarint.Len(f.FrameType)) // for the frame type
+ }
+ return length
+}
+
+func (f *ConnectionCloseFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ if f.IsApplicationError {
+ b = append(b, byte(FrameTypeApplicationClose))
+ } else {
+ b = append(b, byte(FrameTypeConnectionClose))
+ }
+
+ b = quicvarint.Append(b, f.ErrorCode)
+ if !f.IsApplicationError {
+ b = quicvarint.Append(b, f.FrameType)
+ }
+ b = quicvarint.Append(b, uint64(len(f.ReasonPhrase)))
+ b = append(b, []byte(f.ReasonPhrase)...)
+ return b, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/crypto_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/crypto_frame.go
new file mode 100644
index 00000000..60a713f7
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/crypto_frame.go
@@ -0,0 +1,97 @@
+package wire
+
+import (
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A CryptoFrame is a CRYPTO frame
+type CryptoFrame struct {
+ Offset protocol.ByteCount
+ Data []byte
+}
+
+func parseCryptoFrame(b []byte, _ protocol.Version) (*CryptoFrame, int, error) {
+ startLen := len(b)
+ frame := &CryptoFrame{}
+ offset, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ frame.Offset = protocol.ByteCount(offset)
+ dataLen, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ if dataLen > uint64(len(b)) {
+ return nil, 0, io.EOF
+ }
+ if dataLen != 0 {
+ frame.Data = make([]byte, dataLen)
+ copy(frame.Data, b)
+ }
+ return frame, startLen - len(b) + int(dataLen), nil
+}
+
+func (f *CryptoFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeCrypto))
+ b = quicvarint.Append(b, uint64(f.Offset))
+ b = quicvarint.Append(b, uint64(len(f.Data)))
+ b = append(b, f.Data...)
+ return b, nil
+}
+
+// Length of a written frame
+func (f *CryptoFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return protocol.ByteCount(1 + quicvarint.Len(uint64(f.Offset)) + quicvarint.Len(uint64(len(f.Data))) + len(f.Data))
+}
+
+// MaxDataLen returns the maximum data length
+func (f *CryptoFrame) MaxDataLen(maxSize protocol.ByteCount) protocol.ByteCount {
+ // pretend that the data size will be 1 bytes
+ // if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards
+ headerLen := protocol.ByteCount(1 + quicvarint.Len(uint64(f.Offset)) + 1)
+ if headerLen > maxSize {
+ return 0
+ }
+ maxDataLen := maxSize - headerLen
+ if quicvarint.Len(uint64(maxDataLen)) != 1 {
+ maxDataLen--
+ }
+ return maxDataLen
+}
+
+// MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes.
+// It returns if the frame was actually split.
+// The frame might not be split if:
+// * the size is large enough to fit the whole frame
+// * the size is too small to fit even a 1-byte frame. In that case, the frame returned is nil.
+func (f *CryptoFrame) MaybeSplitOffFrame(maxSize protocol.ByteCount, version protocol.Version) (*CryptoFrame, bool /* was splitting required */) {
+ if f.Length(version) <= maxSize {
+ return nil, false
+ }
+
+ n := f.MaxDataLen(maxSize)
+ if n == 0 {
+ return nil, true
+ }
+
+ newLen := protocol.ByteCount(len(f.Data)) - n
+
+ new := &CryptoFrame{}
+ new.Offset = f.Offset
+ new.Data = make([]byte, newLen)
+
+ // swap the data slices
+ new.Data, f.Data = f.Data, new.Data
+
+ copy(f.Data, new.Data[n:])
+ new.Data = new.Data[:n]
+ f.Offset += n
+
+ return new, true
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/data_blocked_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/data_blocked_frame.go
new file mode 100644
index 00000000..11c72ea3
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/data_blocked_frame.go
@@ -0,0 +1,29 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A DataBlockedFrame is a DATA_BLOCKED frame
+type DataBlockedFrame struct {
+ MaximumData protocol.ByteCount
+}
+
+func parseDataBlockedFrame(b []byte, _ protocol.Version) (*DataBlockedFrame, int, error) {
+ offset, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ return &DataBlockedFrame{MaximumData: protocol.ByteCount(offset)}, l, nil
+}
+
+func (f *DataBlockedFrame) Append(b []byte, version protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeDataBlocked))
+ return quicvarint.Append(b, uint64(f.MaximumData)), nil
+}
+
+// Length of a written frame
+func (f *DataBlockedFrame) Length(version protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.MaximumData)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go
new file mode 100644
index 00000000..a6034867
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go
@@ -0,0 +1,85 @@
+package wire
+
+import (
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// MaxDatagramSize is the maximum size of a DATAGRAM frame (RFC 9221).
+// By setting it to a large value, we allow all datagrams that fit into a QUIC packet.
+// The value is chosen such that it can still be encoded as a 2 byte varint.
+// This is a var and not a const so it can be set in tests.
+var MaxDatagramSize protocol.ByteCount = 16383
+
+// A DatagramFrame is a DATAGRAM frame
+type DatagramFrame struct {
+ DataLenPresent bool
+ Data []byte
+}
+
+func parseDatagramFrame(b []byte, typ FrameType, _ protocol.Version) (*DatagramFrame, int, error) {
+ startLen := len(b)
+ f := &DatagramFrame{}
+ f.DataLenPresent = uint64(typ)&0x1 > 0
+
+ var length uint64
+ if f.DataLenPresent {
+ var err error
+ var l int
+ length, l, err = quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ if length > uint64(len(b)) {
+ return nil, 0, io.EOF
+ }
+ } else {
+ length = uint64(len(b))
+ }
+ f.Data = make([]byte, length)
+ copy(f.Data, b)
+ return f, startLen - len(b) + int(length), nil
+}
+
+func (f *DatagramFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ typ := uint8(0x30)
+ if f.DataLenPresent {
+ typ ^= 0b1
+ }
+ b = append(b, typ)
+ if f.DataLenPresent {
+ b = quicvarint.Append(b, uint64(len(f.Data)))
+ }
+ b = append(b, f.Data...)
+ return b, nil
+}
+
+// MaxDataLen returns the maximum data length
+func (f *DatagramFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.Version) protocol.ByteCount {
+ headerLen := protocol.ByteCount(1)
+ if f.DataLenPresent {
+ // pretend that the data size will be 1 bytes
+ // if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards
+ headerLen++
+ }
+ if headerLen > maxSize {
+ return 0
+ }
+ maxDataLen := maxSize - headerLen
+ if f.DataLenPresent && quicvarint.Len(uint64(maxDataLen)) != 1 {
+ maxDataLen--
+ }
+ return maxDataLen
+}
+
+// Length of a written frame
+func (f *DatagramFrame) Length(_ protocol.Version) protocol.ByteCount {
+ length := 1 + protocol.ByteCount(len(f.Data))
+ if f.DataLenPresent {
+ length += protocol.ByteCount(quicvarint.Len(uint64(len(f.Data))))
+ }
+ return length
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go b/vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go
new file mode 100644
index 00000000..6ab9fb98
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/extended_header.go
@@ -0,0 +1,164 @@
+package wire
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// ErrInvalidReservedBits is returned when the reserved bits are incorrect.
+// When this error is returned, parsing continues, and an ExtendedHeader is returned.
+// This is necessary because we need to decrypt the packet in that case,
+// in order to avoid a timing side-channel.
+var ErrInvalidReservedBits = errors.New("invalid reserved bits")
+
+// ExtendedHeader is the header of a QUIC packet.
+type ExtendedHeader struct {
+ Header
+
+ typeByte byte
+
+ KeyPhase protocol.KeyPhaseBit
+
+ PacketNumberLen protocol.PacketNumberLen
+ PacketNumber protocol.PacketNumber
+
+ parsedLen protocol.ByteCount
+}
+
+func (h *ExtendedHeader) parse(data []byte) (bool /* reserved bits valid */, error) {
+ // read the (now unencrypted) first byte
+ h.typeByte = data[0]
+ h.PacketNumberLen = protocol.PacketNumberLen(h.typeByte&0x3) + 1
+ if protocol.ByteCount(len(data)) < h.Header.ParsedLen()+protocol.ByteCount(h.PacketNumberLen) {
+ return false, io.EOF
+ }
+
+ pn, err := readPacketNumber(data[h.Header.ParsedLen():], h.PacketNumberLen)
+ if err != nil {
+ return true, nil
+ }
+ h.PacketNumber = pn
+ reservedBitsValid := h.typeByte&0xc == 0
+
+ h.parsedLen = h.Header.ParsedLen() + protocol.ByteCount(h.PacketNumberLen)
+ return reservedBitsValid, err
+}
+
+// Append appends the Header.
+func (h *ExtendedHeader) Append(b []byte, v protocol.Version) ([]byte, error) {
+ if h.DestConnectionID.Len() > protocol.MaxConnIDLen {
+ return nil, fmt.Errorf("invalid connection ID length: %d bytes", h.DestConnectionID.Len())
+ }
+ if h.SrcConnectionID.Len() > protocol.MaxConnIDLen {
+ return nil, fmt.Errorf("invalid connection ID length: %d bytes", h.SrcConnectionID.Len())
+ }
+
+ var packetType uint8
+ if v == protocol.Version2 {
+ switch h.Type {
+ case protocol.PacketTypeInitial:
+ packetType = 0b01
+ case protocol.PacketType0RTT:
+ packetType = 0b10
+ case protocol.PacketTypeHandshake:
+ packetType = 0b11
+ case protocol.PacketTypeRetry:
+ packetType = 0b00
+ }
+ } else {
+ switch h.Type {
+ case protocol.PacketTypeInitial:
+ packetType = 0b00
+ case protocol.PacketType0RTT:
+ packetType = 0b01
+ case protocol.PacketTypeHandshake:
+ packetType = 0b10
+ case protocol.PacketTypeRetry:
+ packetType = 0b11
+ }
+ }
+ firstByte := 0xc0 | packetType<<4
+ if h.Type != protocol.PacketTypeRetry {
+ // Retry packets don't have a packet number
+ firstByte |= uint8(h.PacketNumberLen - 1)
+ }
+
+ b = append(b, firstByte)
+ b = append(b, make([]byte, 4)...)
+ binary.BigEndian.PutUint32(b[len(b)-4:], uint32(h.Version))
+ b = append(b, uint8(h.DestConnectionID.Len()))
+ b = append(b, h.DestConnectionID.Bytes()...)
+ b = append(b, uint8(h.SrcConnectionID.Len()))
+ b = append(b, h.SrcConnectionID.Bytes()...)
+
+ //nolint:exhaustive
+ switch h.Type {
+ case protocol.PacketTypeRetry:
+ b = append(b, h.Token...)
+ return b, nil
+ case protocol.PacketTypeInitial:
+ b = quicvarint.Append(b, uint64(len(h.Token)))
+ b = append(b, h.Token...)
+ }
+ b = quicvarint.AppendWithLen(b, uint64(h.Length), 2)
+ return appendPacketNumber(b, h.PacketNumber, h.PacketNumberLen)
+}
+
+// ParsedLen returns the number of bytes that were consumed when parsing the header
+func (h *ExtendedHeader) ParsedLen() protocol.ByteCount {
+ return h.parsedLen
+}
+
+// GetLength determines the length of the Header.
+func (h *ExtendedHeader) GetLength(_ protocol.Version) protocol.ByteCount {
+ length := 1 /* type byte */ + 4 /* version */ + 1 /* dest conn ID len */ + protocol.ByteCount(h.DestConnectionID.Len()) + 1 /* src conn ID len */ + protocol.ByteCount(h.SrcConnectionID.Len()) + protocol.ByteCount(h.PacketNumberLen) + 2 /* length */
+ if h.Type == protocol.PacketTypeInitial {
+ length += protocol.ByteCount(quicvarint.Len(uint64(len(h.Token))) + len(h.Token))
+ }
+ return length
+}
+
+// Log logs the Header
+func (h *ExtendedHeader) Log(logger utils.Logger) {
+ var token string
+ if h.Type == protocol.PacketTypeInitial || h.Type == protocol.PacketTypeRetry {
+ if len(h.Token) == 0 {
+ token = "Token: (empty), "
+ } else {
+ token = fmt.Sprintf("Token: %#x, ", h.Token)
+ }
+ if h.Type == protocol.PacketTypeRetry {
+ logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sVersion: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.Version)
+ return
+ }
+ }
+ logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %d, PacketNumberLen: %d, Length: %d, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.PacketNumber, h.PacketNumberLen, h.Length, h.Version)
+}
+
+func appendPacketNumber(b []byte, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen) ([]byte, error) {
+ switch pnLen {
+ case protocol.PacketNumberLen1:
+ b = append(b, uint8(pn))
+ case protocol.PacketNumberLen2:
+ buf := make([]byte, 2)
+ binary.BigEndian.PutUint16(buf, uint16(pn))
+ b = append(b, buf...)
+ case protocol.PacketNumberLen3:
+ buf := make([]byte, 4)
+ binary.BigEndian.PutUint32(buf, uint32(pn))
+ b = append(b, buf[1:]...)
+ case protocol.PacketNumberLen4:
+ buf := make([]byte, 4)
+ binary.BigEndian.PutUint32(buf, uint32(pn))
+ b = append(b, buf...)
+ default:
+ return nil, fmt.Errorf("invalid packet number length: %d", pnLen)
+ }
+ return b, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/frame.go
new file mode 100644
index 00000000..09ea92f7
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/frame.go
@@ -0,0 +1,33 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// A Frame in QUIC
+type Frame interface {
+ Append(b []byte, version protocol.Version) ([]byte, error)
+ Length(version protocol.Version) protocol.ByteCount
+}
+
+// IsProbingFrame returns true if the frame is a probing frame.
+// See section 9.1 of RFC 9000.
+func IsProbingFrame(f Frame) bool {
+ switch f.(type) {
+ case *PathChallengeFrame, *PathResponseFrame, *NewConnectionIDFrame:
+ return true
+ }
+ return false
+}
+
+// IsProbingFrameType returns true if the FrameType is a probing frame.
+// See section 9.1 of RFC 9000.
+func IsProbingFrameType(f FrameType) bool {
+ //nolint:exhaustive // PATH_CHALLENGE, PATH_RESPONSE and NEW_CONNECTION_ID are the only probing frames
+ switch f {
+ case FrameTypePathChallenge, FrameTypePathResponse, FrameTypeNewConnectionID:
+ return true
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go b/vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go
new file mode 100644
index 00000000..afc3bedb
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go
@@ -0,0 +1,192 @@
+package wire
+
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+var errUnknownFrameType = errors.New("unknown frame type")
+
+// The FrameParser parses QUIC frames, one by one.
+type FrameParser struct {
+ ackDelayExponent uint8
+ supportsDatagrams bool
+ supportsResetStreamAt bool
+ supportsAckFrequency bool
+
+ // To avoid allocating when parsing, keep a single ACK frame struct.
+ // It is used over and over again.
+ ackFrame *AckFrame
+}
+
+// NewFrameParser creates a new frame parser.
+func NewFrameParser(supportsDatagrams, supportsResetStreamAt, supportsAckFrequency bool) *FrameParser {
+ return &FrameParser{
+ supportsDatagrams: supportsDatagrams,
+ supportsResetStreamAt: supportsResetStreamAt,
+ supportsAckFrequency: supportsAckFrequency,
+ ackFrame: &AckFrame{},
+ }
+}
+
+// ParseType parses the frame type of the next frame.
+// It skips over PADDING frames.
+func (p *FrameParser) ParseType(b []byte, encLevel protocol.EncryptionLevel) (FrameType, int, error) {
+ var parsed int
+ for len(b) != 0 {
+ typ, l, err := quicvarint.Parse(b)
+ parsed += l
+ if err != nil {
+ return 0, parsed, &qerr.TransportError{
+ ErrorCode: qerr.FrameEncodingError,
+ ErrorMessage: err.Error(),
+ }
+ }
+ b = b[l:]
+ if typ == 0x0 { // skip PADDING frames
+ continue
+ }
+ ft := FrameType(typ)
+ valid := ft.isValidRFC9000() ||
+ (p.supportsDatagrams && ft.IsDatagramFrameType()) ||
+ (p.supportsResetStreamAt && ft == FrameTypeResetStreamAt) ||
+ (p.supportsAckFrequency && (ft == FrameTypeAckFrequency || ft == FrameTypeImmediateAck))
+ if !valid {
+ return 0, parsed, &qerr.TransportError{
+ ErrorCode: qerr.FrameEncodingError,
+ FrameType: typ,
+ ErrorMessage: errUnknownFrameType.Error(),
+ }
+ }
+ if !ft.isAllowedAtEncLevel(encLevel) {
+ return 0, parsed, &qerr.TransportError{
+ ErrorCode: qerr.FrameEncodingError,
+ FrameType: typ,
+ ErrorMessage: fmt.Sprintf("%d not allowed at encryption level %s", ft, encLevel),
+ }
+ }
+ return ft, parsed, nil
+ }
+ return 0, parsed, io.EOF
+}
+
+func (p *FrameParser) ParseStreamFrame(frameType FrameType, data []byte, v protocol.Version) (*StreamFrame, int, error) {
+ frame, n, err := ParseStreamFrame(data, frameType, v)
+ if err != nil {
+ return nil, n, &qerr.TransportError{
+ ErrorCode: qerr.FrameEncodingError,
+ FrameType: uint64(frameType),
+ ErrorMessage: err.Error(),
+ }
+ }
+ return frame, n, nil
+}
+
+func (p *FrameParser) ParseAckFrame(frameType FrameType, data []byte, encLevel protocol.EncryptionLevel, v protocol.Version) (*AckFrame, int, error) {
+ ackDelayExponent := p.ackDelayExponent
+ if encLevel != protocol.Encryption1RTT {
+ ackDelayExponent = protocol.DefaultAckDelayExponent
+ }
+ p.ackFrame.Reset()
+ l, err := parseAckFrame(p.ackFrame, data, frameType, ackDelayExponent, v)
+ if err != nil {
+ return nil, l, &qerr.TransportError{
+ ErrorCode: qerr.FrameEncodingError,
+ FrameType: uint64(frameType),
+ ErrorMessage: err.Error(),
+ }
+ }
+
+ return p.ackFrame, l, nil
+}
+
+func (p *FrameParser) ParseDatagramFrame(frameType FrameType, data []byte, v protocol.Version) (*DatagramFrame, int, error) {
+ f, l, err := parseDatagramFrame(data, frameType, v)
+ if err != nil {
+ return nil, 0, &qerr.TransportError{
+ ErrorCode: qerr.FrameEncodingError,
+ FrameType: uint64(frameType),
+ ErrorMessage: err.Error(),
+ }
+ }
+ return f, l, nil
+}
+
+// ParseLessCommonFrame parses everything except STREAM, ACK or DATAGRAM.
+// These cases should be handled separately for performance reasons.
+func (p *FrameParser) ParseLessCommonFrame(frameType FrameType, data []byte, v protocol.Version) (Frame, int, error) {
+ var frame Frame
+ var l int
+ var err error
+ //nolint:exhaustive // Common frames should already be handled.
+ switch frameType {
+ case FrameTypePing:
+ frame = &PingFrame{}
+ case FrameTypeResetStream:
+ frame, l, err = parseResetStreamFrame(data, false, v)
+ case FrameTypeStopSending:
+ frame, l, err = parseStopSendingFrame(data, v)
+ case FrameTypeCrypto:
+ frame, l, err = parseCryptoFrame(data, v)
+ case FrameTypeNewToken:
+ frame, l, err = parseNewTokenFrame(data, v)
+ case FrameTypeMaxData:
+ frame, l, err = parseMaxDataFrame(data, v)
+ case FrameTypeMaxStreamData:
+ frame, l, err = parseMaxStreamDataFrame(data, v)
+ case FrameTypeBidiMaxStreams, FrameTypeUniMaxStreams:
+ frame, l, err = parseMaxStreamsFrame(data, frameType, v)
+ case FrameTypeDataBlocked:
+ frame, l, err = parseDataBlockedFrame(data, v)
+ case FrameTypeStreamDataBlocked:
+ frame, l, err = parseStreamDataBlockedFrame(data, v)
+ case FrameTypeBidiStreamBlocked, FrameTypeUniStreamBlocked:
+ frame, l, err = parseStreamsBlockedFrame(data, frameType, v)
+ case FrameTypeNewConnectionID:
+ frame, l, err = parseNewConnectionIDFrame(data, v)
+ case FrameTypeRetireConnectionID:
+ frame, l, err = parseRetireConnectionIDFrame(data, v)
+ case FrameTypePathChallenge:
+ frame, l, err = parsePathChallengeFrame(data, v)
+ case FrameTypePathResponse:
+ frame, l, err = parsePathResponseFrame(data, v)
+ case FrameTypeConnectionClose, FrameTypeApplicationClose:
+ frame, l, err = parseConnectionCloseFrame(data, frameType, v)
+ case FrameTypeHandshakeDone:
+ frame = &HandshakeDoneFrame{}
+ case FrameTypeResetStreamAt:
+ frame, l, err = parseResetStreamFrame(data, true, v)
+ case FrameTypeAckFrequency:
+ frame, l, err = parseAckFrequencyFrame(data, v)
+ case FrameTypeImmediateAck:
+ frame = &ImmediateAckFrame{}
+ default:
+ err = errUnknownFrameType
+ }
+ if err != nil {
+ return frame, l, &qerr.TransportError{
+ ErrorCode: qerr.FrameEncodingError,
+ FrameType: uint64(frameType),
+ ErrorMessage: err.Error(),
+ }
+ }
+ return frame, l, err
+}
+
+// SetAckDelayExponent sets the acknowledgment delay exponent (sent in the transport parameters).
+// This value is used to scale the ACK Delay field in the ACK frame.
+func (p *FrameParser) SetAckDelayExponent(exp uint8) {
+ p.ackDelayExponent = exp
+}
+
+func replaceUnexpectedEOF(e error) error {
+ if e == io.ErrUnexpectedEOF {
+ return io.EOF
+ }
+ return e
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/frame_type.go b/vendor/github.com/quic-go/quic-go/internal/wire/frame_type.go
new file mode 100644
index 00000000..d3d086d9
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/frame_type.go
@@ -0,0 +1,81 @@
+package wire
+
+import "github.com/quic-go/quic-go/internal/protocol"
+
+type FrameType uint64
+
+// These constants correspond to those defined in RFC 9000.
+// Stream frame types are not listed explicitly here; use FrameType.IsStreamFrameType() to identify them.
+const (
+ FrameTypePing FrameType = 0x1
+ FrameTypeAck FrameType = 0x2
+ FrameTypeAckECN FrameType = 0x3
+ FrameTypeResetStream FrameType = 0x4
+ FrameTypeStopSending FrameType = 0x5
+ FrameTypeCrypto FrameType = 0x6
+ FrameTypeNewToken FrameType = 0x7
+
+ FrameTypeMaxData FrameType = 0x10
+ FrameTypeMaxStreamData FrameType = 0x11
+ FrameTypeBidiMaxStreams FrameType = 0x12
+ FrameTypeUniMaxStreams FrameType = 0x13
+ FrameTypeDataBlocked FrameType = 0x14
+ FrameTypeStreamDataBlocked FrameType = 0x15
+ FrameTypeBidiStreamBlocked FrameType = 0x16
+ FrameTypeUniStreamBlocked FrameType = 0x17
+ FrameTypeNewConnectionID FrameType = 0x18
+ FrameTypeRetireConnectionID FrameType = 0x19
+ FrameTypePathChallenge FrameType = 0x1a
+ FrameTypePathResponse FrameType = 0x1b
+ FrameTypeConnectionClose FrameType = 0x1c
+ FrameTypeApplicationClose FrameType = 0x1d
+ FrameTypeHandshakeDone FrameType = 0x1e
+ // https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/07/
+ FrameTypeResetStreamAt FrameType = 0x24
+ // https://datatracker.ietf.org/doc/draft-ietf-quic-ack-frequency/11/
+ FrameTypeAckFrequency FrameType = 0xaf
+ FrameTypeImmediateAck FrameType = 0x1f
+
+ FrameTypeDatagramNoLength FrameType = 0x30
+ FrameTypeDatagramWithLength FrameType = 0x31
+)
+
+func (t FrameType) IsStreamFrameType() bool {
+ return t >= 0x8 && t <= 0xf
+}
+
+func (t FrameType) isValidRFC9000() bool {
+ return t <= 0x1e
+}
+
+func (t FrameType) IsAckFrameType() bool {
+ return t == FrameTypeAck || t == FrameTypeAckECN
+}
+
+func (t FrameType) IsDatagramFrameType() bool {
+ return t == FrameTypeDatagramNoLength || t == FrameTypeDatagramWithLength
+}
+
+func (t FrameType) isAllowedAtEncLevel(encLevel protocol.EncryptionLevel) bool {
+ //nolint:exhaustive
+ switch encLevel {
+ case protocol.EncryptionInitial, protocol.EncryptionHandshake:
+ switch t {
+ case FrameTypeCrypto, FrameTypeAck, FrameTypeAckECN, FrameTypeConnectionClose, FrameTypePing:
+ return true
+ default:
+ return false
+ }
+ case protocol.Encryption0RTT:
+ switch t {
+ case FrameTypeCrypto, FrameTypeAck, FrameTypeAckECN, FrameTypeConnectionClose, FrameTypeNewToken, FrameTypePathResponse, FrameTypeRetireConnectionID:
+ return false
+ default:
+ return true
+ }
+ case protocol.Encryption1RTT:
+ return true
+ default:
+ panic("unknown encryption level")
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/handshake_done_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/handshake_done_frame.go
new file mode 100644
index 00000000..bf95f525
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/handshake_done_frame.go
@@ -0,0 +1,17 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// A HandshakeDoneFrame is a HANDSHAKE_DONE frame
+type HandshakeDoneFrame struct{}
+
+func (f *HandshakeDoneFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ return append(b, byte(FrameTypeHandshakeDone)), nil
+}
+
+// Length of a written frame
+func (f *HandshakeDoneFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return 1
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/header.go b/vendor/github.com/quic-go/quic-go/internal/wire/header.go
new file mode 100644
index 00000000..678a04a2
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/header.go
@@ -0,0 +1,302 @@
+package wire
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// ParseConnectionID parses the destination connection ID of a packet.
+func ParseConnectionID(data []byte, shortHeaderConnIDLen int) (protocol.ConnectionID, error) {
+ if len(data) == 0 {
+ return protocol.ConnectionID{}, io.EOF
+ }
+ if !IsLongHeaderPacket(data[0]) {
+ if len(data) < shortHeaderConnIDLen+1 {
+ return protocol.ConnectionID{}, io.EOF
+ }
+ return protocol.ParseConnectionID(data[1 : 1+shortHeaderConnIDLen]), nil
+ }
+ if len(data) < 6 {
+ return protocol.ConnectionID{}, io.EOF
+ }
+ destConnIDLen := int(data[5])
+ if destConnIDLen > protocol.MaxConnIDLen {
+ return protocol.ConnectionID{}, protocol.ErrInvalidConnectionIDLen
+ }
+ if len(data) < 6+destConnIDLen {
+ return protocol.ConnectionID{}, io.EOF
+ }
+ return protocol.ParseConnectionID(data[6 : 6+destConnIDLen]), nil
+}
+
+// ParseArbitraryLenConnectionIDs parses the most general form of a Long Header packet,
+// using only the version-independent packet format as described in Section 5.1 of RFC 8999:
+// https://datatracker.ietf.org/doc/html/rfc8999#section-5.1.
+// This function should only be called on Long Header packets for which we don't support the version.
+func ParseArbitraryLenConnectionIDs(data []byte) (bytesParsed int, dest, src protocol.ArbitraryLenConnectionID, _ error) {
+ startLen := len(data)
+ if len(data) < 6 {
+ return 0, nil, nil, io.EOF
+ }
+ data = data[5:] // skip first byte and version field
+ destConnIDLen := data[0]
+ data = data[1:]
+ destConnID := make(protocol.ArbitraryLenConnectionID, destConnIDLen)
+ if len(data) < int(destConnIDLen)+1 {
+ return 0, nil, nil, io.EOF
+ }
+ copy(destConnID, data)
+ data = data[destConnIDLen:]
+ srcConnIDLen := data[0]
+ data = data[1:]
+ if len(data) < int(srcConnIDLen) {
+ return 0, nil, nil, io.EOF
+ }
+ srcConnID := make(protocol.ArbitraryLenConnectionID, srcConnIDLen)
+ copy(srcConnID, data)
+ return startLen - len(data) + int(srcConnIDLen), destConnID, srcConnID, nil
+}
+
+func IsPotentialQUICPacket(firstByte byte) bool {
+ return firstByte&0x40 > 0
+}
+
+// IsLongHeaderPacket says if this is a Long Header packet
+func IsLongHeaderPacket(firstByte byte) bool {
+ return firstByte&0x80 > 0
+}
+
+// ParseVersion parses the QUIC version.
+// It should only be called for Long Header packets (Short Header packets don't contain a version number).
+func ParseVersion(data []byte) (protocol.Version, error) {
+ if len(data) < 5 {
+ return 0, io.EOF
+ }
+ return protocol.Version(binary.BigEndian.Uint32(data[1:5])), nil
+}
+
+// IsVersionNegotiationPacket says if this is a version negotiation packet
+func IsVersionNegotiationPacket(b []byte) bool {
+ if len(b) < 5 {
+ return false
+ }
+ return IsLongHeaderPacket(b[0]) && b[1] == 0 && b[2] == 0 && b[3] == 0 && b[4] == 0
+}
+
+// Is0RTTPacket says if this is a 0-RTT packet.
+// A packet sent with a version we don't understand can never be a 0-RTT packet.
+func Is0RTTPacket(b []byte) bool {
+ if len(b) < 5 {
+ return false
+ }
+ if !IsLongHeaderPacket(b[0]) {
+ return false
+ }
+ version := protocol.Version(binary.BigEndian.Uint32(b[1:5]))
+ //nolint:exhaustive // We only need to test QUIC versions that we support.
+ switch version {
+ case protocol.Version1:
+ return b[0]>>4&0b11 == 0b01
+ case protocol.Version2:
+ return b[0]>>4&0b11 == 0b10
+ default:
+ return false
+ }
+}
+
+var ErrUnsupportedVersion = errors.New("unsupported version")
+
+// The Header is the version independent part of the header
+type Header struct {
+ typeByte byte
+ Type protocol.PacketType
+
+ Version protocol.Version
+ SrcConnectionID protocol.ConnectionID
+ DestConnectionID protocol.ConnectionID
+
+ Length protocol.ByteCount
+
+ Token []byte
+
+ parsedLen protocol.ByteCount // how many bytes were read while parsing this header
+}
+
+// ParsePacket parses a long header packet.
+// The packet is cut according to the length field.
+// If we understand the version, the packet is parsed up unto the packet number.
+// Otherwise, only the invariant part of the header is parsed.
+func ParsePacket(data []byte) (*Header, []byte, []byte, error) {
+ if len(data) == 0 || !IsLongHeaderPacket(data[0]) {
+ return nil, nil, nil, errors.New("not a long header packet")
+ }
+ hdr, err := parseHeader(data)
+ if err != nil {
+ if errors.Is(err, ErrUnsupportedVersion) {
+ return hdr, nil, nil, err
+ }
+ return nil, nil, nil, err
+ }
+ if protocol.ByteCount(len(data)) < hdr.ParsedLen()+hdr.Length {
+ return nil, nil, nil, fmt.Errorf("packet length (%d bytes) is smaller than the expected length (%d bytes)", len(data)-int(hdr.ParsedLen()), hdr.Length)
+ }
+ packetLen := int(hdr.ParsedLen() + hdr.Length)
+ return hdr, data[:packetLen], data[packetLen:], nil
+}
+
+// ParseHeader parses the header:
+// * if we understand the version: up to the packet number
+// * if not, only the invariant part of the header
+func parseHeader(b []byte) (*Header, error) {
+ if len(b) == 0 {
+ return nil, io.EOF
+ }
+ typeByte := b[0]
+
+ h := &Header{typeByte: typeByte}
+ l, err := h.parseLongHeader(b[1:])
+ h.parsedLen = protocol.ByteCount(l) + 1
+ return h, err
+}
+
+func (h *Header) parseLongHeader(b []byte) (int, error) {
+ startLen := len(b)
+ if len(b) < 5 {
+ return 0, io.EOF
+ }
+ h.Version = protocol.Version(binary.BigEndian.Uint32(b[:4]))
+ if h.Version != 0 && h.typeByte&0x40 == 0 {
+ return startLen - len(b), errors.New("not a QUIC packet")
+ }
+ destConnIDLen := int(b[4])
+ if destConnIDLen > protocol.MaxConnIDLen {
+ return startLen - len(b), protocol.ErrInvalidConnectionIDLen
+ }
+ b = b[5:]
+ if len(b) < destConnIDLen+1 {
+ return startLen - len(b), io.EOF
+ }
+ h.DestConnectionID = protocol.ParseConnectionID(b[:destConnIDLen])
+ srcConnIDLen := int(b[destConnIDLen])
+ if srcConnIDLen > protocol.MaxConnIDLen {
+ return startLen - len(b), protocol.ErrInvalidConnectionIDLen
+ }
+ b = b[destConnIDLen+1:]
+ if len(b) < srcConnIDLen {
+ return startLen - len(b), io.EOF
+ }
+ h.SrcConnectionID = protocol.ParseConnectionID(b[:srcConnIDLen])
+ b = b[srcConnIDLen:]
+ if h.Version == 0 { // version negotiation packet
+ return startLen - len(b), nil
+ }
+ // If we don't understand the version, we have no idea how to interpret the rest of the bytes
+ if !protocol.IsSupportedVersion(protocol.SupportedVersions, h.Version) {
+ return startLen - len(b), ErrUnsupportedVersion
+ }
+
+ if h.Version == protocol.Version2 {
+ switch h.typeByte >> 4 & 0b11 {
+ case 0b00:
+ h.Type = protocol.PacketTypeRetry
+ case 0b01:
+ h.Type = protocol.PacketTypeInitial
+ case 0b10:
+ h.Type = protocol.PacketType0RTT
+ case 0b11:
+ h.Type = protocol.PacketTypeHandshake
+ }
+ } else {
+ switch h.typeByte >> 4 & 0b11 {
+ case 0b00:
+ h.Type = protocol.PacketTypeInitial
+ case 0b01:
+ h.Type = protocol.PacketType0RTT
+ case 0b10:
+ h.Type = protocol.PacketTypeHandshake
+ case 0b11:
+ h.Type = protocol.PacketTypeRetry
+ }
+ }
+
+ if h.Type == protocol.PacketTypeRetry {
+ tokenLen := len(b) - 16
+ if tokenLen <= 0 {
+ return startLen - len(b), io.EOF
+ }
+ h.Token = make([]byte, tokenLen)
+ copy(h.Token, b[:tokenLen])
+ return startLen - len(b) + tokenLen + 16, nil
+ }
+
+ if h.Type == protocol.PacketTypeInitial {
+ tokenLen, n, err := quicvarint.Parse(b)
+ if err != nil {
+ return startLen - len(b), err
+ }
+ b = b[n:]
+ if tokenLen > uint64(len(b)) {
+ return startLen - len(b), io.EOF
+ }
+ h.Token = make([]byte, tokenLen)
+ copy(h.Token, b[:tokenLen])
+ b = b[tokenLen:]
+ }
+
+ pl, n, err := quicvarint.Parse(b)
+ if err != nil {
+ return 0, err
+ }
+ h.Length = protocol.ByteCount(pl)
+ return startLen - len(b) + n, nil
+}
+
+// ParsedLen returns the number of bytes that were consumed when parsing the header
+func (h *Header) ParsedLen() protocol.ByteCount {
+ return h.parsedLen
+}
+
+// ParseExtended parses the version dependent part of the header.
+// The Reader has to be set such that it points to the first byte of the header.
+func (h *Header) ParseExtended(data []byte) (*ExtendedHeader, error) {
+ extHdr := h.toExtendedHeader()
+ reservedBitsValid, err := extHdr.parse(data)
+ if err != nil {
+ return nil, err
+ }
+ if !reservedBitsValid {
+ return extHdr, ErrInvalidReservedBits
+ }
+ return extHdr, nil
+}
+
+func (h *Header) toExtendedHeader() *ExtendedHeader {
+ return &ExtendedHeader{Header: *h}
+}
+
+// PacketType is the type of the packet, for logging purposes
+func (h *Header) PacketType() string {
+ return h.Type.String()
+}
+
+func readPacketNumber(data []byte, pnLen protocol.PacketNumberLen) (protocol.PacketNumber, error) {
+ var pn protocol.PacketNumber
+ switch pnLen {
+ case protocol.PacketNumberLen1:
+ pn = protocol.PacketNumber(data[0])
+ case protocol.PacketNumberLen2:
+ pn = protocol.PacketNumber(binary.BigEndian.Uint16(data[:2]))
+ case protocol.PacketNumberLen3:
+ pn = protocol.PacketNumber(uint32(data[2]) + uint32(data[1])<<8 + uint32(data[0])<<16)
+ case protocol.PacketNumberLen4:
+ pn = protocol.PacketNumber(binary.BigEndian.Uint32(data[:4]))
+ default:
+ return 0, fmt.Errorf("invalid packet number length: %d", pnLen)
+ }
+ return pn, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/immediate_ack_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/immediate_ack_frame.go
new file mode 100644
index 00000000..aeff71b4
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/immediate_ack_frame.go
@@ -0,0 +1,18 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// An ImmediateAckFrame is an IMMEDIATE_ACK frame
+type ImmediateAckFrame struct{}
+
+func (f *ImmediateAckFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ return quicvarint.Append(b, uint64(FrameTypeImmediateAck)), nil
+}
+
+// Length of a written frame
+func (f *ImmediateAckFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return protocol.ByteCount(quicvarint.Len(uint64(FrameTypeImmediateAck)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/log.go b/vendor/github.com/quic-go/quic-go/internal/wire/log.go
new file mode 100644
index 00000000..c8b28d92
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/log.go
@@ -0,0 +1,74 @@
+package wire
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+// LogFrame logs a frame, either sent or received
+func LogFrame(logger utils.Logger, frame Frame, sent bool) {
+ if !logger.Debug() {
+ return
+ }
+ dir := "<-"
+ if sent {
+ dir = "->"
+ }
+ switch f := frame.(type) {
+ case *CryptoFrame:
+ dataLen := protocol.ByteCount(len(f.Data))
+ logger.Debugf("\t%s &wire.CryptoFrame{Offset: %d, Data length: %d, Offset + Data length: %d}", dir, f.Offset, dataLen, f.Offset+dataLen)
+ case *StreamFrame:
+ logger.Debugf("\t%s &wire.StreamFrame{StreamID: %d, Fin: %t, Offset: %d, Data length: %d, Offset + Data length: %d}", dir, f.StreamID, f.Fin, f.Offset, f.DataLen(), f.Offset+f.DataLen())
+ case *ResetStreamFrame:
+ logger.Debugf("\t%s &wire.ResetStreamFrame{StreamID: %d, ErrorCode: %#x, FinalSize: %d}", dir, f.StreamID, f.ErrorCode, f.FinalSize)
+ case *AckFrame:
+ hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0
+ var ecn string
+ if hasECN {
+ ecn = fmt.Sprintf(", ECT0: %d, ECT1: %d, CE: %d", f.ECT0, f.ECT1, f.ECNCE)
+ }
+ if len(f.AckRanges) > 1 {
+ ackRanges := make([]string, len(f.AckRanges))
+ for i, r := range f.AckRanges {
+ ackRanges[i] = fmt.Sprintf("{Largest: %d, Smallest: %d}", r.Largest, r.Smallest)
+ }
+ logger.Debugf("\t%s &wire.AckFrame{LargestAcked: %d, LowestAcked: %d, AckRanges: {%s}, DelayTime: %s%s}", dir, f.LargestAcked(), f.LowestAcked(), strings.Join(ackRanges, ", "), f.DelayTime.String(), ecn)
+ } else {
+ logger.Debugf("\t%s &wire.AckFrame{LargestAcked: %d, LowestAcked: %d, DelayTime: %s%s}", dir, f.LargestAcked(), f.LowestAcked(), f.DelayTime.String(), ecn)
+ }
+ case *MaxDataFrame:
+ logger.Debugf("\t%s &wire.MaxDataFrame{MaximumData: %d}", dir, f.MaximumData)
+ case *MaxStreamDataFrame:
+ logger.Debugf("\t%s &wire.MaxStreamDataFrame{StreamID: %d, MaximumStreamData: %d}", dir, f.StreamID, f.MaximumStreamData)
+ case *DataBlockedFrame:
+ logger.Debugf("\t%s &wire.DataBlockedFrame{MaximumData: %d}", dir, f.MaximumData)
+ case *StreamDataBlockedFrame:
+ logger.Debugf("\t%s &wire.StreamDataBlockedFrame{StreamID: %d, MaximumStreamData: %d}", dir, f.StreamID, f.MaximumStreamData)
+ case *MaxStreamsFrame:
+ switch f.Type {
+ case protocol.StreamTypeUni:
+ logger.Debugf("\t%s &wire.MaxStreamsFrame{Type: uni, MaxStreamNum: %d}", dir, f.MaxStreamNum)
+ case protocol.StreamTypeBidi:
+ logger.Debugf("\t%s &wire.MaxStreamsFrame{Type: bidi, MaxStreamNum: %d}", dir, f.MaxStreamNum)
+ }
+ case *StreamsBlockedFrame:
+ switch f.Type {
+ case protocol.StreamTypeUni:
+ logger.Debugf("\t%s &wire.StreamsBlockedFrame{Type: uni, MaxStreams: %d}", dir, f.StreamLimit)
+ case protocol.StreamTypeBidi:
+ logger.Debugf("\t%s &wire.StreamsBlockedFrame{Type: bidi, MaxStreams: %d}", dir, f.StreamLimit)
+ }
+ case *NewConnectionIDFrame:
+ logger.Debugf("\t%s &wire.NewConnectionIDFrame{SequenceNumber: %d, RetirePriorTo: %d, ConnectionID: %s, StatelessResetToken: %#x}", dir, f.SequenceNumber, f.RetirePriorTo, f.ConnectionID, f.StatelessResetToken)
+ case *RetireConnectionIDFrame:
+ logger.Debugf("\t%s &wire.RetireConnectionIDFrame{SequenceNumber: %d}", dir, f.SequenceNumber)
+ case *NewTokenFrame:
+ logger.Debugf("\t%s &wire.NewTokenFrame{Token: %#x}", dir, f.Token)
+ default:
+ logger.Debugf("\t%s %#v", dir, frame)
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/max_data_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/max_data_frame.go
new file mode 100644
index 00000000..bfbdcba6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/max_data_frame.go
@@ -0,0 +1,33 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A MaxDataFrame carries flow control information for the connection
+type MaxDataFrame struct {
+ MaximumData protocol.ByteCount
+}
+
+// parseMaxDataFrame parses a MAX_DATA frame
+func parseMaxDataFrame(b []byte, _ protocol.Version) (*MaxDataFrame, int, error) {
+ frame := &MaxDataFrame{}
+ byteOffset, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ frame.MaximumData = protocol.ByteCount(byteOffset)
+ return frame, l, nil
+}
+
+func (f *MaxDataFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeMaxData))
+ b = quicvarint.Append(b, uint64(f.MaximumData))
+ return b, nil
+}
+
+// Length of a written frame
+func (f *MaxDataFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.MaximumData)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/max_stream_data_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/max_stream_data_frame.go
new file mode 100644
index 00000000..0966ea46
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/max_stream_data_frame.go
@@ -0,0 +1,43 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A MaxStreamDataFrame is a MAX_STREAM_DATA frame
+type MaxStreamDataFrame struct {
+ StreamID protocol.StreamID
+ MaximumStreamData protocol.ByteCount
+}
+
+func parseMaxStreamDataFrame(b []byte, _ protocol.Version) (*MaxStreamDataFrame, int, error) {
+ startLen := len(b)
+ sid, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ offset, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+
+ return &MaxStreamDataFrame{
+ StreamID: protocol.StreamID(sid),
+ MaximumStreamData: protocol.ByteCount(offset),
+ }, startLen - len(b), nil
+}
+
+func (f *MaxStreamDataFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeMaxStreamData))
+ b = quicvarint.Append(b, uint64(f.StreamID))
+ b = quicvarint.Append(b, uint64(f.MaximumStreamData))
+ return b, nil
+}
+
+// Length of a written frame
+func (f *MaxStreamDataFrame) Length(protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.StreamID))+quicvarint.Len(uint64(f.MaximumStreamData)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/max_streams_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/max_streams_frame.go
new file mode 100644
index 00000000..30612e23
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/max_streams_frame.go
@@ -0,0 +1,50 @@
+package wire
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A MaxStreamsFrame is a MAX_STREAMS frame
+type MaxStreamsFrame struct {
+ Type protocol.StreamType
+ MaxStreamNum protocol.StreamNum
+}
+
+func parseMaxStreamsFrame(b []byte, typ FrameType, _ protocol.Version) (*MaxStreamsFrame, int, error) {
+ f := &MaxStreamsFrame{}
+ //nolint:exhaustive // Function will only be called with BidiMaxStreamsFrameType or UniMaxStreamsFrameType
+ switch typ {
+ case FrameTypeBidiMaxStreams:
+ f.Type = protocol.StreamTypeBidi
+ case FrameTypeUniMaxStreams:
+ f.Type = protocol.StreamTypeUni
+ }
+ streamID, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ f.MaxStreamNum = protocol.StreamNum(streamID)
+ if f.MaxStreamNum > protocol.MaxStreamCount {
+ return nil, 0, fmt.Errorf("%d exceeds the maximum stream count", f.MaxStreamNum)
+ }
+ return f, l, nil
+}
+
+func (f *MaxStreamsFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ switch f.Type {
+ case protocol.StreamTypeBidi:
+ b = append(b, byte(FrameTypeBidiMaxStreams))
+ case protocol.StreamTypeUni:
+ b = append(b, byte(FrameTypeUniMaxStreams))
+ }
+ b = quicvarint.Append(b, uint64(f.MaxStreamNum))
+ return b, nil
+}
+
+// Length of a written frame
+func (f *MaxStreamsFrame) Length(protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.MaxStreamNum)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go
new file mode 100644
index 00000000..05831926
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go
@@ -0,0 +1,80 @@
+package wire
+
+import (
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A NewConnectionIDFrame is a NEW_CONNECTION_ID frame
+type NewConnectionIDFrame struct {
+ SequenceNumber uint64
+ RetirePriorTo uint64
+ ConnectionID protocol.ConnectionID
+ StatelessResetToken protocol.StatelessResetToken
+}
+
+func parseNewConnectionIDFrame(b []byte, _ protocol.Version) (*NewConnectionIDFrame, int, error) {
+ startLen := len(b)
+ seq, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ ret, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ if ret > seq {
+ //nolint:staticcheck // SA1021: Retire Prior To is the name of the field
+ return nil, 0, fmt.Errorf("Retire Prior To value (%d) larger than Sequence Number (%d)", ret, seq)
+ }
+ if len(b) == 0 {
+ return nil, 0, io.EOF
+ }
+ connIDLen := int(b[0])
+ b = b[1:]
+ if connIDLen == 0 {
+ return nil, 0, errors.New("invalid zero-length connection ID")
+ }
+ if connIDLen > protocol.MaxConnIDLen {
+ return nil, 0, protocol.ErrInvalidConnectionIDLen
+ }
+ if len(b) < connIDLen {
+ return nil, 0, io.EOF
+ }
+ frame := &NewConnectionIDFrame{
+ SequenceNumber: seq,
+ RetirePriorTo: ret,
+ ConnectionID: protocol.ParseConnectionID(b[:connIDLen]),
+ }
+ b = b[connIDLen:]
+ if len(b) < len(frame.StatelessResetToken) {
+ return nil, 0, io.EOF
+ }
+ copy(frame.StatelessResetToken[:], b)
+ return frame, startLen - len(b) + len(frame.StatelessResetToken), nil
+}
+
+func (f *NewConnectionIDFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeNewConnectionID))
+ b = quicvarint.Append(b, f.SequenceNumber)
+ b = quicvarint.Append(b, f.RetirePriorTo)
+ connIDLen := f.ConnectionID.Len()
+ if connIDLen > protocol.MaxConnIDLen {
+ return nil, fmt.Errorf("invalid connection ID length: %d", connIDLen)
+ }
+ b = append(b, uint8(connIDLen))
+ b = append(b, f.ConnectionID.Bytes()...)
+ b = append(b, f.StatelessResetToken[:]...)
+ return b, nil
+}
+
+// Length of a written frame
+func (f *NewConnectionIDFrame) Length(protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(f.SequenceNumber)+quicvarint.Len(f.RetirePriorTo)+1 /* connection ID length */ +f.ConnectionID.Len()) + 16
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/new_token_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/new_token_frame.go
new file mode 100644
index 00000000..73d356b1
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/new_token_frame.go
@@ -0,0 +1,43 @@
+package wire
+
+import (
+ "errors"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A NewTokenFrame is a NEW_TOKEN frame
+type NewTokenFrame struct {
+ Token []byte
+}
+
+func parseNewTokenFrame(b []byte, _ protocol.Version) (*NewTokenFrame, int, error) {
+ tokenLen, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ if tokenLen == 0 {
+ return nil, 0, errors.New("token must not be empty")
+ }
+ if uint64(len(b)) < tokenLen {
+ return nil, 0, io.EOF
+ }
+ token := make([]byte, int(tokenLen))
+ copy(token, b)
+ return &NewTokenFrame{Token: token}, l + int(tokenLen), nil
+}
+
+func (f *NewTokenFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeNewToken))
+ b = quicvarint.Append(b, uint64(len(f.Token)))
+ b = append(b, f.Token...)
+ return b, nil
+}
+
+// Length of a written frame
+func (f *NewTokenFrame) Length(protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(len(f.Token)))+len(f.Token))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/path_challenge_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/path_challenge_frame.go
new file mode 100644
index 00000000..7a4a767e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/path_challenge_frame.go
@@ -0,0 +1,32 @@
+package wire
+
+import (
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// A PathChallengeFrame is a PATH_CHALLENGE frame
+type PathChallengeFrame struct {
+ Data [8]byte
+}
+
+func parsePathChallengeFrame(b []byte, _ protocol.Version) (*PathChallengeFrame, int, error) {
+ f := &PathChallengeFrame{}
+ if len(b) < 8 {
+ return nil, 0, io.EOF
+ }
+ copy(f.Data[:], b)
+ return f, 8, nil
+}
+
+func (f *PathChallengeFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypePathChallenge))
+ b = append(b, f.Data[:]...)
+ return b, nil
+}
+
+// Length of a written frame
+func (f *PathChallengeFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return 1 + 8
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/path_response_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/path_response_frame.go
new file mode 100644
index 00000000..e76d037b
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/path_response_frame.go
@@ -0,0 +1,32 @@
+package wire
+
+import (
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// A PathResponseFrame is a PATH_RESPONSE frame
+type PathResponseFrame struct {
+ Data [8]byte
+}
+
+func parsePathResponseFrame(b []byte, _ protocol.Version) (*PathResponseFrame, int, error) {
+ f := &PathResponseFrame{}
+ if len(b) < 8 {
+ return nil, 0, io.EOF
+ }
+ copy(f.Data[:], b)
+ return f, 8, nil
+}
+
+func (f *PathResponseFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypePathResponse))
+ b = append(b, f.Data[:]...)
+ return b, nil
+}
+
+// Length of a written frame
+func (f *PathResponseFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return 1 + 8
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/ping_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/ping_frame.go
new file mode 100644
index 00000000..5d344d44
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/ping_frame.go
@@ -0,0 +1,17 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// A PingFrame is a PING frame
+type PingFrame struct{}
+
+func (f *PingFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ return append(b, byte(FrameTypePing)), nil
+}
+
+// Length of a written frame
+func (f *PingFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return 1
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/pool.go b/vendor/github.com/quic-go/quic-go/internal/wire/pool.go
new file mode 100644
index 00000000..d656fad4
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/pool.go
@@ -0,0 +1,33 @@
+package wire
+
+import (
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+var pool sync.Pool
+
+func init() {
+ pool.New = func() any {
+ return &StreamFrame{
+ Data: make([]byte, 0, protocol.MaxPacketBufferSize),
+ fromPool: true,
+ }
+ }
+}
+
+func GetStreamFrame() *StreamFrame {
+ f := pool.Get().(*StreamFrame)
+ return f
+}
+
+func putStreamFrame(f *StreamFrame) {
+ if !f.fromPool {
+ return
+ }
+ if protocol.ByteCount(cap(f.Data)) != protocol.MaxPacketBufferSize {
+ panic("wire.PutStreamFrame called with packet of wrong size!")
+ }
+ pool.Put(f)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go
new file mode 100644
index 00000000..4101b76b
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/reset_stream_frame.go
@@ -0,0 +1,79 @@
+package wire
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A ResetStreamFrame is a RESET_STREAM or RESET_STREAM_AT frame in QUIC
+type ResetStreamFrame struct {
+ StreamID protocol.StreamID
+ ErrorCode qerr.StreamErrorCode
+ FinalSize protocol.ByteCount
+ ReliableSize protocol.ByteCount
+}
+
+func parseResetStreamFrame(b []byte, isResetStreamAt bool, _ protocol.Version) (*ResetStreamFrame, int, error) {
+ startLen := len(b)
+ streamID, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ errorCode, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ finalSize, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+
+ var reliableSize uint64
+ if isResetStreamAt {
+ reliableSize, l, err = quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ }
+ if reliableSize > finalSize {
+ return nil, 0, fmt.Errorf("RESET_STREAM_AT: reliable size can't be larger than final size (%d vs %d)", reliableSize, finalSize)
+ }
+
+ return &ResetStreamFrame{
+ StreamID: protocol.StreamID(streamID),
+ ErrorCode: qerr.StreamErrorCode(errorCode),
+ FinalSize: protocol.ByteCount(finalSize),
+ ReliableSize: protocol.ByteCount(reliableSize),
+ }, startLen - len(b), nil
+}
+
+func (f *ResetStreamFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ if f.ReliableSize == 0 {
+ b = quicvarint.Append(b, uint64(FrameTypeResetStream))
+ } else {
+ b = quicvarint.Append(b, uint64(FrameTypeResetStreamAt))
+ }
+ b = quicvarint.Append(b, uint64(f.StreamID))
+ b = quicvarint.Append(b, uint64(f.ErrorCode))
+ b = quicvarint.Append(b, uint64(f.FinalSize))
+ if f.ReliableSize > 0 {
+ b = quicvarint.Append(b, uint64(f.ReliableSize))
+ }
+ return b, nil
+}
+
+// Length of a written frame
+func (f *ResetStreamFrame) Length(protocol.Version) protocol.ByteCount {
+ size := 1 // the frame type for both RESET_STREAM and RESET_STREAM_AT fits into 1 byte
+ if f.ReliableSize > 0 {
+ size += quicvarint.Len(uint64(f.ReliableSize))
+ }
+ return protocol.ByteCount(size + quicvarint.Len(uint64(f.StreamID)) + quicvarint.Len(uint64(f.ErrorCode)) + quicvarint.Len(uint64(f.FinalSize)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/retire_connection_id_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/retire_connection_id_frame.go
new file mode 100644
index 00000000..1927f9dc
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/retire_connection_id_frame.go
@@ -0,0 +1,30 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A RetireConnectionIDFrame is a RETIRE_CONNECTION_ID frame
+type RetireConnectionIDFrame struct {
+ SequenceNumber uint64
+}
+
+func parseRetireConnectionIDFrame(b []byte, _ protocol.Version) (*RetireConnectionIDFrame, int, error) {
+ seq, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ return &RetireConnectionIDFrame{SequenceNumber: seq}, l, nil
+}
+
+func (f *RetireConnectionIDFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeRetireConnectionID))
+ b = quicvarint.Append(b, f.SequenceNumber)
+ return b, nil
+}
+
+// Length of a written frame
+func (f *RetireConnectionIDFrame) Length(protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(f.SequenceNumber))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/short_header.go b/vendor/github.com/quic-go/quic-go/internal/wire/short_header.go
new file mode 100644
index 00000000..cf2889c5
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/short_header.go
@@ -0,0 +1,62 @@
+package wire
+
+import (
+ "errors"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+// ParseShortHeader parses a short header packet.
+// It must be called after header protection was removed.
+// Otherwise, the check for the reserved bits will (most likely) fail.
+func ParseShortHeader(data []byte, connIDLen int) (length int, _ protocol.PacketNumber, _ protocol.PacketNumberLen, _ protocol.KeyPhaseBit, _ error) {
+ if len(data) == 0 {
+ return 0, 0, 0, 0, io.EOF
+ }
+ if data[0]&0x80 > 0 {
+ return 0, 0, 0, 0, errors.New("not a short header packet")
+ }
+ if data[0]&0x40 == 0 {
+ return 0, 0, 0, 0, errors.New("not a QUIC packet")
+ }
+ pnLen := protocol.PacketNumberLen(data[0]&0b11) + 1
+ if len(data) < 1+int(pnLen)+connIDLen {
+ return 0, 0, 0, 0, io.EOF
+ }
+
+ pos := 1 + connIDLen
+ pn, err := readPacketNumber(data[pos:], pnLen)
+ if err != nil {
+ return 0, 0, 0, 0, err
+ }
+ kp := protocol.KeyPhaseZero
+ if data[0]&0b100 > 0 {
+ kp = protocol.KeyPhaseOne
+ }
+
+ if data[0]&0x18 != 0 {
+ err = ErrInvalidReservedBits
+ }
+ return 1 + connIDLen + int(pnLen), pn, pnLen, kp, err
+}
+
+// AppendShortHeader writes a short header.
+func AppendShortHeader(b []byte, connID protocol.ConnectionID, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen, kp protocol.KeyPhaseBit) ([]byte, error) {
+ typeByte := 0x40 | uint8(pnLen-1)
+ if kp == protocol.KeyPhaseOne {
+ typeByte |= byte(1 << 2)
+ }
+ b = append(b, typeByte)
+ b = append(b, connID.Bytes()...)
+ return appendPacketNumber(b, pn, pnLen)
+}
+
+func ShortHeaderLen(dest protocol.ConnectionID, pnLen protocol.PacketNumberLen) protocol.ByteCount {
+ return 1 + protocol.ByteCount(dest.Len()) + protocol.ByteCount(pnLen)
+}
+
+func LogShortHeader(logger utils.Logger, dest protocol.ConnectionID, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen, kp protocol.KeyPhaseBit) {
+ logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %d, PacketNumberLen: %d, KeyPhase: %s}", dest, pn, pnLen, kp)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/stop_sending_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/stop_sending_frame.go
new file mode 100644
index 00000000..2b15c710
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/stop_sending_frame.go
@@ -0,0 +1,45 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A StopSendingFrame is a STOP_SENDING frame
+type StopSendingFrame struct {
+ StreamID protocol.StreamID
+ ErrorCode qerr.StreamErrorCode
+}
+
+// parseStopSendingFrame parses a STOP_SENDING frame
+func parseStopSendingFrame(b []byte, _ protocol.Version) (*StopSendingFrame, int, error) {
+ startLen := len(b)
+ streamID, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ errorCode, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+
+ return &StopSendingFrame{
+ StreamID: protocol.StreamID(streamID),
+ ErrorCode: qerr.StreamErrorCode(errorCode),
+ }, startLen - len(b), nil
+}
+
+// Length of a written frame
+func (f *StopSendingFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.StreamID))+quicvarint.Len(uint64(f.ErrorCode)))
+}
+
+func (f *StopSendingFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, byte(FrameTypeStopSending))
+ b = quicvarint.Append(b, uint64(f.StreamID))
+ b = quicvarint.Append(b, uint64(f.ErrorCode))
+ return b, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/stream_data_blocked_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/stream_data_blocked_frame.go
new file mode 100644
index 00000000..3762ec76
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/stream_data_blocked_frame.go
@@ -0,0 +1,42 @@
+package wire
+
+import (
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A StreamDataBlockedFrame is a STREAM_DATA_BLOCKED frame
+type StreamDataBlockedFrame struct {
+ StreamID protocol.StreamID
+ MaximumStreamData protocol.ByteCount
+}
+
+func parseStreamDataBlockedFrame(b []byte, _ protocol.Version) (*StreamDataBlockedFrame, int, error) {
+ startLen := len(b)
+ sid, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ offset, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+
+ return &StreamDataBlockedFrame{
+ StreamID: protocol.StreamID(sid),
+ MaximumStreamData: protocol.ByteCount(offset),
+ }, startLen - len(b) + l, nil
+}
+
+func (f *StreamDataBlockedFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ b = append(b, 0x15)
+ b = quicvarint.Append(b, uint64(f.StreamID))
+ b = quicvarint.Append(b, uint64(f.MaximumStreamData))
+ return b, nil
+}
+
+// Length of a written frame
+func (f *StreamDataBlockedFrame) Length(protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.StreamID))+quicvarint.Len(uint64(f.MaximumStreamData)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/stream_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/stream_frame.go
new file mode 100644
index 00000000..e53962b1
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/stream_frame.go
@@ -0,0 +1,191 @@
+package wire
+
+import (
+ "errors"
+ "io"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A StreamFrame of QUIC
+type StreamFrame struct {
+ StreamID protocol.StreamID
+ Offset protocol.ByteCount
+ Data []byte
+ Fin bool
+ DataLenPresent bool
+
+ fromPool bool
+}
+
+func ParseStreamFrame(b []byte, typ FrameType, _ protocol.Version) (*StreamFrame, int, error) {
+ startLen := len(b)
+ hasOffset := typ&0b100 > 0
+ fin := typ&0b1 > 0
+ hasDataLen := typ&0b10 > 0
+
+ streamID, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ var offset uint64
+ if hasOffset {
+ offset, l, err = quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ }
+
+ var dataLen uint64
+ if hasDataLen {
+ var err error
+ var l int
+ dataLen, l, err = quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ b = b[l:]
+ if dataLen > uint64(len(b)) {
+ return nil, 0, io.EOF
+ }
+ } else {
+ // The rest of the packet is data
+ dataLen = uint64(len(b))
+ }
+
+ var frame *StreamFrame
+ if dataLen < protocol.MinStreamFrameBufferSize {
+ frame = &StreamFrame{}
+ if dataLen > 0 {
+ frame.Data = make([]byte, dataLen)
+ }
+ } else {
+ frame = GetStreamFrame()
+ // The STREAM frame can't be larger than the StreamFrame we obtained from the buffer,
+ // since those StreamFrames have a buffer length of the maximum packet size.
+ if dataLen > uint64(cap(frame.Data)) {
+ return nil, 0, io.EOF
+ }
+ frame.Data = frame.Data[:dataLen]
+ }
+
+ frame.StreamID = protocol.StreamID(streamID)
+ frame.Offset = protocol.ByteCount(offset)
+ frame.Fin = fin
+ frame.DataLenPresent = hasDataLen
+
+ if dataLen > 0 {
+ copy(frame.Data, b)
+ }
+ if frame.Offset+frame.DataLen() > protocol.MaxByteCount {
+ return nil, 0, errors.New("stream data overflows maximum offset")
+ }
+ return frame, startLen - len(b) + int(dataLen), nil
+}
+
+func (f *StreamFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ if len(f.Data) == 0 && !f.Fin {
+ return nil, errors.New("StreamFrame: attempting to write empty frame without FIN")
+ }
+
+ typ := byte(0x8)
+ if f.Fin {
+ typ ^= 0b1
+ }
+ hasOffset := f.Offset != 0
+ if f.DataLenPresent {
+ typ ^= 0b10
+ }
+ if hasOffset {
+ typ ^= 0b100
+ }
+ b = append(b, typ)
+ b = quicvarint.Append(b, uint64(f.StreamID))
+ if hasOffset {
+ b = quicvarint.Append(b, uint64(f.Offset))
+ }
+ if f.DataLenPresent {
+ b = quicvarint.Append(b, uint64(f.DataLen()))
+ }
+ b = append(b, f.Data...)
+ return b, nil
+}
+
+// Length returns the total length of the STREAM frame
+func (f *StreamFrame) Length(protocol.Version) protocol.ByteCount {
+ length := 1 + quicvarint.Len(uint64(f.StreamID))
+ if f.Offset != 0 {
+ length += quicvarint.Len(uint64(f.Offset))
+ }
+ if f.DataLenPresent {
+ length += quicvarint.Len(uint64(f.DataLen()))
+ }
+ return protocol.ByteCount(length) + f.DataLen()
+}
+
+// DataLen gives the length of data in bytes
+func (f *StreamFrame) DataLen() protocol.ByteCount {
+ return protocol.ByteCount(len(f.Data))
+}
+
+// MaxDataLen returns the maximum data length
+// If 0 is returned, writing will fail (a STREAM frame must contain at least 1 byte of data).
+func (f *StreamFrame) MaxDataLen(maxSize protocol.ByteCount, _ protocol.Version) protocol.ByteCount {
+ headerLen := 1 + protocol.ByteCount(quicvarint.Len(uint64(f.StreamID)))
+ if f.Offset != 0 {
+ headerLen += protocol.ByteCount(quicvarint.Len(uint64(f.Offset)))
+ }
+ if f.DataLenPresent {
+ // Pretend that the data size will be 1 byte.
+ // If it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterward
+ headerLen++
+ }
+ if headerLen > maxSize {
+ return 0
+ }
+ maxDataLen := maxSize - headerLen
+ if f.DataLenPresent && quicvarint.Len(uint64(maxDataLen)) != 1 {
+ maxDataLen--
+ }
+ return maxDataLen
+}
+
+// MaybeSplitOffFrame splits a frame such that it is not bigger than n bytes.
+// It returns if the frame was actually split.
+// The frame might not be split if:
+// * the size is large enough to fit the whole frame
+// * the size is too small to fit even a 1-byte frame. In that case, the frame returned is nil.
+func (f *StreamFrame) MaybeSplitOffFrame(maxSize protocol.ByteCount, version protocol.Version) (*StreamFrame, bool /* was splitting required */) {
+ if maxSize >= f.Length(version) {
+ return nil, false
+ }
+
+ n := f.MaxDataLen(maxSize, version)
+ if n == 0 {
+ return nil, true
+ }
+
+ new := GetStreamFrame()
+ new.StreamID = f.StreamID
+ new.Offset = f.Offset
+ new.Fin = false
+ new.DataLenPresent = f.DataLenPresent
+
+ // swap the data slices
+ new.Data, f.Data = f.Data, new.Data
+ new.fromPool, f.fromPool = f.fromPool, new.fromPool
+
+ f.Data = f.Data[:protocol.ByteCount(len(new.Data))-n]
+ copy(f.Data, new.Data[n:])
+ new.Data = new.Data[:n]
+ f.Offset += n
+
+ return new, true
+}
+
+func (f *StreamFrame) PutBack() {
+ putStreamFrame(f)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/streams_blocked_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/streams_blocked_frame.go
new file mode 100644
index 00000000..d98fde46
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/streams_blocked_frame.go
@@ -0,0 +1,50 @@
+package wire
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// A StreamsBlockedFrame is a STREAMS_BLOCKED frame
+type StreamsBlockedFrame struct {
+ Type protocol.StreamType
+ StreamLimit protocol.StreamNum
+}
+
+func parseStreamsBlockedFrame(b []byte, typ FrameType, _ protocol.Version) (*StreamsBlockedFrame, int, error) {
+ f := &StreamsBlockedFrame{}
+ //nolint:exhaustive // This will only be called with a BidiStreamBlockedFrameType or a UniStreamBlockedFrameType.
+ switch typ {
+ case FrameTypeBidiStreamBlocked:
+ f.Type = protocol.StreamTypeBidi
+ case FrameTypeUniStreamBlocked:
+ f.Type = protocol.StreamTypeUni
+ }
+ streamLimit, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return nil, 0, replaceUnexpectedEOF(err)
+ }
+ f.StreamLimit = protocol.StreamNum(streamLimit)
+ if f.StreamLimit > protocol.MaxStreamCount {
+ return nil, 0, fmt.Errorf("%d exceeds the maximum stream count", f.StreamLimit)
+ }
+ return f, l, nil
+}
+
+func (f *StreamsBlockedFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
+ switch f.Type {
+ case protocol.StreamTypeBidi:
+ b = append(b, byte(FrameTypeBidiStreamBlocked))
+ case protocol.StreamTypeUni:
+ b = append(b, byte(FrameTypeUniStreamBlocked))
+ }
+ b = quicvarint.Append(b, uint64(f.StreamLimit))
+ return b, nil
+}
+
+// Length of a written frame
+func (f *StreamsBlockedFrame) Length(_ protocol.Version) protocol.ByteCount {
+ return 1 + protocol.ByteCount(quicvarint.Len(uint64(f.StreamLimit)))
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go b/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go
new file mode 100644
index 00000000..ff101b6e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go
@@ -0,0 +1,583 @@
+package wire
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "net/netip"
+ "slices"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/quicvarint"
+)
+
+// AdditionalTransportParametersClient are additional transport parameters that will be added
+// to the client's transport parameters.
+// This is not intended for production use, but _only_ to increase the size of the ClientHello beyond
+// the usual size of less than 1 MTU.
+var AdditionalTransportParametersClient map[uint64][]byte
+
+const transportParameterMarshalingVersion = 1
+
+type transportParameterID uint64
+
+const (
+ originalDestinationConnectionIDParameterID transportParameterID = 0x0
+ maxIdleTimeoutParameterID transportParameterID = 0x1
+ statelessResetTokenParameterID transportParameterID = 0x2
+ maxUDPPayloadSizeParameterID transportParameterID = 0x3
+ initialMaxDataParameterID transportParameterID = 0x4
+ initialMaxStreamDataBidiLocalParameterID transportParameterID = 0x5
+ initialMaxStreamDataBidiRemoteParameterID transportParameterID = 0x6
+ initialMaxStreamDataUniParameterID transportParameterID = 0x7
+ initialMaxStreamsBidiParameterID transportParameterID = 0x8
+ initialMaxStreamsUniParameterID transportParameterID = 0x9
+ ackDelayExponentParameterID transportParameterID = 0xa
+ maxAckDelayParameterID transportParameterID = 0xb
+ disableActiveMigrationParameterID transportParameterID = 0xc
+ preferredAddressParameterID transportParameterID = 0xd
+ activeConnectionIDLimitParameterID transportParameterID = 0xe
+ initialSourceConnectionIDParameterID transportParameterID = 0xf
+ retrySourceConnectionIDParameterID transportParameterID = 0x10
+ // RFC 9221
+ maxDatagramFrameSizeParameterID transportParameterID = 0x20
+ // https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/06/
+ resetStreamAtParameterID transportParameterID = 0x17f7586d2cb571
+ // https://datatracker.ietf.org/doc/draft-ietf-quic-ack-frequency/11/
+ minAckDelayParameterID transportParameterID = 0xff04de1b
+)
+
+// PreferredAddress is the value encoding in the preferred_address transport parameter
+type PreferredAddress struct {
+ IPv4, IPv6 netip.AddrPort
+ ConnectionID protocol.ConnectionID
+ StatelessResetToken protocol.StatelessResetToken
+}
+
+// TransportParameters are parameters sent to the peer during the handshake
+type TransportParameters struct {
+ InitialMaxStreamDataBidiLocal protocol.ByteCount
+ InitialMaxStreamDataBidiRemote protocol.ByteCount
+ InitialMaxStreamDataUni protocol.ByteCount
+ InitialMaxData protocol.ByteCount
+
+ MaxAckDelay time.Duration
+ AckDelayExponent uint8
+
+ DisableActiveMigration bool
+
+ MaxUDPPayloadSize protocol.ByteCount
+
+ MaxUniStreamNum protocol.StreamNum
+ MaxBidiStreamNum protocol.StreamNum
+
+ MaxIdleTimeout time.Duration
+
+ PreferredAddress *PreferredAddress
+
+ OriginalDestinationConnectionID protocol.ConnectionID
+ InitialSourceConnectionID protocol.ConnectionID
+ RetrySourceConnectionID *protocol.ConnectionID // use a pointer here to distinguish zero-length connection IDs from missing transport parameters
+
+ StatelessResetToken *protocol.StatelessResetToken
+ ActiveConnectionIDLimit uint64
+
+ MaxDatagramFrameSize protocol.ByteCount // RFC 9221
+ EnableResetStreamAt bool // https://datatracker.ietf.org/doc/draft-ietf-quic-reliable-stream-reset/06/
+ MinAckDelay *time.Duration
+}
+
+// Unmarshal the transport parameters
+func (p *TransportParameters) Unmarshal(data []byte, sentBy protocol.Perspective) error {
+ if err := p.unmarshal(data, sentBy, false); err != nil {
+ return &qerr.TransportError{
+ ErrorCode: qerr.TransportParameterError,
+ ErrorMessage: err.Error(),
+ }
+ }
+ return nil
+}
+
+func (p *TransportParameters) unmarshal(b []byte, sentBy protocol.Perspective, fromSessionTicket bool) error {
+ // needed to check that every parameter is only sent at most once
+ parameterIDs := make([]transportParameterID, 0, 32)
+
+ var (
+ readOriginalDestinationConnectionID bool
+ readInitialSourceConnectionID bool
+ )
+
+ p.AckDelayExponent = protocol.DefaultAckDelayExponent
+ p.MaxAckDelay = protocol.DefaultMaxAckDelay
+ p.MaxDatagramFrameSize = protocol.InvalidByteCount
+ p.ActiveConnectionIDLimit = protocol.DefaultActiveConnectionIDLimit
+
+ for len(b) > 0 {
+ paramIDInt, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return err
+ }
+ paramID := transportParameterID(paramIDInt)
+ b = b[l:]
+ paramLen, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return err
+ }
+ b = b[l:]
+ if uint64(len(b)) < paramLen {
+ return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", len(b), paramLen)
+ }
+ parameterIDs = append(parameterIDs, paramID)
+ switch paramID {
+ case maxIdleTimeoutParameterID,
+ maxUDPPayloadSizeParameterID,
+ initialMaxDataParameterID,
+ initialMaxStreamDataBidiLocalParameterID,
+ initialMaxStreamDataBidiRemoteParameterID,
+ initialMaxStreamDataUniParameterID,
+ initialMaxStreamsBidiParameterID,
+ initialMaxStreamsUniParameterID,
+ maxAckDelayParameterID,
+ maxDatagramFrameSizeParameterID,
+ ackDelayExponentParameterID,
+ activeConnectionIDLimitParameterID,
+ minAckDelayParameterID:
+ if err := p.readNumericTransportParameter(b, paramID, int(paramLen)); err != nil {
+ return err
+ }
+ b = b[paramLen:]
+ case preferredAddressParameterID:
+ if sentBy == protocol.PerspectiveClient {
+ return errors.New("client sent a preferred_address")
+ }
+ if err := p.readPreferredAddress(b, int(paramLen)); err != nil {
+ return err
+ }
+ b = b[paramLen:]
+ case disableActiveMigrationParameterID:
+ if paramLen != 0 {
+ return fmt.Errorf("wrong length for disable_active_migration: %d (expected empty)", paramLen)
+ }
+ p.DisableActiveMigration = true
+ case statelessResetTokenParameterID:
+ if sentBy == protocol.PerspectiveClient {
+ return errors.New("client sent a stateless_reset_token")
+ }
+ if paramLen != 16 {
+ return fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", paramLen)
+ }
+ var token protocol.StatelessResetToken
+ if len(b) < len(token) {
+ return io.EOF
+ }
+ copy(token[:], b)
+ b = b[len(token):]
+ p.StatelessResetToken = &token
+ case originalDestinationConnectionIDParameterID:
+ if sentBy == protocol.PerspectiveClient {
+ return errors.New("client sent an original_destination_connection_id")
+ }
+ if paramLen > protocol.MaxConnIDLen {
+ return protocol.ErrInvalidConnectionIDLen
+ }
+ p.OriginalDestinationConnectionID = protocol.ParseConnectionID(b[:paramLen])
+ b = b[paramLen:]
+ readOriginalDestinationConnectionID = true
+ case initialSourceConnectionIDParameterID:
+ if paramLen > protocol.MaxConnIDLen {
+ return protocol.ErrInvalidConnectionIDLen
+ }
+ p.InitialSourceConnectionID = protocol.ParseConnectionID(b[:paramLen])
+ b = b[paramLen:]
+ readInitialSourceConnectionID = true
+ case retrySourceConnectionIDParameterID:
+ if sentBy == protocol.PerspectiveClient {
+ return errors.New("client sent a retry_source_connection_id")
+ }
+ if paramLen > protocol.MaxConnIDLen {
+ return protocol.ErrInvalidConnectionIDLen
+ }
+ connID := protocol.ParseConnectionID(b[:paramLen])
+ b = b[paramLen:]
+ p.RetrySourceConnectionID = &connID
+ case resetStreamAtParameterID:
+ if paramLen != 0 {
+ return fmt.Errorf("wrong length for reset_stream_at: %d (expected empty)", paramLen)
+ }
+ p.EnableResetStreamAt = true
+ default:
+ b = b[paramLen:]
+ }
+ }
+
+ // min_ack_delay must be less or equal to max_ack_delay
+ if p.MinAckDelay != nil && *p.MinAckDelay > p.MaxAckDelay {
+ return fmt.Errorf("min_ack_delay (%s) is greater than max_ack_delay (%s)", *p.MinAckDelay, p.MaxAckDelay)
+ }
+ if !fromSessionTicket {
+ if sentBy == protocol.PerspectiveServer && !readOriginalDestinationConnectionID {
+ return errors.New("missing original_destination_connection_id")
+ }
+ if p.MaxUDPPayloadSize == 0 {
+ p.MaxUDPPayloadSize = protocol.MaxByteCount
+ }
+ if !readInitialSourceConnectionID {
+ return errors.New("missing initial_source_connection_id")
+ }
+ }
+
+ // check that every transport parameter was sent at most once
+ slices.SortFunc(parameterIDs, func(a, b transportParameterID) int {
+ if a < b {
+ return -1
+ }
+ return 1
+ })
+ for i := 0; i < len(parameterIDs)-1; i++ {
+ if parameterIDs[i] == parameterIDs[i+1] {
+ return fmt.Errorf("received duplicate transport parameter %#x", parameterIDs[i])
+ }
+ }
+
+ return nil
+}
+
+func (p *TransportParameters) readPreferredAddress(b []byte, expectedLen int) error {
+ remainingLen := len(b)
+ pa := &PreferredAddress{}
+ if len(b) < 4+2+16+2+1 {
+ return io.EOF
+ }
+ var ipv4 [4]byte
+ copy(ipv4[:], b[:4])
+ port4 := binary.BigEndian.Uint16(b[4:])
+ b = b[4+2:]
+ if port4 != 0 && ipv4 != [4]byte{} {
+ pa.IPv4 = netip.AddrPortFrom(netip.AddrFrom4(ipv4), port4)
+ }
+ var ipv6 [16]byte
+ copy(ipv6[:], b[:16])
+ port6 := binary.BigEndian.Uint16(b[16:])
+ if port6 != 0 && ipv6 != [16]byte{} {
+ pa.IPv6 = netip.AddrPortFrom(netip.AddrFrom16(ipv6), port6)
+ }
+ b = b[16+2:]
+ connIDLen := int(b[0])
+ b = b[1:]
+ if connIDLen == 0 || connIDLen > protocol.MaxConnIDLen {
+ return fmt.Errorf("invalid connection ID length: %d", connIDLen)
+ }
+ if len(b) < connIDLen+len(pa.StatelessResetToken) {
+ return io.EOF
+ }
+ pa.ConnectionID = protocol.ParseConnectionID(b[:connIDLen])
+ b = b[connIDLen:]
+ copy(pa.StatelessResetToken[:], b)
+ b = b[len(pa.StatelessResetToken):]
+ if bytesRead := remainingLen - len(b); bytesRead != expectedLen {
+ return fmt.Errorf("expected preferred_address to be %d long, read %d bytes", expectedLen, bytesRead)
+ }
+ p.PreferredAddress = pa
+ return nil
+}
+
+func (p *TransportParameters) readNumericTransportParameter(b []byte, paramID transportParameterID, expectedLen int) error {
+ val, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return fmt.Errorf("error while reading transport parameter %d: %s", paramID, err)
+ }
+ if l != expectedLen {
+ return fmt.Errorf("inconsistent transport parameter length for transport parameter %#x", paramID)
+ }
+ //nolint:exhaustive // This only covers the numeric transport parameters.
+ switch paramID {
+ case initialMaxStreamDataBidiLocalParameterID:
+ p.InitialMaxStreamDataBidiLocal = protocol.ByteCount(val)
+ case initialMaxStreamDataBidiRemoteParameterID:
+ p.InitialMaxStreamDataBidiRemote = protocol.ByteCount(val)
+ case initialMaxStreamDataUniParameterID:
+ p.InitialMaxStreamDataUni = protocol.ByteCount(val)
+ case initialMaxDataParameterID:
+ p.InitialMaxData = protocol.ByteCount(val)
+ case initialMaxStreamsBidiParameterID:
+ p.MaxBidiStreamNum = protocol.StreamNum(val)
+ if p.MaxBidiStreamNum > protocol.MaxStreamCount {
+ return fmt.Errorf("initial_max_streams_bidi too large: %d (maximum %d)", p.MaxBidiStreamNum, protocol.MaxStreamCount)
+ }
+ case initialMaxStreamsUniParameterID:
+ p.MaxUniStreamNum = protocol.StreamNum(val)
+ if p.MaxUniStreamNum > protocol.MaxStreamCount {
+ return fmt.Errorf("initial_max_streams_uni too large: %d (maximum %d)", p.MaxUniStreamNum, protocol.MaxStreamCount)
+ }
+ case maxIdleTimeoutParameterID:
+ p.MaxIdleTimeout = max(protocol.MinRemoteIdleTimeout, time.Duration(val)*time.Millisecond)
+ case maxUDPPayloadSizeParameterID:
+ if val < 1200 {
+ return fmt.Errorf("invalid value for max_udp_payload_size: %d (minimum 1200)", val)
+ }
+ p.MaxUDPPayloadSize = protocol.ByteCount(val)
+ case ackDelayExponentParameterID:
+ if val > protocol.MaxAckDelayExponent {
+ return fmt.Errorf("invalid value for ack_delay_exponent: %d (maximum %d)", val, protocol.MaxAckDelayExponent)
+ }
+ p.AckDelayExponent = uint8(val)
+ case maxAckDelayParameterID:
+ if val > uint64(protocol.MaxMaxAckDelay/time.Millisecond) {
+ return fmt.Errorf("invalid value for max_ack_delay: %dms (maximum %dms)", val, protocol.MaxMaxAckDelay/time.Millisecond)
+ }
+ p.MaxAckDelay = time.Duration(val) * time.Millisecond
+ case activeConnectionIDLimitParameterID:
+ if val < 2 {
+ return fmt.Errorf("invalid value for active_connection_id_limit: %d (minimum 2)", val)
+ }
+ p.ActiveConnectionIDLimit = val
+ case maxDatagramFrameSizeParameterID:
+ p.MaxDatagramFrameSize = protocol.ByteCount(val)
+ case minAckDelayParameterID:
+ mad := time.Duration(val) * time.Microsecond
+ if mad < 0 {
+ mad = math.MaxInt64
+ }
+ p.MinAckDelay = &mad
+ default:
+ return fmt.Errorf("TransportParameter BUG: transport parameter %d not found", paramID)
+ }
+ return nil
+}
+
+// Marshal the transport parameters
+func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
+ // Typical Transport Parameters consume around 110 bytes, depending on the exact values,
+ // especially the lengths of the Connection IDs.
+ // Allocate 256 bytes, so we won't have to grow the slice in any case.
+ b := make([]byte, 0, 256)
+
+ // add a greased value
+ random := make([]byte, 18)
+ rand.Read(random)
+ b = quicvarint.Append(b, 27+31*uint64(random[0]))
+ length := random[1] % 16
+ b = quicvarint.Append(b, uint64(length))
+ b = append(b, random[2:2+length]...)
+
+ // initial_max_stream_data_bidi_local
+ b = p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
+ // initial_max_stream_data_bidi_remote
+ b = p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
+ // initial_max_stream_data_uni
+ b = p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
+ // initial_max_data
+ b = p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
+ // initial_max_bidi_streams
+ b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
+ // initial_max_uni_streams
+ b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
+ // idle_timeout
+ b = p.marshalVarintParam(b, maxIdleTimeoutParameterID, uint64(p.MaxIdleTimeout/time.Millisecond))
+ // max_udp_payload_size
+ if p.MaxUDPPayloadSize > 0 {
+ b = p.marshalVarintParam(b, maxUDPPayloadSizeParameterID, uint64(p.MaxUDPPayloadSize))
+ }
+ // max_ack_delay
+ // Only send it if is different from the default value.
+ if p.MaxAckDelay != protocol.DefaultMaxAckDelay {
+ b = p.marshalVarintParam(b, maxAckDelayParameterID, uint64(p.MaxAckDelay/time.Millisecond))
+ }
+ // ack_delay_exponent
+ // Only send it if is different from the default value.
+ if p.AckDelayExponent != protocol.DefaultAckDelayExponent {
+ b = p.marshalVarintParam(b, ackDelayExponentParameterID, uint64(p.AckDelayExponent))
+ }
+ // disable_active_migration
+ if p.DisableActiveMigration {
+ b = quicvarint.Append(b, uint64(disableActiveMigrationParameterID))
+ b = quicvarint.Append(b, 0)
+ }
+ if pers == protocol.PerspectiveServer {
+ // stateless_reset_token
+ if p.StatelessResetToken != nil {
+ b = quicvarint.Append(b, uint64(statelessResetTokenParameterID))
+ b = quicvarint.Append(b, 16)
+ b = append(b, p.StatelessResetToken[:]...)
+ }
+ // original_destination_connection_id
+ b = quicvarint.Append(b, uint64(originalDestinationConnectionIDParameterID))
+ b = quicvarint.Append(b, uint64(p.OriginalDestinationConnectionID.Len()))
+ b = append(b, p.OriginalDestinationConnectionID.Bytes()...)
+ // preferred_address
+ if p.PreferredAddress != nil {
+ b = quicvarint.Append(b, uint64(preferredAddressParameterID))
+ b = quicvarint.Append(b, 4+2+16+2+1+uint64(p.PreferredAddress.ConnectionID.Len())+16)
+ if p.PreferredAddress.IPv4.IsValid() {
+ ipv4 := p.PreferredAddress.IPv4.Addr().As4()
+ b = append(b, ipv4[:]...)
+ b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv4.Port())
+ } else {
+ b = append(b, make([]byte, 6)...)
+ }
+ if p.PreferredAddress.IPv6.IsValid() {
+ ipv6 := p.PreferredAddress.IPv6.Addr().As16()
+ b = append(b, ipv6[:]...)
+ b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv6.Port())
+ } else {
+ b = append(b, make([]byte, 18)...)
+ }
+ b = append(b, uint8(p.PreferredAddress.ConnectionID.Len()))
+ b = append(b, p.PreferredAddress.ConnectionID.Bytes()...)
+ b = append(b, p.PreferredAddress.StatelessResetToken[:]...)
+ }
+ }
+ // active_connection_id_limit
+ if p.ActiveConnectionIDLimit != protocol.DefaultActiveConnectionIDLimit {
+ b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
+ }
+ // initial_source_connection_id
+ b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID))
+ b = quicvarint.Append(b, uint64(p.InitialSourceConnectionID.Len()))
+ b = append(b, p.InitialSourceConnectionID.Bytes()...)
+ // retry_source_connection_id
+ if pers == protocol.PerspectiveServer && p.RetrySourceConnectionID != nil {
+ b = quicvarint.Append(b, uint64(retrySourceConnectionIDParameterID))
+ b = quicvarint.Append(b, uint64(p.RetrySourceConnectionID.Len()))
+ b = append(b, p.RetrySourceConnectionID.Bytes()...)
+ }
+ // QUIC datagrams
+ if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
+ b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
+ }
+ // QUIC Stream Resets with Partial Delivery
+ if p.EnableResetStreamAt {
+ b = quicvarint.Append(b, uint64(resetStreamAtParameterID))
+ b = quicvarint.Append(b, 0)
+ }
+ if p.MinAckDelay != nil {
+ b = p.marshalVarintParam(b, minAckDelayParameterID, uint64(*p.MinAckDelay/time.Microsecond))
+ }
+
+ if pers == protocol.PerspectiveClient && len(AdditionalTransportParametersClient) > 0 {
+ for k, v := range AdditionalTransportParametersClient {
+ b = quicvarint.Append(b, k)
+ b = quicvarint.Append(b, uint64(len(v)))
+ b = append(b, v...)
+ }
+ }
+
+ return b
+}
+
+func (p *TransportParameters) marshalVarintParam(b []byte, id transportParameterID, val uint64) []byte {
+ b = quicvarint.Append(b, uint64(id))
+ b = quicvarint.Append(b, uint64(quicvarint.Len(val)))
+ return quicvarint.Append(b, val)
+}
+
+// MarshalForSessionTicket marshals the transport parameters we save in the session ticket.
+// When sending a 0-RTT enabled TLS session tickets, we need to save the transport parameters.
+// The client will remember the transport parameters used in the last session,
+// and apply those to the 0-RTT data it sends.
+// Saving the transport parameters in the ticket gives the server the option to reject 0-RTT
+// if the transport parameters changed.
+// Since the session ticket is encrypted, the serialization format is defined by the server.
+// For convenience, we use the same format that we also use for sending the transport parameters.
+func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte {
+ b = quicvarint.Append(b, transportParameterMarshalingVersion)
+
+ // initial_max_stream_data_bidi_local
+ b = p.marshalVarintParam(b, initialMaxStreamDataBidiLocalParameterID, uint64(p.InitialMaxStreamDataBidiLocal))
+ // initial_max_stream_data_bidi_remote
+ b = p.marshalVarintParam(b, initialMaxStreamDataBidiRemoteParameterID, uint64(p.InitialMaxStreamDataBidiRemote))
+ // initial_max_stream_data_uni
+ b = p.marshalVarintParam(b, initialMaxStreamDataUniParameterID, uint64(p.InitialMaxStreamDataUni))
+ // initial_max_data
+ b = p.marshalVarintParam(b, initialMaxDataParameterID, uint64(p.InitialMaxData))
+ // initial_max_bidi_streams
+ b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum))
+ // initial_max_uni_streams
+ b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum))
+ // active_connection_id_limit
+ b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
+ // max_datagram_frame_size
+ if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
+ b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize))
+ }
+ // reset_stream_at
+ if p.EnableResetStreamAt {
+ b = quicvarint.Append(b, uint64(resetStreamAtParameterID))
+ b = quicvarint.Append(b, 0)
+ }
+ return b
+}
+
+// UnmarshalFromSessionTicket unmarshals transport parameters from a session ticket.
+func (p *TransportParameters) UnmarshalFromSessionTicket(b []byte) error {
+ version, l, err := quicvarint.Parse(b)
+ if err != nil {
+ return err
+ }
+ if version != transportParameterMarshalingVersion {
+ return fmt.Errorf("unknown transport parameter marshaling version: %d", version)
+ }
+ return p.unmarshal(b[l:], protocol.PerspectiveServer, true)
+}
+
+// ValidFor0RTT checks if the transport parameters match those saved in the session ticket.
+func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool {
+ if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
+ return false
+ }
+ return p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
+ p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote &&
+ p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni &&
+ p.InitialMaxData >= saved.InitialMaxData &&
+ p.MaxBidiStreamNum >= saved.MaxBidiStreamNum &&
+ p.MaxUniStreamNum >= saved.MaxUniStreamNum &&
+ p.ActiveConnectionIDLimit == saved.ActiveConnectionIDLimit
+}
+
+// ValidForUpdate checks that the new transport parameters don't reduce limits after resuming a 0-RTT connection.
+// It is only used on the client side.
+func (p *TransportParameters) ValidForUpdate(saved *TransportParameters) bool {
+ if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) {
+ return false
+ }
+ return p.ActiveConnectionIDLimit >= saved.ActiveConnectionIDLimit &&
+ p.InitialMaxData >= saved.InitialMaxData &&
+ p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal &&
+ p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote &&
+ p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni &&
+ p.MaxBidiStreamNum >= saved.MaxBidiStreamNum &&
+ p.MaxUniStreamNum >= saved.MaxUniStreamNum
+}
+
+// String returns a string representation, intended for logging.
+func (p *TransportParameters) String() string {
+ logString := "&wire.TransportParameters{OriginalDestinationConnectionID: %s, InitialSourceConnectionID: %s, "
+ logParams := []any{p.OriginalDestinationConnectionID, p.InitialSourceConnectionID}
+ if p.RetrySourceConnectionID != nil {
+ logString += "RetrySourceConnectionID: %s, "
+ logParams = append(logParams, p.RetrySourceConnectionID)
+ }
+ logString += "InitialMaxStreamDataBidiLocal: %d, InitialMaxStreamDataBidiRemote: %d, InitialMaxStreamDataUni: %d, InitialMaxData: %d, MaxBidiStreamNum: %d, MaxUniStreamNum: %d, MaxIdleTimeout: %s, AckDelayExponent: %d, MaxAckDelay: %s, ActiveConnectionIDLimit: %d"
+ logParams = append(logParams, []any{p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreamNum, p.MaxUniStreamNum, p.MaxIdleTimeout, p.AckDelayExponent, p.MaxAckDelay, p.ActiveConnectionIDLimit}...)
+ if p.StatelessResetToken != nil { // the client never sends a stateless reset token
+ logString += ", StatelessResetToken: %#x"
+ logParams = append(logParams, *p.StatelessResetToken)
+ }
+ if p.MaxDatagramFrameSize != protocol.InvalidByteCount {
+ logString += ", MaxDatagramFrameSize: %d"
+ logParams = append(logParams, p.MaxDatagramFrameSize)
+ }
+ logString += ", EnableResetStreamAt: %t"
+ logParams = append(logParams, p.EnableResetStreamAt)
+ if p.MinAckDelay != nil {
+ logString += ", MinAckDelay: %s"
+ logParams = append(logParams, *p.MinAckDelay)
+ }
+ logString += "}"
+ return fmt.Sprintf(logString, logParams...)
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go b/vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go
new file mode 100644
index 00000000..407cb629
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go
@@ -0,0 +1,53 @@
+package wire
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "errors"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+// ParseVersionNegotiationPacket parses a Version Negotiation packet.
+func ParseVersionNegotiationPacket(b []byte) (dest, src protocol.ArbitraryLenConnectionID, _ []protocol.Version, _ error) {
+ n, dest, src, err := ParseArbitraryLenConnectionIDs(b)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ b = b[n:]
+ if len(b) == 0 {
+ //nolint:staticcheck // SA1021: the packet is called Version Negotiation packet
+ return nil, nil, nil, errors.New("Version Negotiation packet has empty version list")
+ }
+ if len(b)%4 != 0 {
+ //nolint:staticcheck // SA1021: the packet is called Version Negotiation packet
+ return nil, nil, nil, errors.New("Version Negotiation packet has a version list with an invalid length")
+ }
+ versions := make([]protocol.Version, len(b)/4)
+ for i := 0; len(b) > 0; i++ {
+ versions[i] = protocol.Version(binary.BigEndian.Uint32(b[:4]))
+ b = b[4:]
+ }
+ return dest, src, versions, nil
+}
+
+// ComposeVersionNegotiation composes a Version Negotiation
+func ComposeVersionNegotiation(destConnID, srcConnID protocol.ArbitraryLenConnectionID, versions []protocol.Version) []byte {
+ greasedVersions := protocol.GetGreasedVersions(versions)
+ expectedLen := 1 /* type byte */ + 4 /* version field */ + 1 /* dest connection ID length field */ + destConnID.Len() + 1 /* src connection ID length field */ + srcConnID.Len() + len(greasedVersions)*4
+ buf := make([]byte, 1+4 /* type byte and version field */, expectedLen)
+ _, _ = rand.Read(buf[:1]) // ignore the error here. It is not critical to have perfect random here.
+ // Setting the "QUIC bit" (0x40) is not required by the RFC,
+ // but it allows clients to demultiplex QUIC with a long list of other protocols.
+ // See RFC 9443 and https://mailarchive.ietf.org/arch/msg/quic/oR4kxGKY6mjtPC1CZegY1ED4beg/ for details.
+ buf[0] |= 0xc0
+ // The next 4 bytes are left at 0 (version number).
+ buf = append(buf, uint8(destConnID.Len()))
+ buf = append(buf, destConnID.Bytes()...)
+ buf = append(buf, uint8(srcConnID.Len()))
+ buf = append(buf, srcConnID.Bytes()...)
+ for _, v := range greasedVersions {
+ buf = binary.BigEndian.AppendUint32(buf, uint32(v))
+ }
+ return buf
+}
diff --git a/vendor/github.com/quic-go/quic-go/mockgen.go b/vendor/github.com/quic-go/quic-go/mockgen.go
new file mode 100644
index 00000000..65160d0d
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/mockgen.go
@@ -0,0 +1,47 @@
+//go:build gomock || generate
+
+package quic
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn"
+type SendConn = sendConn
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_raw_conn_test.go github.com/quic-go/quic-go RawConn"
+type RawConn = rawConn
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender"
+type Sender = sender
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender"
+type StreamSender = streamSender
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_control_frame_getter_test.go github.com/quic-go/quic-go StreamControlFrameGetter"
+type StreamControlFrameGetter = streamControlFrameGetter
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_frame_getter_test.go github.com/quic-go/quic-go StreamFrameGetter"
+type StreamFrameGetter = streamFrameGetter
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource"
+type FrameSource = frameSource
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource"
+type AckFrameSource = ackFrameSource
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager"
+type SealingManager = sealingManager
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unpacker_test.go github.com/quic-go/quic-go Unpacker"
+type Unpacker = unpacker
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packer_test.go github.com/quic-go/quic-go Packer"
+type Packer = packer
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_mtu_discoverer_test.go github.com/quic-go/quic-go MTUDiscoverer"
+type MTUDiscoverer = mtuDiscoverer
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner"
+type ConnRunner = connRunner
+
+//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler"
+type PacketHandler = packetHandler
+
+//go:generate sh -c "go tool mockgen -typed -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_packetconn_test.go net PacketConn"
diff --git a/vendor/github.com/quic-go/quic-go/mtu_discoverer.go b/vendor/github.com/quic-go/quic-go/mtu_discoverer.go
new file mode 100644
index 00000000..b2a75ae4
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/mtu_discoverer.go
@@ -0,0 +1,253 @@
+package quic
+
+import (
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+type mtuDiscoverer interface {
+ // Start starts the MTU discovery process.
+ // It's unnecessary to call ShouldSendProbe before that.
+ Start(now monotime.Time)
+ ShouldSendProbe(now monotime.Time) bool
+ CurrentSize() protocol.ByteCount
+ GetPing(now monotime.Time) (ping ackhandler.Frame, datagramSize protocol.ByteCount)
+ Reset(now monotime.Time, start, max protocol.ByteCount)
+}
+
+const (
+ // At some point, we have to stop searching for a higher MTU.
+ // We're happy to send a packet that's 10 bytes smaller than the actual MTU.
+ maxMTUDiff protocol.ByteCount = 20
+ // send a probe packet every mtuProbeDelay RTTs
+ mtuProbeDelay = 5
+ // Once maxLostMTUProbes MTU probe packets larger than a certain size are lost,
+ // MTU discovery won't probe for larger MTUs than this size.
+ // The algorithm used here is resilient to packet loss of (maxLostMTUProbes - 1) packets.
+ maxLostMTUProbes = 3
+)
+
+// The Path MTU is found by sending a larger packet every now and then.
+// If the packet is acknowledged, we conclude that the path supports this larger packet size.
+// If the packet is lost, this can mean one of two things:
+// 1. The path doesn't support this larger packet size, or
+// 2. The packet was lost due to packet loss, independent of its size.
+// The algorithm used here is resilient to packet loss of (maxLostMTUProbes - 1) packets.
+// For simplicty, the following example use maxLostMTUProbes = 2.
+//
+// Initialization:
+// |------------------------------------------------------------------------------|
+// min max
+//
+// The first MTU probe packet will have size (min+max)/2.
+// Assume that this packet is acknowledged. We can now move the min marker,
+// and continue the search in the resulting interval.
+//
+// If 1st probe packet acknowledged:
+// |---------------------------------------|--------------------------------------|
+// min max
+//
+// If 1st probe packet lost:
+// |---------------------------------------|--------------------------------------|
+// min lost[0] max
+//
+// We can't conclude that the path doesn't support this packet size, since the loss of the probe
+// packet could have been unrelated to the packet size. A larger probe packet will be sent later on.
+// After a loss, the next probe packet has size (min+lost[0])/2.
+// Now assume this probe packet is acknowledged:
+//
+// 2nd probe packet acknowledged:
+// |------------------|--------------------|--------------------------------------|
+// min lost[0] max
+//
+// First of all, we conclude that the path supports at least this MTU. That's progress!
+// Second, we probe a bit more aggressively with the next probe packet:
+// After an acknowledgement, the next probe packet has size (min+max)/2.
+// This means we'll send a packet larger than the first probe packet (which was lost).
+//
+// If 3rd probe packet acknowledged:
+// |-------------------------------------------------|----------------------------|
+// min max
+//
+// We can conclude that the loss of the 1st probe packet was not due to its size, and
+// continue searching in a much smaller interval now.
+//
+// If 3rd probe packet lost:
+// |------------------|--------------------|---------|----------------------------|
+// min lost[0] max
+//
+// Since in our example numPTOProbes = 2, and we lost 2 packets smaller than max, we
+// conclude that this packet size is not supported on the path, and reduce the maximum
+// value of the search interval.
+//
+// MTU discovery concludes once the interval min and max has been narrowed down to maxMTUDiff.
+
+type mtuFinder struct {
+ lastProbeTime monotime.Time
+
+ rttStats *utils.RTTStats
+
+ inFlight protocol.ByteCount // the size of the probe packet currently in flight. InvalidByteCount if none is in flight
+ min protocol.ByteCount
+
+ // on initialization, we treat the maximum size as the first "lost" packet
+ lost [maxLostMTUProbes]protocol.ByteCount
+ lastProbeWasLost bool
+
+ // The generation is used to ignore ACKs / losses for probe packets sent before a reset.
+ // Resets happen when the connection is migrated to a new path.
+ // We're therefore not concerned about overflows of this counter.
+ generation uint8
+
+ qlogger qlogwriter.Recorder
+}
+
+var _ mtuDiscoverer = &mtuFinder{}
+
+func newMTUDiscoverer(
+ rttStats *utils.RTTStats,
+ start, max protocol.ByteCount,
+ qlogger qlogwriter.Recorder,
+) *mtuFinder {
+ f := &mtuFinder{
+ inFlight: protocol.InvalidByteCount,
+ rttStats: rttStats,
+ qlogger: qlogger,
+ }
+ f.init(start, max)
+ return f
+}
+
+func (f *mtuFinder) init(start, max protocol.ByteCount) {
+ f.min = start
+ for i := range f.lost {
+ if i == 0 {
+ f.lost[i] = max
+ continue
+ }
+ f.lost[i] = protocol.InvalidByteCount
+ }
+}
+
+func (f *mtuFinder) done() bool {
+ return f.max()-f.min <= maxMTUDiff+1
+}
+
+func (f *mtuFinder) max() protocol.ByteCount {
+ for i, v := range f.lost {
+ if v == protocol.InvalidByteCount {
+ return f.lost[i-1]
+ }
+ }
+ return f.lost[len(f.lost)-1]
+}
+
+func (f *mtuFinder) Start(now monotime.Time) {
+ f.lastProbeTime = now // makes sure the first probe packet is not sent immediately
+}
+
+func (f *mtuFinder) ShouldSendProbe(now monotime.Time) bool {
+ if f.lastProbeTime.IsZero() {
+ return false
+ }
+ if f.inFlight != protocol.InvalidByteCount || f.done() {
+ return false
+ }
+ return !now.Before(f.lastProbeTime.Add(mtuProbeDelay * f.rttStats.SmoothedRTT()))
+}
+
+func (f *mtuFinder) GetPing(now monotime.Time) (ackhandler.Frame, protocol.ByteCount) {
+ var size protocol.ByteCount
+ if f.lastProbeWasLost {
+ size = (f.min + f.lost[0]) / 2
+ } else {
+ size = (f.min + f.max()) / 2
+ }
+ f.lastProbeTime = now
+ f.inFlight = size
+ return ackhandler.Frame{
+ Frame: &wire.PingFrame{},
+ Handler: &mtuFinderAckHandler{mtuFinder: f, generation: f.generation},
+ }, size
+}
+
+func (f *mtuFinder) CurrentSize() protocol.ByteCount {
+ return f.min
+}
+
+func (f *mtuFinder) Reset(now monotime.Time, start, max protocol.ByteCount) {
+ f.generation++
+ f.lastProbeTime = now
+ f.lastProbeWasLost = false
+ f.inFlight = protocol.InvalidByteCount
+ f.init(start, max)
+}
+
+type mtuFinderAckHandler struct {
+ *mtuFinder
+ generation uint8
+}
+
+var _ ackhandler.FrameHandler = &mtuFinderAckHandler{}
+
+func (h *mtuFinderAckHandler) OnAcked(wire.Frame) {
+ if h.generation != h.mtuFinder.generation {
+ // ACK for probe sent before reset
+ return
+ }
+ size := h.inFlight
+ if size == protocol.InvalidByteCount {
+ panic("OnAcked callback called although there's no MTU probe packet in flight")
+ }
+ h.inFlight = protocol.InvalidByteCount
+ h.min = size
+ h.lastProbeWasLost = false
+ // remove all values smaller than size from the lost array
+ var j int
+ for i, v := range h.lost {
+ if size < v {
+ j = i
+ break
+ }
+ }
+ if j > 0 {
+ for i := range len(h.lost) {
+ if i+j < len(h.lost) {
+ h.lost[i] = h.lost[i+j]
+ } else {
+ h.lost[i] = protocol.InvalidByteCount
+ }
+ }
+ }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.MTUUpdated{
+ Value: int(size),
+ Done: h.done(),
+ })
+ }
+}
+
+func (h *mtuFinderAckHandler) OnLost(wire.Frame) {
+ if h.generation != h.mtuFinder.generation {
+ // probe sent before reset received
+ return
+ }
+ size := h.inFlight
+ if size == protocol.InvalidByteCount {
+ panic("OnLost callback called although there's no MTU probe packet in flight")
+ }
+ h.lastProbeWasLost = true
+ h.inFlight = protocol.InvalidByteCount
+ for i, v := range h.lost {
+ if size < v {
+ copy(h.lost[i+1:], h.lost[i:])
+ h.lost[i] = size
+ break
+ }
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/oss-fuzz.sh b/vendor/github.com/quic-go/quic-go/oss-fuzz.sh
new file mode 100644
index 00000000..45df1569
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/oss-fuzz.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+set -euo pipefail
+
+echo "Build date (UTC): $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
+
+go version
+go env
+
+# fuzz qpack
+cd $GOPATH/src/github.com/quic-go/qpack
+git log -1 --format='qpack revision: %H (%cI) %s'
+compile_native_go_fuzzer_v2 github.com/quic-go/qpack FuzzDecode qpack_decode_fuzzer
+
+# fuzz quic-go
+cd $GOPATH/src/github.com/quic-go/quic-go/
+git log -1 --format='quic-go revision: %H (%cI) %s'
+
+build_native_go_fuzzer() {
+ local pkg=$1
+ local fuzz=$2
+ local name=$3
+ local corpus_dir="${WORK:-/tmp}/quic-go-seed-corpus/$name"
+ local corpus_zip="$OUT/${name}_seed_corpus.zip"
+
+ # FUZZ_CORPUS_DIR makes go-ossfuzz-seeds write each f.Add seed as a raw
+ # libFuzzer corpus file. OSS-Fuzz picks up _seed_corpus.zip from
+ # $OUT and unpacks it next to the fuzzer binary.
+ rm -rf "$corpus_dir"
+ mkdir -p "$corpus_dir"
+ FUZZ_CORPUS_DIR="$corpus_dir" go test "$pkg" -run "^${fuzz}$" -count=1 -v
+
+ rm -f "$corpus_zip"
+ corpus_files=$(find "$corpus_dir" -type f | wc -l)
+ echo "$name: generated $corpus_files corpus files"
+ if [[ "$corpus_files" -gt 0 ]]; then
+ (cd "$corpus_dir" && zip -q -r "$corpus_zip" .)
+ fi
+
+ compile_native_go_fuzzer_v2 "$pkg" "$fuzz" "$name"
+}
+
+build_native_go_fuzzer github.com/quic-go/quic-go/internal/wire FuzzFrames frame_fuzzer_v2
+build_native_go_fuzzer github.com/quic-go/quic-go/internal/wire FuzzTransportParameters transportparameter_fuzzer_v2
+build_native_go_fuzzer github.com/quic-go/quic-go/http3 FuzzFrameParser http3_frame_fuzzer
+build_native_go_fuzzer github.com/quic-go/quic-go/internal/wire FuzzHeaderParser header_fuzzer_v2
+build_native_go_fuzzer github.com/quic-go/quic-go/internal/handshake FuzzHandshake handshake_fuzzer_v2
+build_native_go_fuzzer github.com/quic-go/quic-go FuzzFrameSorter frame_sorter_fuzzer
+build_native_go_fuzzer github.com/quic-go/quic-go/http3 FuzzHeaderParsing http3_header_parsing_fuzzer
+
+# for debugging
+ls -al $OUT
diff --git a/vendor/github.com/quic-go/quic-go/packet_packer.go b/vendor/github.com/quic-go/quic-go/packet_packer.go
new file mode 100644
index 00000000..175d3c86
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/packet_packer.go
@@ -0,0 +1,1009 @@
+package quic
+
+import (
+ crand "crypto/rand"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "math/rand/v2"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/handshake"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+var errNothingToPack = errors.New("nothing to pack")
+
+type packer interface {
+ PackCoalescedPacket(onlyAck bool, maxPacketSize protocol.ByteCount, now monotime.Time, v protocol.Version) (*coalescedPacket, error)
+ PackAckOnlyPacket(maxPacketSize protocol.ByteCount, now monotime.Time, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)
+ AppendPacket(_ *packetBuffer, maxPacketSize protocol.ByteCount, now monotime.Time, v protocol.Version) (shortHeaderPacket, error)
+ PackPTOProbePacket(_ protocol.EncryptionLevel, _ protocol.ByteCount, addPingIfEmpty bool, now monotime.Time, v protocol.Version) (*coalescedPacket, error)
+ PackConnectionClose(*qerr.TransportError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
+ PackApplicationClose(*qerr.ApplicationError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error)
+ PackPathProbePacket(protocol.ConnectionID, []ackhandler.Frame, protocol.Version) (shortHeaderPacket, *packetBuffer, error)
+ PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.Version) (shortHeaderPacket, *packetBuffer, error)
+
+ SetToken([]byte)
+}
+
+type sealer interface {
+ handshake.LongHeaderSealer
+}
+
+type payload struct {
+ streamFrames []ackhandler.StreamFrame
+ frames []ackhandler.Frame
+ ack *wire.AckFrame
+ length protocol.ByteCount
+}
+
+type longHeaderPacket struct {
+ header *wire.ExtendedHeader
+ ack *wire.AckFrame
+ frames []ackhandler.Frame
+ streamFrames []ackhandler.StreamFrame // only used for 0-RTT packets
+
+ length protocol.ByteCount
+}
+
+type shortHeaderPacket struct {
+ PacketNumber protocol.PacketNumber
+ Frames []ackhandler.Frame
+ StreamFrames []ackhandler.StreamFrame
+ Ack *wire.AckFrame
+ Length protocol.ByteCount
+ IsPathMTUProbePacket bool
+ IsPathProbePacket bool
+
+ // used for logging
+ DestConnID protocol.ConnectionID
+ PacketNumberLen protocol.PacketNumberLen
+ KeyPhase protocol.KeyPhaseBit
+}
+
+func (p *shortHeaderPacket) IsAckEliciting() bool { return ackhandler.HasAckElicitingFrames(p.Frames) }
+
+type coalescedPacket struct {
+ buffer *packetBuffer
+ longHdrPackets []*longHeaderPacket
+ shortHdrPacket *shortHeaderPacket
+}
+
+// IsOnlyShortHeaderPacket says if this packet only contains a short header packet (and no long header packets).
+func (p *coalescedPacket) IsOnlyShortHeaderPacket() bool {
+ return len(p.longHdrPackets) == 0 && p.shortHdrPacket != nil
+}
+
+func (p *longHeaderPacket) EncryptionLevel() protocol.EncryptionLevel {
+ //nolint:exhaustive // Will never be called for Retry packets (and they don't have encrypted data).
+ switch p.header.Type {
+ case protocol.PacketTypeInitial:
+ return protocol.EncryptionInitial
+ case protocol.PacketTypeHandshake:
+ return protocol.EncryptionHandshake
+ case protocol.PacketType0RTT:
+ return protocol.Encryption0RTT
+ default:
+ panic("can't determine encryption level")
+ }
+}
+
+func (p *longHeaderPacket) IsAckEliciting() bool { return ackhandler.HasAckElicitingFrames(p.frames) }
+
+type packetNumberManager interface {
+ PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
+ PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
+}
+
+type sealingManager interface {
+ GetInitialSealer() (handshake.LongHeaderSealer, error)
+ GetHandshakeSealer() (handshake.LongHeaderSealer, error)
+ Get0RTTSealer() (handshake.LongHeaderSealer, error)
+ Get1RTTSealer() (handshake.ShortHeaderSealer, error)
+}
+
+type frameSource interface {
+ HasData() bool
+ Append([]ackhandler.Frame, []ackhandler.StreamFrame, protocol.ByteCount, monotime.Time, protocol.Version) ([]ackhandler.Frame, []ackhandler.StreamFrame, protocol.ByteCount)
+}
+
+type ackFrameSource interface {
+ GetAckFrame(_ protocol.EncryptionLevel, now monotime.Time, onlyIfQueued bool) *wire.AckFrame
+}
+
+type packetPacker struct {
+ srcConnID protocol.ConnectionID
+ getDestConnID func() protocol.ConnectionID
+
+ perspective protocol.Perspective
+ cryptoSetup sealingManager
+
+ initialStream *initialCryptoStream
+ handshakeStream *cryptoStream
+
+ token []byte
+
+ pnManager packetNumberManager
+ framer frameSource
+ acks ackFrameSource
+ datagramQueue *datagramQueue
+ retransmissionQueue *retransmissionQueue
+ rand rand.Rand
+
+ numNonAckElicitingAcks int
+}
+
+var _ packer = &packetPacker{}
+
+func newPacketPacker(
+ srcConnID protocol.ConnectionID,
+ getDestConnID func() protocol.ConnectionID,
+ initialStream *initialCryptoStream,
+ handshakeStream *cryptoStream,
+ packetNumberManager packetNumberManager,
+ retransmissionQueue *retransmissionQueue,
+ cryptoSetup sealingManager,
+ framer frameSource,
+ acks ackFrameSource,
+ datagramQueue *datagramQueue,
+ perspective protocol.Perspective,
+) *packetPacker {
+ var b [16]byte
+ _, _ = crand.Read(b[:])
+
+ return &packetPacker{
+ cryptoSetup: cryptoSetup,
+ getDestConnID: getDestConnID,
+ srcConnID: srcConnID,
+ initialStream: initialStream,
+ handshakeStream: handshakeStream,
+ retransmissionQueue: retransmissionQueue,
+ datagramQueue: datagramQueue,
+ perspective: perspective,
+ framer: framer,
+ acks: acks,
+ rand: *rand.New(rand.NewPCG(binary.BigEndian.Uint64(b[:8]), binary.BigEndian.Uint64(b[8:]))),
+ pnManager: packetNumberManager,
+ }
+}
+
+// PackConnectionClose packs a packet that closes the connection with a transport error.
+func (p *packetPacker) PackConnectionClose(e *qerr.TransportError, maxPacketSize protocol.ByteCount, v protocol.Version) (*coalescedPacket, error) {
+ var reason string
+ // don't send details of crypto errors
+ if !e.ErrorCode.IsCryptoError() {
+ reason = e.ErrorMessage
+ }
+ return p.packConnectionClose(false, uint64(e.ErrorCode), e.FrameType, reason, maxPacketSize, v)
+}
+
+// PackApplicationClose packs a packet that closes the connection with an application error.
+func (p *packetPacker) PackApplicationClose(e *qerr.ApplicationError, maxPacketSize protocol.ByteCount, v protocol.Version) (*coalescedPacket, error) {
+ return p.packConnectionClose(true, uint64(e.ErrorCode), 0, e.ErrorMessage, maxPacketSize, v)
+}
+
+func (p *packetPacker) packConnectionClose(
+ isApplicationError bool,
+ errorCode uint64,
+ frameType uint64,
+ reason string,
+ maxPacketSize protocol.ByteCount,
+ v protocol.Version,
+) (*coalescedPacket, error) {
+ var sealers [4]sealer
+ var hdrs [3]*wire.ExtendedHeader
+ var payloads [4]payload
+ var size protocol.ByteCount
+ var connID protocol.ConnectionID
+ var oneRTTPacketNumber protocol.PacketNumber
+ var oneRTTPacketNumberLen protocol.PacketNumberLen
+ var keyPhase protocol.KeyPhaseBit // only set for 1-RTT
+ var numLongHdrPackets uint8
+ encLevels := [4]protocol.EncryptionLevel{protocol.EncryptionInitial, protocol.EncryptionHandshake, protocol.Encryption0RTT, protocol.Encryption1RTT}
+ for i, encLevel := range encLevels {
+ if p.perspective == protocol.PerspectiveServer && encLevel == protocol.Encryption0RTT {
+ continue
+ }
+ ccf := &wire.ConnectionCloseFrame{
+ IsApplicationError: isApplicationError,
+ ErrorCode: errorCode,
+ FrameType: frameType,
+ ReasonPhrase: reason,
+ }
+ // don't send application errors in Initial or Handshake packets
+ if isApplicationError && (encLevel == protocol.EncryptionInitial || encLevel == protocol.EncryptionHandshake) {
+ ccf.IsApplicationError = false
+ ccf.ErrorCode = uint64(qerr.ApplicationErrorErrorCode)
+ ccf.ReasonPhrase = ""
+ }
+ pl := payload{
+ frames: []ackhandler.Frame{{Frame: ccf}},
+ length: ccf.Length(v),
+ }
+
+ var sealer sealer
+ var err error
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ sealer, err = p.cryptoSetup.GetInitialSealer()
+ case protocol.EncryptionHandshake:
+ sealer, err = p.cryptoSetup.GetHandshakeSealer()
+ case protocol.Encryption0RTT:
+ sealer, err = p.cryptoSetup.Get0RTTSealer()
+ case protocol.Encryption1RTT:
+ var s handshake.ShortHeaderSealer
+ s, err = p.cryptoSetup.Get1RTTSealer()
+ if err == nil {
+ keyPhase = s.KeyPhase()
+ }
+ sealer = s
+ }
+ if err == handshake.ErrKeysNotYetAvailable || err == handshake.ErrKeysDropped {
+ continue
+ }
+ if err != nil {
+ return nil, err
+ }
+ sealers[i] = sealer
+ var hdr *wire.ExtendedHeader
+ if encLevel == protocol.Encryption1RTT {
+ connID = p.getDestConnID()
+ oneRTTPacketNumber, oneRTTPacketNumberLen = p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
+ size += p.shortHeaderPacketLength(connID, oneRTTPacketNumberLen, pl)
+ } else {
+ hdr = p.getLongHeader(encLevel, v)
+ hdrs[i] = hdr
+ size += p.longHeaderPacketLength(hdr, pl, v) + protocol.ByteCount(sealer.Overhead())
+ numLongHdrPackets++
+ }
+ payloads[i] = pl
+ }
+ buffer := getPacketBuffer()
+ packet := &coalescedPacket{
+ buffer: buffer,
+ longHdrPackets: make([]*longHeaderPacket, 0, numLongHdrPackets),
+ }
+ for i, encLevel := range encLevels {
+ if sealers[i] == nil {
+ continue
+ }
+ if encLevel == protocol.Encryption1RTT {
+ shp, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, keyPhase, payloads[i], 0, maxPacketSize, sealers[i], false, v)
+ if err != nil {
+ return nil, err
+ }
+ packet.shortHdrPacket = &shp
+ } else {
+ var paddingLen protocol.ByteCount
+ if encLevel == protocol.EncryptionInitial {
+ paddingLen = p.initialPaddingLen(payloads[i].frames, size, maxPacketSize)
+ }
+ longHdrPacket, err := p.appendLongHeaderPacket(buffer, hdrs[i], payloads[i], paddingLen, encLevel, sealers[i], v)
+ if err != nil {
+ return nil, err
+ }
+ packet.longHdrPackets = append(packet.longHdrPackets, longHdrPacket)
+ }
+ }
+ return packet, nil
+}
+
+// longHeaderPacketLength calculates the length of a serialized long header packet.
+// It takes into account that packets that have a tiny payload need to be padded,
+// such that len(payload) + packet number len >= 4 + AEAD overhead
+func (p *packetPacker) longHeaderPacketLength(hdr *wire.ExtendedHeader, pl payload, v protocol.Version) protocol.ByteCount {
+ var paddingLen protocol.ByteCount
+ pnLen := protocol.ByteCount(hdr.PacketNumberLen)
+ if pl.length < 4-pnLen {
+ paddingLen = 4 - pnLen - pl.length
+ }
+ return hdr.GetLength(v) + pl.length + paddingLen
+}
+
+// shortHeaderPacketLength calculates the length of a serialized short header packet.
+// It takes into account that packets that have a tiny payload need to be padded,
+// such that len(payload) + packet number len >= 4 + AEAD overhead
+func (p *packetPacker) shortHeaderPacketLength(connID protocol.ConnectionID, pnLen protocol.PacketNumberLen, pl payload) protocol.ByteCount {
+ var paddingLen protocol.ByteCount
+ if pl.length < 4-protocol.ByteCount(pnLen) {
+ paddingLen = 4 - protocol.ByteCount(pnLen) - pl.length
+ }
+ return wire.ShortHeaderLen(connID, pnLen) + pl.length + paddingLen
+}
+
+// size is the expected size of the packet, if no padding was applied.
+func (p *packetPacker) initialPaddingLen(frames []ackhandler.Frame, currentSize, maxPacketSize protocol.ByteCount) protocol.ByteCount {
+ // For the server, only ack-eliciting Initial packets need to be padded.
+ if p.perspective == protocol.PerspectiveServer && !ackhandler.HasAckElicitingFrames(frames) {
+ return 0
+ }
+ if currentSize >= maxPacketSize {
+ return 0
+ }
+ return maxPacketSize - currentSize
+}
+
+// PackCoalescedPacket packs a new packet.
+// It packs an Initial / Handshake if there is data to send in these packet number spaces.
+// It should only be called before the handshake is confirmed.
+func (p *packetPacker) PackCoalescedPacket(onlyAck bool, maxSize protocol.ByteCount, now monotime.Time, v protocol.Version) (*coalescedPacket, error) {
+ var (
+ initialHdr, handshakeHdr, zeroRTTHdr *wire.ExtendedHeader
+ initialPayload, handshakePayload, zeroRTTPayload, oneRTTPayload payload
+ oneRTTPacketNumber protocol.PacketNumber
+ oneRTTPacketNumberLen protocol.PacketNumberLen
+ )
+ // Try packing an Initial packet.
+ initialSealer, err := p.cryptoSetup.GetInitialSealer()
+ if err != nil && err != handshake.ErrKeysDropped {
+ return nil, err
+ }
+ var size protocol.ByteCount
+ if initialSealer != nil {
+ initialHdr, initialPayload = p.maybeGetCryptoPacket(
+ maxSize-protocol.ByteCount(initialSealer.Overhead()),
+ protocol.EncryptionInitial,
+ now,
+ false,
+ onlyAck,
+ v,
+ )
+ if initialPayload.length > 0 {
+ size += p.longHeaderPacketLength(initialHdr, initialPayload, v) + protocol.ByteCount(initialSealer.Overhead())
+ }
+ }
+
+ // Add a Handshake packet.
+ var handshakeSealer sealer
+ if (onlyAck && size == 0) || (!onlyAck && size < maxSize-protocol.MinCoalescedPacketSize) {
+ var err error
+ handshakeSealer, err = p.cryptoSetup.GetHandshakeSealer()
+ if err != nil && err != handshake.ErrKeysDropped && err != handshake.ErrKeysNotYetAvailable {
+ return nil, err
+ }
+ if handshakeSealer != nil {
+ handshakeHdr, handshakePayload = p.maybeGetCryptoPacket(
+ maxSize-size-protocol.ByteCount(handshakeSealer.Overhead()),
+ protocol.EncryptionHandshake,
+ now,
+ false,
+ onlyAck,
+ v,
+ )
+ if handshakePayload.length > 0 {
+ s := p.longHeaderPacketLength(handshakeHdr, handshakePayload, v) + protocol.ByteCount(handshakeSealer.Overhead())
+ size += s
+ }
+ }
+ }
+
+ // Add a 0-RTT / 1-RTT packet.
+ var zeroRTTSealer sealer
+ var oneRTTSealer handshake.ShortHeaderSealer
+ var connID protocol.ConnectionID
+ var kp protocol.KeyPhaseBit
+ if (onlyAck && size == 0) || (!onlyAck && size < maxSize-protocol.MinCoalescedPacketSize) {
+ var err error
+ oneRTTSealer, err = p.cryptoSetup.Get1RTTSealer()
+ if err != nil && err != handshake.ErrKeysDropped && err != handshake.ErrKeysNotYetAvailable {
+ return nil, err
+ }
+ if err == nil { // 1-RTT
+ kp = oneRTTSealer.KeyPhase()
+ connID = p.getDestConnID()
+ oneRTTPacketNumber, oneRTTPacketNumberLen = p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
+ hdrLen := wire.ShortHeaderLen(connID, oneRTTPacketNumberLen)
+ oneRTTPayload = p.maybeGetShortHeaderPacket(oneRTTSealer, hdrLen, maxSize-size, onlyAck, now, v)
+ if oneRTTPayload.length > 0 {
+ size += p.shortHeaderPacketLength(connID, oneRTTPacketNumberLen, oneRTTPayload) + protocol.ByteCount(oneRTTSealer.Overhead())
+ }
+ } else if p.perspective == protocol.PerspectiveClient && !onlyAck { // 0-RTT packets can't contain ACK frames
+ var err error
+ zeroRTTSealer, err = p.cryptoSetup.Get0RTTSealer()
+ if err != nil && err != handshake.ErrKeysDropped && err != handshake.ErrKeysNotYetAvailable {
+ return nil, err
+ }
+ if zeroRTTSealer != nil {
+ zeroRTTHdr, zeroRTTPayload = p.maybeGetAppDataPacketFor0RTT(zeroRTTSealer, maxSize-size, now, v)
+ if zeroRTTPayload.length > 0 {
+ size += p.longHeaderPacketLength(zeroRTTHdr, zeroRTTPayload, v) + protocol.ByteCount(zeroRTTSealer.Overhead())
+ }
+ }
+ }
+ }
+
+ if initialPayload.length == 0 && handshakePayload.length == 0 && zeroRTTPayload.length == 0 && oneRTTPayload.length == 0 {
+ return nil, nil
+ }
+
+ buffer := getPacketBuffer()
+ packet := &coalescedPacket{
+ buffer: buffer,
+ longHdrPackets: make([]*longHeaderPacket, 0, 3),
+ }
+ if initialPayload.length > 0 {
+ padding := p.initialPaddingLen(initialPayload.frames, size, maxSize)
+ cont, err := p.appendLongHeaderPacket(buffer, initialHdr, initialPayload, padding, protocol.EncryptionInitial, initialSealer, v)
+ if err != nil {
+ return nil, err
+ }
+ packet.longHdrPackets = append(packet.longHdrPackets, cont)
+ }
+ if handshakePayload.length > 0 {
+ cont, err := p.appendLongHeaderPacket(buffer, handshakeHdr, handshakePayload, 0, protocol.EncryptionHandshake, handshakeSealer, v)
+ if err != nil {
+ return nil, err
+ }
+ packet.longHdrPackets = append(packet.longHdrPackets, cont)
+ }
+ if zeroRTTPayload.length > 0 {
+ longHdrPacket, err := p.appendLongHeaderPacket(buffer, zeroRTTHdr, zeroRTTPayload, 0, protocol.Encryption0RTT, zeroRTTSealer, v)
+ if err != nil {
+ return nil, err
+ }
+ packet.longHdrPackets = append(packet.longHdrPackets, longHdrPacket)
+ } else if oneRTTPayload.length > 0 {
+ shp, err := p.appendShortHeaderPacket(buffer, connID, oneRTTPacketNumber, oneRTTPacketNumberLen, kp, oneRTTPayload, 0, maxSize, oneRTTSealer, false, v)
+ if err != nil {
+ return nil, err
+ }
+ packet.shortHdrPacket = &shp
+ }
+ return packet, nil
+}
+
+// PackAckOnlyPacket packs a packet containing only an ACK in the application data packet number space.
+// It should be called after the handshake is confirmed.
+func (p *packetPacker) PackAckOnlyPacket(maxSize protocol.ByteCount, now monotime.Time, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) {
+ buf := getPacketBuffer()
+ packet, err := p.appendPacket(buf, true, maxSize, now, v)
+ return packet, buf, err
+}
+
+// AppendPacket packs a packet in the application data packet number space.
+// It should be called after the handshake is confirmed.
+func (p *packetPacker) AppendPacket(buf *packetBuffer, maxSize protocol.ByteCount, now monotime.Time, v protocol.Version) (shortHeaderPacket, error) {
+ return p.appendPacket(buf, false, maxSize, now, v)
+}
+
+func (p *packetPacker) appendPacket(
+ buf *packetBuffer,
+ onlyAck bool,
+ maxPacketSize protocol.ByteCount,
+ now monotime.Time,
+ v protocol.Version,
+) (shortHeaderPacket, error) {
+ sealer, err := p.cryptoSetup.Get1RTTSealer()
+ if err != nil {
+ return shortHeaderPacket{}, err
+ }
+ pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
+ connID := p.getDestConnID()
+ hdrLen := wire.ShortHeaderLen(connID, pnLen)
+ pl := p.maybeGetShortHeaderPacket(sealer, hdrLen, maxPacketSize, onlyAck, now, v)
+ if pl.length == 0 {
+ return shortHeaderPacket{}, errNothingToPack
+ }
+ kp := sealer.KeyPhase()
+
+ return p.appendShortHeaderPacket(buf, connID, pn, pnLen, kp, pl, 0, maxPacketSize, sealer, false, v)
+}
+
+func (p *packetPacker) maybeGetCryptoPacket(
+ maxPacketSize protocol.ByteCount,
+ encLevel protocol.EncryptionLevel,
+ now monotime.Time,
+ addPingIfEmpty bool,
+ onlyAck bool,
+ v protocol.Version,
+) (*wire.ExtendedHeader, payload) {
+ if onlyAck {
+ if ack := p.acks.GetAckFrame(encLevel, now, true); ack != nil {
+ hdr := p.getLongHeader(encLevel, v)
+ maxPacketSize -= hdr.GetLength(v)
+ ack.Truncate(maxPacketSize, v)
+ return hdr, payload{ack: ack, length: ack.Length(v)}
+ }
+ return nil, payload{length: 0}
+ }
+
+ var hasCryptoData func() bool
+ var popCryptoFrame func(maxLen protocol.ByteCount) *wire.CryptoFrame
+ //nolint:exhaustive // Initial and Handshake are the only two encryption levels here.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ hasCryptoData = p.initialStream.HasData
+ popCryptoFrame = p.initialStream.PopCryptoFrame
+ case protocol.EncryptionHandshake:
+ hasCryptoData = p.handshakeStream.HasData
+ popCryptoFrame = p.handshakeStream.PopCryptoFrame
+ }
+ handler := p.retransmissionQueue.AckHandler(encLevel)
+ hasRetransmission := p.retransmissionQueue.HasData(encLevel)
+
+ ack := p.acks.GetAckFrame(encLevel, now, !hasRetransmission && !hasCryptoData())
+ var pl payload
+ if !hasCryptoData() && !hasRetransmission && ack == nil {
+ if !addPingIfEmpty {
+ // nothing to send
+ return nil, payload{}
+ }
+ ping := &wire.PingFrame{}
+ pl.frames = append(pl.frames, ackhandler.Frame{Frame: ping, Handler: emptyHandler{}})
+ pl.length += ping.Length(v)
+ }
+
+ hdr := p.getLongHeader(encLevel, v)
+ maxPacketSize -= hdr.GetLength(v)
+
+ if ack != nil {
+ ack.Truncate(maxPacketSize, v)
+ pl.ack = ack
+ pl.length = ack.Length(v)
+ maxPacketSize -= pl.length
+ }
+ if hasRetransmission {
+ for {
+ frame := p.retransmissionQueue.GetFrame(encLevel, maxPacketSize, v)
+ if frame == nil {
+ break
+ }
+ pl.frames = append(pl.frames, ackhandler.Frame{
+ Frame: frame,
+ Handler: p.retransmissionQueue.AckHandler(encLevel),
+ })
+ frameLen := frame.Length(v)
+ pl.length += frameLen
+ maxPacketSize -= frameLen
+ }
+ return hdr, pl
+ } else {
+ for hasCryptoData() {
+ cf := popCryptoFrame(maxPacketSize)
+ if cf == nil {
+ break
+ }
+ pl.frames = append(pl.frames, ackhandler.Frame{Frame: cf, Handler: handler})
+ pl.length += cf.Length(v)
+ maxPacketSize -= cf.Length(v)
+ }
+ }
+ return hdr, pl
+}
+
+func (p *packetPacker) maybeGetAppDataPacketFor0RTT(sealer sealer, maxSize protocol.ByteCount, now monotime.Time, v protocol.Version) (*wire.ExtendedHeader, payload) {
+ if p.perspective != protocol.PerspectiveClient {
+ return nil, payload{}
+ }
+
+ hdr := p.getLongHeader(protocol.Encryption0RTT, v)
+ maxPayloadSize := maxSize - hdr.GetLength(v) - protocol.ByteCount(sealer.Overhead())
+ return hdr, p.maybeGetAppDataPacket(maxPayloadSize, false, false, now, v)
+}
+
+func (p *packetPacker) maybeGetShortHeaderPacket(
+ sealer handshake.ShortHeaderSealer,
+ hdrLen, maxPacketSize protocol.ByteCount,
+ onlyAck bool,
+ now monotime.Time,
+ v protocol.Version,
+) payload {
+ maxPayloadSize := maxPacketSize - hdrLen - protocol.ByteCount(sealer.Overhead())
+ return p.maybeGetAppDataPacket(maxPayloadSize, onlyAck, true, now, v)
+}
+
+func (p *packetPacker) maybeGetAppDataPacket(
+ maxPayloadSize protocol.ByteCount,
+ onlyAck, ackAllowed bool,
+ now monotime.Time,
+ v protocol.Version,
+) payload {
+ pl := p.composeNextPacket(maxPayloadSize, onlyAck, ackAllowed, now, v)
+
+ // check if we have anything to send
+ if len(pl.frames) == 0 && len(pl.streamFrames) == 0 {
+ if pl.ack == nil {
+ return payload{}
+ }
+ // the packet only contains an ACK
+ if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
+ ping := &wire.PingFrame{}
+ pl.frames = append(pl.frames, ackhandler.Frame{Frame: ping})
+ pl.length += ping.Length(v)
+ p.numNonAckElicitingAcks = 0
+ } else {
+ p.numNonAckElicitingAcks++
+ }
+ } else {
+ p.numNonAckElicitingAcks = 0
+ }
+ return pl
+}
+
+func (p *packetPacker) composeNextPacket(
+ maxPayloadSize protocol.ByteCount,
+ onlyAck, ackAllowed bool,
+ now monotime.Time,
+ v protocol.Version,
+) payload {
+ if onlyAck {
+ if ack := p.acks.GetAckFrame(protocol.Encryption1RTT, now, true); ack != nil {
+ ack.Truncate(maxPayloadSize, v)
+ return payload{ack: ack, length: ack.Length(v)}
+ }
+ return payload{}
+ }
+
+ hasData := p.framer.HasData()
+ hasRetransmission := p.retransmissionQueue.HasData(protocol.Encryption1RTT)
+
+ var pl payload
+ if ackAllowed {
+ if ack := p.acks.GetAckFrame(protocol.Encryption1RTT, now, !hasRetransmission && !hasData); ack != nil {
+ ack.Truncate(maxPayloadSize, v)
+ pl.ack = ack
+ pl.length += ack.Length(v)
+ }
+ }
+
+ if p.datagramQueue != nil {
+ if f := p.datagramQueue.Peek(); f != nil {
+ size := f.Length(v)
+ if size <= maxPayloadSize-pl.length { // DATAGRAM frame fits
+ pl.frames = append(pl.frames, ackhandler.Frame{Frame: f})
+ pl.length += size
+ p.datagramQueue.Pop()
+ } else if pl.ack == nil {
+ // The DATAGRAM frame doesn't fit, and the packet doesn't contain an ACK.
+ // Discard this frame. There's no point in retrying this in the next packet,
+ // as it's unlikely that the available packet size will increase.
+ p.datagramQueue.Pop()
+ }
+ // If the DATAGRAM frame was too large and the packet contained an ACK, we'll try to send it out later.
+ }
+ }
+
+ if pl.ack != nil && !hasData && !hasRetransmission {
+ return pl
+ }
+
+ if hasRetransmission {
+ for {
+ remainingLen := maxPayloadSize - pl.length
+ if remainingLen < protocol.MinStreamFrameSize {
+ break
+ }
+ f := p.retransmissionQueue.GetFrame(protocol.Encryption1RTT, remainingLen, v)
+ if f == nil {
+ break
+ }
+ pl.frames = append(pl.frames, ackhandler.Frame{Frame: f, Handler: p.retransmissionQueue.AckHandler(protocol.Encryption1RTT)})
+ pl.length += f.Length(v)
+ }
+ }
+
+ if hasData {
+ var lengthAdded protocol.ByteCount
+ startLen := len(pl.frames)
+ pl.frames, pl.streamFrames, lengthAdded = p.framer.Append(pl.frames, pl.streamFrames, maxPayloadSize-pl.length, now, v)
+ pl.length += lengthAdded
+ // add handlers for the control frames that were added
+ for i := startLen; i < len(pl.frames); i++ {
+ if pl.frames[i].Handler != nil {
+ continue
+ }
+ switch pl.frames[i].Frame.(type) {
+ case *wire.PathChallengeFrame, *wire.PathResponseFrame:
+ // Path probing is currently not supported, therefore we don't need to set the OnAcked callback yet.
+ // PATH_CHALLENGE and PATH_RESPONSE are never retransmitted.
+ default:
+ // we might be packing a 0-RTT packet, but we need to use the 1-RTT ack handler anyway
+ pl.frames[i].Handler = p.retransmissionQueue.AckHandler(protocol.Encryption1RTT)
+ }
+ }
+ }
+ return pl
+}
+
+func (p *packetPacker) PackPTOProbePacket(
+ encLevel protocol.EncryptionLevel,
+ maxPacketSize protocol.ByteCount,
+ addPingIfEmpty bool,
+ now monotime.Time,
+ v protocol.Version,
+) (*coalescedPacket, error) {
+ if encLevel == protocol.Encryption1RTT {
+ return p.packPTOProbePacket1RTT(maxPacketSize, addPingIfEmpty, now, v)
+ }
+
+ var sealer handshake.LongHeaderSealer
+ //nolint:exhaustive // Probe packets are never sent for 0-RTT.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ var err error
+ sealer, err = p.cryptoSetup.GetInitialSealer()
+ if err != nil {
+ return nil, err
+ }
+ case protocol.EncryptionHandshake:
+ var err error
+ sealer, err = p.cryptoSetup.GetHandshakeSealer()
+ if err != nil {
+ return nil, err
+ }
+ default:
+ panic("unknown encryption level")
+ }
+ hdr, pl := p.maybeGetCryptoPacket(
+ maxPacketSize-protocol.ByteCount(sealer.Overhead()),
+ encLevel,
+ now,
+ addPingIfEmpty,
+ false,
+ v,
+ )
+ if pl.length == 0 {
+ return nil, nil
+ }
+ buffer := getPacketBuffer()
+ packet := &coalescedPacket{buffer: buffer}
+ size := p.longHeaderPacketLength(hdr, pl, v) + protocol.ByteCount(sealer.Overhead())
+ var padding protocol.ByteCount
+ if encLevel == protocol.EncryptionInitial {
+ padding = p.initialPaddingLen(pl.frames, size, maxPacketSize)
+ }
+
+ longHdrPacket, err := p.appendLongHeaderPacket(buffer, hdr, pl, padding, encLevel, sealer, v)
+ if err != nil {
+ return nil, err
+ }
+ packet.longHdrPackets = []*longHeaderPacket{longHdrPacket}
+ return packet, nil
+}
+
+func (p *packetPacker) packPTOProbePacket1RTT(maxPacketSize protocol.ByteCount, addPingIfEmpty bool, now monotime.Time, v protocol.Version) (*coalescedPacket, error) {
+ s, err := p.cryptoSetup.Get1RTTSealer()
+ if err != nil {
+ return nil, err
+ }
+ kp := s.KeyPhase()
+ connID := p.getDestConnID()
+ pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
+ hdrLen := wire.ShortHeaderLen(connID, pnLen)
+ pl := p.maybeGetAppDataPacket(maxPacketSize-protocol.ByteCount(s.Overhead())-hdrLen, false, true, now, v)
+ if pl.length == 0 {
+ if !addPingIfEmpty {
+ return nil, nil
+ }
+ ping := &wire.PingFrame{}
+ pl.frames = append(pl.frames, ackhandler.Frame{Frame: ping, Handler: emptyHandler{}})
+ pl.length += ping.Length(v)
+ }
+ buffer := getPacketBuffer()
+ packet := &coalescedPacket{buffer: buffer}
+ shp, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, 0, maxPacketSize, s, false, v)
+ if err != nil {
+ return nil, err
+ }
+ packet.shortHdrPacket = &shp
+ return packet, nil
+}
+
+func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) {
+ pl := payload{
+ frames: []ackhandler.Frame{ping},
+ length: ping.Frame.Length(v),
+ }
+ buffer := getPacketBuffer()
+ s, err := p.cryptoSetup.Get1RTTSealer()
+ if err != nil {
+ return shortHeaderPacket{}, nil, err
+ }
+ connID := p.getDestConnID()
+ pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
+ padding := size - p.shortHeaderPacketLength(connID, pnLen, pl) - protocol.ByteCount(s.Overhead())
+ kp := s.KeyPhase()
+ packet, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, padding, size, s, true, v)
+ return packet, buffer, err
+}
+
+func (p *packetPacker) PackPathProbePacket(connID protocol.ConnectionID, frames []ackhandler.Frame, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) {
+ pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
+ buf := getPacketBuffer()
+ s, err := p.cryptoSetup.Get1RTTSealer()
+ if err != nil {
+ return shortHeaderPacket{}, nil, err
+ }
+ var l protocol.ByteCount
+ for _, f := range frames {
+ l += f.Frame.Length(v)
+ }
+ payload := payload{
+ frames: frames,
+ length: l,
+ }
+ padding := protocol.MinInitialPacketSize - p.shortHeaderPacketLength(connID, pnLen, payload) - protocol.ByteCount(s.Overhead())
+ packet, err := p.appendShortHeaderPacket(buf, connID, pn, pnLen, s.KeyPhase(), payload, padding, protocol.MinInitialPacketSize, s, false, v)
+ if err != nil {
+ return shortHeaderPacket{}, nil, err
+ }
+ packet.IsPathProbePacket = true
+ return packet, buf, err
+}
+
+func (p *packetPacker) getLongHeader(encLevel protocol.EncryptionLevel, v protocol.Version) *wire.ExtendedHeader {
+ pn, pnLen := p.pnManager.PeekPacketNumber(encLevel)
+ hdr := &wire.ExtendedHeader{
+ PacketNumber: pn,
+ PacketNumberLen: pnLen,
+ }
+ hdr.Version = v
+ hdr.SrcConnectionID = p.srcConnID
+ hdr.DestConnectionID = p.getDestConnID()
+
+ //nolint:exhaustive // 1-RTT packets are not long header packets.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ hdr.Type = protocol.PacketTypeInitial
+ hdr.Token = p.token
+ case protocol.EncryptionHandshake:
+ hdr.Type = protocol.PacketTypeHandshake
+ case protocol.Encryption0RTT:
+ hdr.Type = protocol.PacketType0RTT
+ }
+ return hdr
+}
+
+func (p *packetPacker) appendLongHeaderPacket(buffer *packetBuffer, header *wire.ExtendedHeader, pl payload, padding protocol.ByteCount, encLevel protocol.EncryptionLevel, sealer sealer, v protocol.Version) (*longHeaderPacket, error) {
+ var paddingLen protocol.ByteCount
+ pnLen := protocol.ByteCount(header.PacketNumberLen)
+ if pl.length < 4-pnLen {
+ paddingLen = 4 - pnLen - pl.length
+ }
+ paddingLen += padding
+ header.Length = pnLen + protocol.ByteCount(sealer.Overhead()) + pl.length + paddingLen
+
+ startLen := len(buffer.Data)
+ raw := buffer.Data[startLen:]
+ raw, err := header.Append(raw, v)
+ if err != nil {
+ return nil, err
+ }
+ payloadOffset := protocol.ByteCount(len(raw))
+
+ raw, err = p.appendPacketPayload(raw, pl, paddingLen, v)
+ if err != nil {
+ return nil, err
+ }
+ raw = p.encryptPacket(raw, sealer, header.PacketNumber, payloadOffset, pnLen)
+ buffer.Data = buffer.Data[:len(buffer.Data)+len(raw)]
+
+ if pn := p.pnManager.PopPacketNumber(encLevel); pn != header.PacketNumber {
+ return nil, fmt.Errorf("packetPacker BUG: Peeked and Popped packet numbers do not match: expected %d, got %d", pn, header.PacketNumber)
+ }
+ return &longHeaderPacket{
+ header: header,
+ ack: pl.ack,
+ frames: pl.frames,
+ streamFrames: pl.streamFrames,
+ length: protocol.ByteCount(len(raw)),
+ }, nil
+}
+
+func (p *packetPacker) appendShortHeaderPacket(
+ buffer *packetBuffer,
+ connID protocol.ConnectionID,
+ pn protocol.PacketNumber,
+ pnLen protocol.PacketNumberLen,
+ kp protocol.KeyPhaseBit,
+ pl payload,
+ padding, maxPacketSize protocol.ByteCount,
+ sealer sealer,
+ isMTUProbePacket bool,
+ v protocol.Version,
+) (shortHeaderPacket, error) {
+ var paddingLen protocol.ByteCount
+ if pl.length < 4-protocol.ByteCount(pnLen) {
+ paddingLen = 4 - protocol.ByteCount(pnLen) - pl.length
+ }
+ paddingLen += padding
+
+ startLen := len(buffer.Data)
+ raw := buffer.Data[startLen:]
+ raw, err := wire.AppendShortHeader(raw, connID, pn, pnLen, kp)
+ if err != nil {
+ return shortHeaderPacket{}, err
+ }
+ payloadOffset := protocol.ByteCount(len(raw))
+
+ raw, err = p.appendPacketPayload(raw, pl, paddingLen, v)
+ if err != nil {
+ return shortHeaderPacket{}, err
+ }
+ if !isMTUProbePacket {
+ if size := protocol.ByteCount(len(raw) + sealer.Overhead()); size > maxPacketSize {
+ return shortHeaderPacket{}, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, maxPacketSize)
+ }
+ }
+ raw = p.encryptPacket(raw, sealer, pn, payloadOffset, protocol.ByteCount(pnLen))
+ buffer.Data = buffer.Data[:len(buffer.Data)+len(raw)]
+
+ if newPN := p.pnManager.PopPacketNumber(protocol.Encryption1RTT); newPN != pn {
+ return shortHeaderPacket{}, fmt.Errorf("packetPacker BUG: Peeked and Popped packet numbers do not match: expected %d, got %d", pn, newPN)
+ }
+ return shortHeaderPacket{
+ PacketNumber: pn,
+ PacketNumberLen: pnLen,
+ KeyPhase: kp,
+ StreamFrames: pl.streamFrames,
+ Frames: pl.frames,
+ Ack: pl.ack,
+ Length: protocol.ByteCount(len(raw)),
+ DestConnID: connID,
+ IsPathMTUProbePacket: isMTUProbePacket,
+ }, nil
+}
+
+// appendPacketPayload serializes the payload of a packet into the raw byte slice.
+// It modifies the order of payload.frames.
+func (p *packetPacker) appendPacketPayload(raw []byte, pl payload, paddingLen protocol.ByteCount, v protocol.Version) ([]byte, error) {
+ payloadOffset := len(raw)
+ if pl.ack != nil {
+ var err error
+ raw, err = pl.ack.Append(raw, v)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if paddingLen > 0 {
+ raw = append(raw, make([]byte, paddingLen)...)
+ }
+ // Randomize the order of the control frames.
+ // This makes sure that the receiver doesn't rely on the order in which frames are packed.
+ if len(pl.frames) > 1 {
+ p.rand.Shuffle(len(pl.frames), func(i, j int) { pl.frames[i], pl.frames[j] = pl.frames[j], pl.frames[i] })
+ }
+ for _, f := range pl.frames {
+ var err error
+ raw, err = f.Frame.Append(raw, v)
+ if err != nil {
+ return nil, err
+ }
+ }
+ for _, f := range pl.streamFrames {
+ var err error
+ raw, err = f.Frame.Append(raw, v)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if payloadSize := protocol.ByteCount(len(raw)-payloadOffset) - paddingLen; payloadSize != pl.length {
+ return nil, fmt.Errorf("PacketPacker BUG: payload size inconsistent (expected %d, got %d bytes)", pl.length, payloadSize)
+ }
+ return raw, nil
+}
+
+func (p *packetPacker) encryptPacket(raw []byte, sealer sealer, pn protocol.PacketNumber, payloadOffset, pnLen protocol.ByteCount) []byte {
+ _ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], pn, raw[:payloadOffset])
+ raw = raw[:len(raw)+sealer.Overhead()]
+ // apply header protection
+ pnOffset := payloadOffset - pnLen
+ sealer.EncryptHeader(raw[pnOffset+4:pnOffset+4+16], &raw[0], raw[pnOffset:payloadOffset])
+ return raw
+}
+
+func (p *packetPacker) SetToken(token []byte) {
+ p.token = token
+}
+
+type emptyHandler struct{}
+
+var _ ackhandler.FrameHandler = emptyHandler{}
+
+func (emptyHandler) OnAcked(wire.Frame) {}
+func (emptyHandler) OnLost(wire.Frame) {}
diff --git a/vendor/github.com/quic-go/quic-go/packet_unpacker.go b/vendor/github.com/quic-go/quic-go/packet_unpacker.go
new file mode 100644
index 00000000..0729636e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/packet_unpacker.go
@@ -0,0 +1,222 @@
+package quic
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/handshake"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type headerDecryptor interface {
+ DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte)
+}
+
+type headerParseError struct {
+ err error
+}
+
+func (e *headerParseError) Unwrap() error {
+ return e.err
+}
+
+func (e *headerParseError) Error() string {
+ return e.err.Error()
+}
+
+type unpackedPacket struct {
+ hdr *wire.ExtendedHeader
+ encryptionLevel protocol.EncryptionLevel
+ data []byte
+}
+
+// The packetUnpacker unpacks QUIC packets.
+type packetUnpacker struct {
+ cs handshake.CryptoSetup
+
+ shortHdrConnIDLen int
+}
+
+var _ unpacker = &packetUnpacker{}
+
+func newPacketUnpacker(cs handshake.CryptoSetup, shortHdrConnIDLen int) *packetUnpacker {
+ return &packetUnpacker{
+ cs: cs,
+ shortHdrConnIDLen: shortHdrConnIDLen,
+ }
+}
+
+// UnpackLongHeader unpacks a Long Header packet.
+// If the reserved bits are invalid, the error is wire.ErrInvalidReservedBits.
+// If any other error occurred when parsing the header, the error is of type headerParseError.
+// If decrypting the payload fails for any reason, the error is the error returned by the AEAD.
+func (u *packetUnpacker) UnpackLongHeader(hdr *wire.Header, data []byte) (*unpackedPacket, error) {
+ var encLevel protocol.EncryptionLevel
+ var extHdr *wire.ExtendedHeader
+ var decrypted []byte
+ //nolint:exhaustive // Retry packets can't be unpacked.
+ switch hdr.Type {
+ case protocol.PacketTypeInitial:
+ encLevel = protocol.EncryptionInitial
+ opener, err := u.cs.GetInitialOpener()
+ if err != nil {
+ return nil, err
+ }
+ extHdr, decrypted, err = u.unpackLongHeaderPacket(opener, hdr, data)
+ if err != nil {
+ return nil, err
+ }
+ case protocol.PacketTypeHandshake:
+ encLevel = protocol.EncryptionHandshake
+ opener, err := u.cs.GetHandshakeOpener()
+ if err != nil {
+ return nil, err
+ }
+ extHdr, decrypted, err = u.unpackLongHeaderPacket(opener, hdr, data)
+ if err != nil {
+ return nil, err
+ }
+ case protocol.PacketType0RTT:
+ encLevel = protocol.Encryption0RTT
+ opener, err := u.cs.Get0RTTOpener()
+ if err != nil {
+ return nil, err
+ }
+ extHdr, decrypted, err = u.unpackLongHeaderPacket(opener, hdr, data)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ return nil, fmt.Errorf("unknown packet type: %s", hdr.Type)
+ }
+
+ if len(decrypted) == 0 {
+ return nil, &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "empty packet",
+ }
+ }
+
+ return &unpackedPacket{
+ hdr: extHdr,
+ encryptionLevel: encLevel,
+ data: decrypted,
+ }, nil
+}
+
+func (u *packetUnpacker) UnpackShortHeader(rcvTime monotime.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error) {
+ opener, err := u.cs.Get1RTTOpener()
+ if err != nil {
+ return 0, 0, 0, nil, err
+ }
+ pn, pnLen, kp, decrypted, err := u.unpackShortHeaderPacket(opener, rcvTime, data)
+ if err != nil {
+ return 0, 0, 0, nil, err
+ }
+ if len(decrypted) == 0 {
+ return 0, 0, 0, nil, &qerr.TransportError{
+ ErrorCode: qerr.ProtocolViolation,
+ ErrorMessage: "empty packet",
+ }
+ }
+ return pn, pnLen, kp, decrypted, nil
+}
+
+func (u *packetUnpacker) unpackLongHeaderPacket(opener handshake.LongHeaderOpener, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, []byte, error) {
+ extHdr, parseErr := u.unpackLongHeader(opener, hdr, data)
+ // If the reserved bits are set incorrectly, we still need to continue unpacking.
+ // This avoids a timing side-channel, which otherwise might allow an attacker
+ // to gain information about the header encryption.
+ if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
+ return nil, nil, parseErr
+ }
+ extHdrLen := extHdr.ParsedLen()
+ extHdr.PacketNumber = opener.DecodePacketNumber(extHdr.PacketNumber, extHdr.PacketNumberLen)
+ decrypted, err := opener.Open(data[extHdrLen:extHdrLen], data[extHdrLen:], extHdr.PacketNumber, data[:extHdrLen])
+ if err != nil {
+ return nil, nil, err
+ }
+ if parseErr != nil {
+ return nil, nil, parseErr
+ }
+ return extHdr, decrypted, nil
+}
+
+func (u *packetUnpacker) unpackShortHeaderPacket(opener handshake.ShortHeaderOpener, rcvTime monotime.Time, data []byte) (protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, []byte, error) {
+ l, pn, pnLen, kp, parseErr := u.unpackShortHeader(opener, data)
+ // If the reserved bits are set incorrectly, we still need to continue unpacking.
+ // This avoids a timing side-channel, which otherwise might allow an attacker
+ // to gain information about the header encryption.
+ if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
+ return 0, 0, 0, nil, &headerParseError{parseErr}
+ }
+ pn = opener.DecodePacketNumber(pn, pnLen)
+ decrypted, err := opener.Open(data[l:l], data[l:], rcvTime, pn, kp, data[:l])
+ if err != nil {
+ return 0, 0, 0, nil, err
+ }
+ return pn, pnLen, kp, decrypted, parseErr
+}
+
+func (u *packetUnpacker) unpackShortHeader(hd headerDecryptor, data []byte) (int, protocol.PacketNumber, protocol.PacketNumberLen, protocol.KeyPhaseBit, error) {
+ hdrLen := 1 /* first header byte */ + u.shortHdrConnIDLen
+ if len(data) < hdrLen+4+16 {
+ return 0, 0, 0, 0, fmt.Errorf("packet too small, expected at least 20 bytes after the header, got %d", len(data)-hdrLen)
+ }
+ origPNBytes := make([]byte, 4)
+ copy(origPNBytes, data[hdrLen:hdrLen+4])
+ // 2. decrypt the header, assuming a 4 byte packet number
+ hd.DecryptHeader(
+ data[hdrLen+4:hdrLen+4+16],
+ &data[0],
+ data[hdrLen:hdrLen+4],
+ )
+ // 3. parse the header (and learn the actual length of the packet number)
+ l, pn, pnLen, kp, parseErr := wire.ParseShortHeader(data, u.shortHdrConnIDLen)
+ if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
+ return l, pn, pnLen, kp, parseErr
+ }
+ // 4. if the packet number is shorter than 4 bytes, replace the remaining bytes with the copy we saved earlier
+ if pnLen != protocol.PacketNumberLen4 {
+ copy(data[hdrLen+int(pnLen):hdrLen+4], origPNBytes[int(pnLen):])
+ }
+ return l, pn, pnLen, kp, parseErr
+}
+
+// The error is either nil, a wire.ErrInvalidReservedBits or of type headerParseError.
+func (u *packetUnpacker) unpackLongHeader(hd headerDecryptor, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, error) {
+ extHdr, err := unpackLongHeader(hd, hdr, data)
+ if err != nil && err != wire.ErrInvalidReservedBits {
+ return nil, &headerParseError{err: err}
+ }
+ return extHdr, err
+}
+
+func unpackLongHeader(hd headerDecryptor, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, error) {
+ hdrLen := hdr.ParsedLen()
+ if protocol.ByteCount(len(data)) < hdrLen+4+16 {
+ return nil, fmt.Errorf("packet too small, expected at least 20 bytes after the header, got %d", protocol.ByteCount(len(data))-hdrLen)
+ }
+ // The packet number can be up to 4 bytes long, but we won't know the length until we decrypt it.
+ // 1. save a copy of the 4 bytes
+ origPNBytes := make([]byte, 4)
+ copy(origPNBytes, data[hdrLen:hdrLen+4])
+ // 2. decrypt the header, assuming a 4 byte packet number
+ hd.DecryptHeader(
+ data[hdrLen+4:hdrLen+4+16],
+ &data[0],
+ data[hdrLen:hdrLen+4],
+ )
+ // 3. parse the header (and learn the actual length of the packet number)
+ extHdr, parseErr := hdr.ParseExtended(data)
+ if parseErr != nil && parseErr != wire.ErrInvalidReservedBits {
+ return nil, parseErr
+ }
+ // 4. if the packet number is shorter than 4 bytes, replace the remaining bytes with the copy we saved earlier
+ if extHdr.PacketNumberLen != protocol.PacketNumberLen4 {
+ copy(data[extHdr.ParsedLen():hdrLen+4], origPNBytes[int(extHdr.PacketNumberLen):])
+ }
+ return extHdr, parseErr
+}
diff --git a/vendor/github.com/quic-go/quic-go/path_manager.go b/vendor/github.com/quic-go/quic-go/path_manager.go
new file mode 100644
index 00000000..dd188ea1
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/path_manager.go
@@ -0,0 +1,206 @@
+package quic
+
+import (
+ "crypto/rand"
+ "net"
+ "slices"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type pathID int64
+
+const invalidPathID pathID = -1
+
+// Maximum number of paths to keep track of.
+// If the peer probes another path (before the pathTimeout of an existing path expires),
+// this probing attempt is ignored.
+const maxPaths = 3
+
+// If no packet is received for a path for pathTimeout,
+// the path can be evicted when the peer probes another path.
+// This prevents an attacker from churning through paths by duplicating packets and
+// sending them with spoofed source addresses.
+const pathTimeout = 5 * time.Second
+
+type path struct {
+ id pathID
+ addr net.Addr
+ lastPacketTime monotime.Time
+ pathChallenge [8]byte
+ validated bool
+ rcvdNonProbing bool
+}
+
+type pathManager struct {
+ nextPathID pathID
+ // ordered by lastPacketTime, with the most recently used path at the end
+ paths []*path
+
+ getConnID func(pathID) (_ protocol.ConnectionID, ok bool)
+ retireConnID func(pathID)
+
+ logger utils.Logger
+}
+
+func newPathManager(
+ getConnID func(pathID) (_ protocol.ConnectionID, ok bool),
+ retireConnID func(pathID),
+ logger utils.Logger,
+) *pathManager {
+ return &pathManager{
+ paths: make([]*path, 0, maxPaths+1),
+ getConnID: getConnID,
+ retireConnID: retireConnID,
+ logger: logger,
+ }
+}
+
+// Returns a path challenge frame if one should be sent.
+// May return nil.
+func (pm *pathManager) HandlePacket(
+ remoteAddr net.Addr,
+ t monotime.Time,
+ pathChallenge *wire.PathChallengeFrame, // may be nil if the packet didn't contain a PATH_CHALLENGE
+ isNonProbing bool,
+) (_ protocol.ConnectionID, _ []ackhandler.Frame, shouldSwitch bool) {
+ var p *path
+ for i, path := range pm.paths {
+ if addrsEqual(path.addr, remoteAddr) {
+ p = path
+ p.lastPacketTime = t
+ // already sent a PATH_CHALLENGE for this path
+ if isNonProbing {
+ path.rcvdNonProbing = true
+ }
+ if pm.logger.Debug() {
+ pm.logger.Debugf("received packet for path %s that was already probed, validated: %t", remoteAddr, path.validated)
+ }
+ shouldSwitch = path.validated && path.rcvdNonProbing
+ if i != len(pm.paths)-1 {
+ // move the path to the end of the list
+ pm.paths = slices.Delete(pm.paths, i, i+1)
+ pm.paths = append(pm.paths, p)
+ }
+ if pathChallenge == nil {
+ return protocol.ConnectionID{}, nil, shouldSwitch
+ }
+ }
+ }
+
+ if len(pm.paths) >= maxPaths {
+ if pm.paths[0].lastPacketTime.Add(pathTimeout).After(t) {
+ if pm.logger.Debug() {
+ pm.logger.Debugf("received packet for previously unseen path %s, but already have %d paths", remoteAddr, len(pm.paths))
+ }
+ return protocol.ConnectionID{}, nil, shouldSwitch
+ }
+ // evict the oldest path, if the last packet was received more than pathTimeout ago
+ pm.retireConnID(pm.paths[0].id)
+ pm.paths = pm.paths[1:]
+ }
+
+ var pathID pathID
+ if p != nil {
+ pathID = p.id
+ } else {
+ pathID = pm.nextPathID
+ }
+
+ // previously unseen path, initiate path validation by sending a PATH_CHALLENGE
+ connID, ok := pm.getConnID(pathID)
+ if !ok {
+ pm.logger.Debugf("skipping validation of new path %s since no connection ID is available", remoteAddr)
+ return protocol.ConnectionID{}, nil, shouldSwitch
+ }
+
+ frames := make([]ackhandler.Frame, 0, 2)
+ if p == nil {
+ var pathChallengeData [8]byte
+ rand.Read(pathChallengeData[:])
+ p = &path{
+ id: pm.nextPathID,
+ addr: remoteAddr,
+ lastPacketTime: t,
+ rcvdNonProbing: isNonProbing,
+ pathChallenge: pathChallengeData,
+ }
+ pm.nextPathID++
+ pm.paths = append(pm.paths, p)
+ frames = append(frames, ackhandler.Frame{
+ Frame: &wire.PathChallengeFrame{Data: p.pathChallenge},
+ Handler: (*pathManagerAckHandler)(pm),
+ })
+ pm.logger.Debugf("enqueueing PATH_CHALLENGE for new path %s", remoteAddr)
+ }
+ if pathChallenge != nil {
+ frames = append(frames, ackhandler.Frame{
+ Frame: &wire.PathResponseFrame{Data: pathChallenge.Data},
+ Handler: (*pathManagerAckHandler)(pm),
+ })
+ }
+ return connID, frames, shouldSwitch
+}
+
+func (pm *pathManager) HandlePathResponseFrame(f *wire.PathResponseFrame) {
+ for _, p := range pm.paths {
+ if f.Data == p.pathChallenge {
+ // path validated
+ p.validated = true
+ pm.logger.Debugf("path %s validated", p.addr)
+ break
+ }
+ }
+}
+
+// SwitchToPath is called when the connection switches to a new path
+func (pm *pathManager) SwitchToPath(addr net.Addr) {
+ // retire all other paths
+ for _, path := range pm.paths {
+ if addrsEqual(path.addr, addr) {
+ pm.logger.Debugf("switching to path %d (%s)", path.id, addr)
+ continue
+ }
+ pm.retireConnID(path.id)
+ }
+ clear(pm.paths)
+ pm.paths = pm.paths[:0]
+}
+
+type pathManagerAckHandler pathManager
+
+var _ ackhandler.FrameHandler = &pathManagerAckHandler{}
+
+// Acknowledging the frame doesn't validate the path, only receiving the PATH_RESPONSE does.
+func (pm *pathManagerAckHandler) OnAcked(f wire.Frame) {}
+
+func (pm *pathManagerAckHandler) OnLost(f wire.Frame) {
+ pc, ok := f.(*wire.PathChallengeFrame)
+ if !ok {
+ return
+ }
+ for i, path := range pm.paths {
+ if path.pathChallenge == pc.Data {
+ pm.paths = slices.Delete(pm.paths, i, i+1)
+ pm.retireConnID(path.id)
+ break
+ }
+ }
+}
+
+func addrsEqual(addr1, addr2 net.Addr) bool {
+ if addr1 == nil || addr2 == nil {
+ return false
+ }
+ a1, ok1 := addr1.(*net.UDPAddr)
+ a2, ok2 := addr2.(*net.UDPAddr)
+ if ok1 && ok2 {
+ return a1.IP.Equal(a2.IP) && a1.Port == a2.Port
+ }
+ return addr1.String() == addr2.String()
+}
diff --git a/vendor/github.com/quic-go/quic-go/path_manager_outgoing.go b/vendor/github.com/quic-go/quic-go/path_manager_outgoing.go
new file mode 100644
index 00000000..78f68eea
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/path_manager_outgoing.go
@@ -0,0 +1,314 @@
+package quic
+
+import (
+ "context"
+ "crypto/rand"
+ "errors"
+ "slices"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+var (
+ // ErrPathClosed is returned when trying to switch to a path that has been closed.
+ ErrPathClosed = errors.New("path closed")
+ // ErrPathNotValidated is returned when trying to use a path before path probing has completed.
+ ErrPathNotValidated = errors.New("path not yet validated")
+)
+
+var errPathDoesNotExist = errors.New("path does not exist")
+
+// Path is a network path.
+type Path struct {
+ id pathID
+ pathManager *pathManagerOutgoing
+ tr *Transport
+ initialRTT time.Duration
+
+ enablePath func()
+ validated atomic.Bool
+ abandon chan struct{}
+}
+
+func (p *Path) Probe(ctx context.Context) error {
+ path := p.pathManager.addPath(p, p.enablePath)
+
+ p.pathManager.enqueueProbe(p)
+ nextProbeDur := p.initialRTT
+ var timer *time.Timer
+ var timerChan <-chan time.Time
+ for {
+ select {
+ case <-ctx.Done():
+ return context.Cause(ctx)
+ case <-path.Validated():
+ p.validated.Store(true)
+ return nil
+ case <-timerChan:
+ nextProbeDur *= 2 // exponential backoff
+ p.pathManager.enqueueProbe(p)
+ case <-path.ProbeSent():
+ case <-p.abandon:
+ return ErrPathClosed
+ }
+
+ if timer != nil {
+ timer.Stop()
+ }
+ timer = time.NewTimer(nextProbeDur)
+ timerChan = timer.C
+ }
+}
+
+// Switch switches the QUIC connection to this path.
+// It immediately stops sending on the old path, and sends on this new path.
+func (p *Path) Switch() error {
+ if err := p.pathManager.switchToPath(p.id); err != nil {
+ switch {
+ case errors.Is(err, ErrPathNotValidated):
+ return err
+ case errors.Is(err, errPathDoesNotExist) && !p.validated.Load():
+ select {
+ case <-p.abandon:
+ return ErrPathClosed
+ default:
+ return ErrPathNotValidated
+ }
+ default:
+ return ErrPathClosed
+ }
+ }
+ return nil
+}
+
+// Close abandons a path.
+// It is not possible to close the path that’s currently active.
+// After closing, it is not possible to probe this path again.
+func (p *Path) Close() error {
+ select {
+ case <-p.abandon:
+ return nil
+ default:
+ }
+
+ if err := p.pathManager.removePath(p.id); err != nil {
+ return err
+ }
+ close(p.abandon)
+ return nil
+}
+
+type pathOutgoing struct {
+ pathChallenges [][8]byte // length is implicitly limited by exponential backoff
+ tr *Transport
+ isValidated bool
+ probeSent chan struct{} // receives when a PATH_CHALLENGE is sent
+ validated chan struct{} // closed when the path the corresponding PATH_RESPONSE is received
+ enablePath func()
+}
+
+func (p *pathOutgoing) ProbeSent() <-chan struct{} { return p.probeSent }
+func (p *pathOutgoing) Validated() <-chan struct{} { return p.validated }
+
+type pathManagerOutgoing struct {
+ getConnID func(pathID) (_ protocol.ConnectionID, ok bool)
+ retireConnID func(pathID)
+ scheduleSending func()
+
+ mx sync.Mutex
+ activePath pathID
+ pathsToProbe []pathID
+ paths map[pathID]*pathOutgoing
+ nextPathID pathID
+ pathToSwitchTo *pathOutgoing
+}
+
+// newPathManagerOutgoing creates a new pathManagerOutgoing object. This
+// function must be side-effect free as it may be called multiple times for a
+// single connection.
+func newPathManagerOutgoing(
+ getConnID func(pathID) (_ protocol.ConnectionID, ok bool),
+ retireConnID func(pathID),
+ scheduleSending func(),
+) *pathManagerOutgoing {
+ return &pathManagerOutgoing{
+ activePath: 0, // at initialization time, we're guaranteed to be using the handshake path
+ nextPathID: 1,
+ getConnID: getConnID,
+ retireConnID: retireConnID,
+ scheduleSending: scheduleSending,
+ paths: make(map[pathID]*pathOutgoing, 4),
+ }
+}
+
+func (pm *pathManagerOutgoing) addPath(p *Path, enablePath func()) *pathOutgoing {
+ pm.mx.Lock()
+ defer pm.mx.Unlock()
+
+ // path might already exist, and just being re-probed
+ if existingPath, ok := pm.paths[p.id]; ok {
+ existingPath.validated = make(chan struct{})
+ return existingPath
+ }
+
+ path := &pathOutgoing{
+ tr: p.tr,
+ probeSent: make(chan struct{}, 1),
+ validated: make(chan struct{}),
+ enablePath: enablePath,
+ }
+ pm.paths[p.id] = path
+ return path
+}
+
+func (pm *pathManagerOutgoing) enqueueProbe(p *Path) {
+ pm.mx.Lock()
+ pm.pathsToProbe = append(pm.pathsToProbe, p.id)
+ pm.mx.Unlock()
+ pm.scheduleSending()
+}
+
+func (pm *pathManagerOutgoing) removePath(id pathID) error {
+ if err := pm.removePathImpl(id); err != nil {
+ return err
+ }
+ pm.scheduleSending()
+ return nil
+}
+
+func (pm *pathManagerOutgoing) removePathImpl(id pathID) error {
+ pm.mx.Lock()
+ defer pm.mx.Unlock()
+
+ if id == pm.activePath {
+ return errors.New("cannot close active path")
+ }
+ p, ok := pm.paths[id]
+ if !ok {
+ return nil
+ }
+ if len(p.pathChallenges) > 0 {
+ pm.retireConnID(id)
+ }
+ delete(pm.paths, id)
+ return nil
+}
+
+func (pm *pathManagerOutgoing) switchToPath(id pathID) error {
+ pm.mx.Lock()
+ defer pm.mx.Unlock()
+
+ p, ok := pm.paths[id]
+ if !ok {
+ return errPathDoesNotExist
+ }
+ if !p.isValidated {
+ return ErrPathNotValidated
+ }
+ pm.pathToSwitchTo = p
+ pm.activePath = id
+ return nil
+}
+
+func (pm *pathManagerOutgoing) NewPath(t *Transport, initialRTT time.Duration, enablePath func()) *Path {
+ pm.mx.Lock()
+ defer pm.mx.Unlock()
+
+ id := pm.nextPathID
+ pm.nextPathID++
+ return &Path{
+ pathManager: pm,
+ id: id,
+ tr: t,
+ enablePath: enablePath,
+ initialRTT: initialRTT,
+ abandon: make(chan struct{}),
+ }
+}
+
+func (pm *pathManagerOutgoing) NextPathToProbe() (_ protocol.ConnectionID, _ ackhandler.Frame, _ *Transport, hasPath bool) {
+ pm.mx.Lock()
+ defer pm.mx.Unlock()
+
+ var p *pathOutgoing
+ id := invalidPathID
+ for _, pID := range pm.pathsToProbe {
+ var ok bool
+ p, ok = pm.paths[pID]
+ if ok {
+ id = pID
+ break
+ }
+ // if the path doesn't exist in the map, it might have been abandoned
+ pm.pathsToProbe = pm.pathsToProbe[1:]
+ }
+ if id == invalidPathID {
+ return protocol.ConnectionID{}, ackhandler.Frame{}, nil, false
+ }
+
+ connID, ok := pm.getConnID(id)
+ if !ok {
+ return protocol.ConnectionID{}, ackhandler.Frame{}, nil, false
+ }
+
+ var b [8]byte
+ _, _ = rand.Read(b[:])
+ p.pathChallenges = append(p.pathChallenges, b)
+
+ pm.pathsToProbe = pm.pathsToProbe[1:]
+ p.enablePath()
+ select {
+ case p.probeSent <- struct{}{}:
+ default:
+ }
+ frame := ackhandler.Frame{
+ Frame: &wire.PathChallengeFrame{Data: b},
+ Handler: (*pathManagerOutgoingAckHandler)(pm),
+ }
+ return connID, frame, p.tr, true
+}
+
+func (pm *pathManagerOutgoing) HandlePathResponseFrame(f *wire.PathResponseFrame) {
+ pm.mx.Lock()
+ defer pm.mx.Unlock()
+
+ for _, p := range pm.paths {
+ if slices.Contains(p.pathChallenges, f.Data) {
+ // path validated
+ if !p.isValidated {
+ // make sure that duplicate PATH_RESPONSE frames are ignored
+ p.isValidated = true
+ p.pathChallenges = nil
+ close(p.validated)
+ }
+ break
+ }
+ }
+}
+
+func (pm *pathManagerOutgoing) ShouldSwitchPath() (*Transport, bool) {
+ pm.mx.Lock()
+ defer pm.mx.Unlock()
+
+ if pm.pathToSwitchTo == nil {
+ return nil, false
+ }
+ p := pm.pathToSwitchTo
+ pm.pathToSwitchTo = nil
+ return p.tr, true
+}
+
+type pathManagerOutgoingAckHandler pathManagerOutgoing
+
+var _ ackhandler.FrameHandler = &pathManagerOutgoingAckHandler{}
+
+// OnAcked is called when the PATH_CHALLENGE is acked.
+// This doesn't validate the path, only receiving the PATH_RESPONSE does.
+func (pm *pathManagerOutgoingAckHandler) OnAcked(wire.Frame) {}
+
+func (pm *pathManagerOutgoingAckHandler) OnLost(wire.Frame) {}
diff --git a/vendor/github.com/quic-go/quic-go/qlog/event.go b/vendor/github.com/quic-go/quic-go/qlog/event.go
new file mode 100644
index 00000000..83ca71f1
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlog/event.go
@@ -0,0 +1,849 @@
+package qlog
+
+import (
+ "fmt"
+ "net/netip"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/qlogwriter/jsontext"
+)
+
+func milliseconds(dur time.Duration) float64 { return float64(dur.Nanoseconds()) / 1e6 }
+
+type encoderHelper struct {
+ enc *jsontext.Encoder
+ err error
+}
+
+func (h *encoderHelper) WriteToken(t jsontext.Token) {
+ if h.err != nil {
+ return
+ }
+ h.err = h.enc.WriteToken(t)
+}
+
+type versions []Version
+
+func (v versions) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
+ for _, e := range v {
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", uint32(e))))
+ }
+ h.WriteToken(jsontext.EndArray)
+ return h.err
+}
+
+type RawInfo struct {
+ Length int // full packet length, including header and AEAD authentication tag
+ PayloadLength int // length of the packet payload, excluding AEAD tag
+}
+
+func (i RawInfo) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Uint(uint64(i.Length)))
+ if i.PayloadLength != 0 {
+ h.WriteToken(jsontext.String("payload_length"))
+ h.WriteToken(jsontext.Uint(uint64(i.PayloadLength)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type PathEndpointInfo struct {
+ IPv4 netip.AddrPort
+ IPv6 netip.AddrPort
+}
+
+func (p PathEndpointInfo) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if p.IPv4.IsValid() {
+ h.WriteToken(jsontext.String("ip_v4"))
+ h.WriteToken(jsontext.String(p.IPv4.Addr().String()))
+ h.WriteToken(jsontext.String("port_v4"))
+ h.WriteToken(jsontext.Int(int64(p.IPv4.Port())))
+ }
+ if p.IPv6.IsValid() {
+ h.WriteToken(jsontext.String("ip_v6"))
+ h.WriteToken(jsontext.String(p.IPv6.Addr().String()))
+ h.WriteToken(jsontext.String("port_v6"))
+ h.WriteToken(jsontext.Int(int64(p.IPv6.Port())))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type StartedConnection struct {
+ Local PathEndpointInfo
+ Remote PathEndpointInfo
+}
+
+func (e StartedConnection) Name() string { return "transport:connection_started" }
+
+func (e StartedConnection) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("local"))
+ if err := e.Local.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("remote"))
+ if err := e.Remote.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type VersionInformation struct {
+ ClientVersions, ServerVersions []Version
+ ChosenVersion Version
+}
+
+func (e VersionInformation) Name() string { return "transport:version_information" }
+
+func (e VersionInformation) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if len(e.ClientVersions) > 0 {
+ h.WriteToken(jsontext.String("client_versions"))
+ if err := versions(e.ClientVersions).encode(enc); err != nil {
+ return err
+ }
+ }
+ if len(e.ServerVersions) > 0 {
+ h.WriteToken(jsontext.String("server_versions"))
+ if err := versions(e.ServerVersions).encode(enc); err != nil {
+ return err
+ }
+ }
+ h.WriteToken(jsontext.String("chosen_version"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", uint32(e.ChosenVersion))))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type ConnectionClosed struct {
+ Initiator Initiator
+
+ ConnectionError *TransportErrorCode
+ ApplicationError *ApplicationErrorCode
+
+ Reason string
+
+ Trigger ConnectionCloseTrigger
+}
+
+func (e ConnectionClosed) Name() string { return "transport:connection_closed" }
+
+func (e ConnectionClosed) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("initiator"))
+ h.WriteToken(jsontext.String(string(e.Initiator)))
+ if e.ConnectionError != nil {
+ h.WriteToken(jsontext.String("connection_error"))
+ if e.ConnectionError.IsCryptoError() {
+ h.WriteToken(jsontext.String(fmt.Sprintf("crypto_error_%#x", uint16(*e.ConnectionError))))
+ } else {
+ switch *e.ConnectionError {
+ case qerr.NoError:
+ h.WriteToken(jsontext.String("no_error"))
+ case qerr.InternalError:
+ h.WriteToken(jsontext.String("internal_error"))
+ case qerr.ConnectionRefused:
+ h.WriteToken(jsontext.String("connection_refused"))
+ case qerr.FlowControlError:
+ h.WriteToken(jsontext.String("flow_control_error"))
+ case qerr.StreamLimitError:
+ h.WriteToken(jsontext.String("stream_limit_error"))
+ case qerr.StreamStateError:
+ h.WriteToken(jsontext.String("stream_state_error"))
+ case qerr.FinalSizeError:
+ h.WriteToken(jsontext.String("final_size_error"))
+ case qerr.FrameEncodingError:
+ h.WriteToken(jsontext.String("frame_encoding_error"))
+ case qerr.TransportParameterError:
+ h.WriteToken(jsontext.String("transport_parameter_error"))
+ case qerr.ConnectionIDLimitError:
+ h.WriteToken(jsontext.String("connection_id_limit_error"))
+ case qerr.ProtocolViolation:
+ h.WriteToken(jsontext.String("protocol_violation"))
+ case qerr.InvalidToken:
+ h.WriteToken(jsontext.String("invalid_token"))
+ case qerr.ApplicationErrorErrorCode:
+ h.WriteToken(jsontext.String("application_error"))
+ case qerr.CryptoBufferExceeded:
+ h.WriteToken(jsontext.String("crypto_buffer_exceeded"))
+ case qerr.KeyUpdateError:
+ h.WriteToken(jsontext.String("key_update_error"))
+ case qerr.AEADLimitReached:
+ h.WriteToken(jsontext.String("aead_limit_reached"))
+ case qerr.NoViablePathError:
+ h.WriteToken(jsontext.String("no_viable_path"))
+ default:
+ h.WriteToken(jsontext.String("unknown"))
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Uint(uint64(*e.ConnectionError)))
+ }
+ }
+ }
+ if e.ApplicationError != nil {
+ h.WriteToken(jsontext.String("application_error"))
+ h.WriteToken(jsontext.String("unknown"))
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Uint(uint64(*e.ApplicationError)))
+ }
+ if e.ConnectionError != nil || e.ApplicationError != nil {
+ h.WriteToken(jsontext.String("reason"))
+ h.WriteToken(jsontext.String(e.Reason))
+ }
+ if e.Trigger != "" {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(string(e.Trigger)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type PacketSent struct {
+ Header PacketHeader
+ Raw RawInfo
+ DatagramID DatagramID
+ Frames []Frame
+ ECN ECN
+ IsCoalesced bool
+ Trigger string
+ SupportedVersions []Version
+}
+
+func (e PacketSent) Name() string { return "transport:packet_sent" }
+
+func (e PacketSent) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ if e.DatagramID != 0 {
+ h.WriteToken(jsontext.String("datagram_id"))
+ h.WriteToken(jsontext.Uint(uint64(e.DatagramID)))
+ }
+ if len(e.Frames) > 0 {
+ h.WriteToken(jsontext.String("frames"))
+ if err := frames(e.Frames).encode(enc); err != nil {
+ return err
+ }
+ }
+ if e.IsCoalesced {
+ h.WriteToken(jsontext.String("is_coalesced"))
+ h.WriteToken(jsontext.True)
+ }
+ if e.ECN != ECNUnsupported {
+ h.WriteToken(jsontext.String("ecn"))
+ h.WriteToken(jsontext.String(string(e.ECN)))
+ }
+ if e.Trigger != "" {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type PacketReceived struct {
+ Header PacketHeader
+ Raw RawInfo
+ DatagramID DatagramID
+ Frames []Frame
+ ECN ECN
+ IsCoalesced bool
+ Trigger string
+}
+
+func (e PacketReceived) Name() string { return "transport:packet_received" }
+
+func (e PacketReceived) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ if e.DatagramID != 0 {
+ h.WriteToken(jsontext.String("datagram_id"))
+ h.WriteToken(jsontext.Uint(uint64(e.DatagramID)))
+ }
+ if len(e.Frames) > 0 {
+ h.WriteToken(jsontext.String("frames"))
+ if err := frames(e.Frames).encode(enc); err != nil {
+ return err
+ }
+ }
+ if e.IsCoalesced {
+ h.WriteToken(jsontext.String("is_coalesced"))
+ h.WriteToken(jsontext.True)
+ }
+ if e.ECN != ECNUnsupported {
+ h.WriteToken(jsontext.String("ecn"))
+ h.WriteToken(jsontext.String(string(e.ECN)))
+ }
+ if e.Trigger != "" {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type VersionNegotiationReceived struct {
+ Header PacketHeaderVersionNegotiation
+ SupportedVersions []Version
+}
+
+func (e VersionNegotiationReceived) Name() string { return "transport:packet_received" }
+
+func (e VersionNegotiationReceived) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("supported_versions"))
+ if err := versions(e.SupportedVersions).encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type VersionNegotiationSent struct {
+ Header PacketHeaderVersionNegotiation
+ SupportedVersions []Version
+}
+
+func (e VersionNegotiationSent) Name() string { return "transport:packet_sent" }
+
+func (e VersionNegotiationSent) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("supported_versions"))
+ if err := versions(e.SupportedVersions).encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type PacketBuffered struct {
+ Header PacketHeader
+ Raw RawInfo
+ DatagramID DatagramID
+}
+
+func (e PacketBuffered) Name() string { return "transport:packet_buffered" }
+
+func (e PacketBuffered) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ if e.DatagramID != 0 {
+ h.WriteToken(jsontext.String("datagram_id"))
+ h.WriteToken(jsontext.Uint(uint64(e.DatagramID)))
+ }
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("keys_unavailable"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// PacketDropped is the transport:packet_dropped event.
+type PacketDropped struct {
+ Header PacketHeader
+ Raw RawInfo
+ DatagramID DatagramID
+ Trigger PacketDropReason
+}
+
+func (e PacketDropped) Name() string { return "transport:packet_dropped" }
+
+func (e PacketDropped) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("raw"))
+ if err := e.Raw.encode(enc); err != nil {
+ return err
+ }
+ if e.DatagramID != 0 {
+ h.WriteToken(jsontext.String("datagram_id"))
+ h.WriteToken(jsontext.Uint(uint64(e.DatagramID)))
+ }
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(string(e.Trigger)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type MTUUpdated struct {
+ Value int
+ Done bool
+}
+
+func (e MTUUpdated) Name() string { return "recovery:mtu_updated" }
+
+func (e MTUUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("mtu"))
+ h.WriteToken(jsontext.Uint(uint64(e.Value)))
+ h.WriteToken(jsontext.String("done"))
+ h.WriteToken(jsontext.Bool(e.Done))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// MetricsUpdated logs RTT and congestion metrics as defined in the
+// recovery:metrics_updated event.
+// The PTO count is logged via PTOCountUpdated.
+type MetricsUpdated struct {
+ MinRTT time.Duration
+ SmoothedRTT time.Duration
+ LatestRTT time.Duration
+ RTTVariance time.Duration
+ CongestionWindow int
+ BytesInFlight int
+ PacketsInFlight int
+}
+
+func (e MetricsUpdated) Name() string { return "recovery:metrics_updated" }
+
+func (e MetricsUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if e.MinRTT != 0 {
+ h.WriteToken(jsontext.String("min_rtt"))
+ h.WriteToken(jsontext.Float(milliseconds(e.MinRTT)))
+ }
+ if e.SmoothedRTT != 0 {
+ h.WriteToken(jsontext.String("smoothed_rtt"))
+ h.WriteToken(jsontext.Float(milliseconds(e.SmoothedRTT)))
+ }
+ if e.LatestRTT != 0 {
+ h.WriteToken(jsontext.String("latest_rtt"))
+ h.WriteToken(jsontext.Float(milliseconds(e.LatestRTT)))
+ }
+ if e.RTTVariance != 0 {
+ h.WriteToken(jsontext.String("rtt_variance"))
+ h.WriteToken(jsontext.Float(milliseconds(e.RTTVariance)))
+ }
+ if e.CongestionWindow != 0 {
+ h.WriteToken(jsontext.String("congestion_window"))
+ h.WriteToken(jsontext.Uint(uint64(e.CongestionWindow)))
+ }
+ if e.BytesInFlight != 0 {
+ h.WriteToken(jsontext.String("bytes_in_flight"))
+ h.WriteToken(jsontext.Uint(uint64(e.BytesInFlight)))
+ }
+ if e.PacketsInFlight != 0 {
+ h.WriteToken(jsontext.String("packets_in_flight"))
+ h.WriteToken(jsontext.Uint(uint64(e.PacketsInFlight)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// PTOCountUpdated logs the pto_count value of the
+// recovery:metrics_updated event.
+type PTOCountUpdated struct {
+ PTOCount uint32
+}
+
+func (e PTOCountUpdated) Name() string { return "recovery:metrics_updated" }
+
+func (e PTOCountUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("pto_count"))
+ h.WriteToken(jsontext.Uint(uint64(e.PTOCount)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type PacketLost struct {
+ Header PacketHeader
+ Trigger PacketLossReason
+}
+
+func (e PacketLost) Name() string { return "recovery:packet_lost" }
+
+func (e PacketLost) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("header"))
+ if err := e.Header.encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(string(e.Trigger)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type SpuriousLoss struct {
+ EncryptionLevel protocol.EncryptionLevel
+ PacketNumber protocol.PacketNumber
+ PacketReordering uint64
+ TimeReordering time.Duration
+}
+
+func (e SpuriousLoss) Name() string { return "recovery:spurious_loss" }
+
+func (e SpuriousLoss) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("packet_number_space"))
+ h.WriteToken(jsontext.String(encLevelToPacketNumberSpace(e.EncryptionLevel)))
+ h.WriteToken(jsontext.String("packet_number"))
+ h.WriteToken(jsontext.Uint(uint64(e.PacketNumber)))
+ h.WriteToken(jsontext.String("reordering_packets"))
+ h.WriteToken(jsontext.Uint(e.PacketReordering))
+ h.WriteToken(jsontext.String("reordering_time"))
+ h.WriteToken(jsontext.Float(milliseconds(e.TimeReordering)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type KeyUpdated struct {
+ Trigger KeyUpdateTrigger
+ KeyType KeyType
+ KeyPhase KeyPhase // only set for 1-RTT keys
+ // we don't log the keys here, so we don't need `old` and `new`.
+}
+
+func (e KeyUpdated) Name() string { return "security:key_updated" }
+
+func (e KeyUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(string(e.Trigger)))
+ h.WriteToken(jsontext.String("key_type"))
+ h.WriteToken(jsontext.String(string(e.KeyType)))
+ if e.KeyType == KeyTypeClient1RTT || e.KeyType == KeyTypeServer1RTT {
+ h.WriteToken(jsontext.String("key_phase"))
+ h.WriteToken(jsontext.Uint(uint64(e.KeyPhase)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type KeyDiscarded struct {
+ KeyType KeyType
+ KeyPhase KeyPhase // only set for 1-RTT keys
+}
+
+func (e KeyDiscarded) Name() string { return "security:key_discarded" }
+
+func (e KeyDiscarded) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if e.KeyType != KeyTypeClient1RTT && e.KeyType != KeyTypeServer1RTT {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String("tls"))
+ }
+ h.WriteToken(jsontext.String("key_type"))
+ h.WriteToken(jsontext.String(string(e.KeyType)))
+ if e.KeyType == KeyTypeClient1RTT || e.KeyType == KeyTypeServer1RTT {
+ h.WriteToken(jsontext.String("key_phase"))
+ h.WriteToken(jsontext.Uint(uint64(e.KeyPhase)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type ParametersSet struct {
+ Restore bool
+ Initiator Initiator
+ SentBy protocol.Perspective
+ OriginalDestinationConnectionID protocol.ConnectionID
+ InitialSourceConnectionID protocol.ConnectionID
+ RetrySourceConnectionID *protocol.ConnectionID
+ StatelessResetToken *protocol.StatelessResetToken
+ DisableActiveMigration bool
+ MaxIdleTimeout time.Duration
+ MaxUDPPayloadSize protocol.ByteCount
+ AckDelayExponent uint8
+ MaxAckDelay time.Duration
+ ActiveConnectionIDLimit uint64
+ InitialMaxData protocol.ByteCount
+ InitialMaxStreamDataBidiLocal protocol.ByteCount
+ InitialMaxStreamDataBidiRemote protocol.ByteCount
+ InitialMaxStreamDataUni protocol.ByteCount
+ InitialMaxStreamsBidi int64
+ InitialMaxStreamsUni int64
+ PreferredAddress *PreferredAddress
+ MaxDatagramFrameSize protocol.ByteCount
+ EnableResetStreamAt bool
+}
+
+func (e ParametersSet) Name() string {
+ if e.Restore {
+ return "transport:parameters_restored"
+ }
+ return "transport:parameters_set"
+}
+
+func (e ParametersSet) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if !e.Restore {
+ h.WriteToken(jsontext.String("initiator"))
+ h.WriteToken(jsontext.String(string(e.Initiator)))
+ if e.SentBy == protocol.PerspectiveServer {
+ h.WriteToken(jsontext.String("original_destination_connection_id"))
+ h.WriteToken(jsontext.String(e.OriginalDestinationConnectionID.String()))
+ if e.StatelessResetToken != nil {
+ h.WriteToken(jsontext.String("stateless_reset_token"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", e.StatelessResetToken[:])))
+ }
+ if e.RetrySourceConnectionID != nil {
+ h.WriteToken(jsontext.String("retry_source_connection_id"))
+ h.WriteToken(jsontext.String((*e.RetrySourceConnectionID).String()))
+ }
+ }
+ h.WriteToken(jsontext.String("initial_source_connection_id"))
+ h.WriteToken(jsontext.String(e.InitialSourceConnectionID.String()))
+ }
+ h.WriteToken(jsontext.String("disable_active_migration"))
+ h.WriteToken(jsontext.Bool(e.DisableActiveMigration))
+ if e.MaxIdleTimeout != 0 {
+ h.WriteToken(jsontext.String("max_idle_timeout"))
+ h.WriteToken(jsontext.Float(milliseconds(e.MaxIdleTimeout)))
+ }
+ if e.MaxUDPPayloadSize != 0 {
+ h.WriteToken(jsontext.String("max_udp_payload_size"))
+ h.WriteToken(jsontext.Int(int64(e.MaxUDPPayloadSize)))
+ }
+ if e.AckDelayExponent != 0 {
+ h.WriteToken(jsontext.String("ack_delay_exponent"))
+ h.WriteToken(jsontext.Uint(uint64(e.AckDelayExponent)))
+ }
+ if e.MaxAckDelay != 0 {
+ h.WriteToken(jsontext.String("max_ack_delay"))
+ h.WriteToken(jsontext.Float(milliseconds(e.MaxAckDelay)))
+ }
+ if e.ActiveConnectionIDLimit != 0 {
+ h.WriteToken(jsontext.String("active_connection_id_limit"))
+ h.WriteToken(jsontext.Uint(e.ActiveConnectionIDLimit))
+ }
+ if e.InitialMaxData != 0 {
+ h.WriteToken(jsontext.String("initial_max_data"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxData)))
+ }
+ if e.InitialMaxStreamDataBidiLocal != 0 {
+ h.WriteToken(jsontext.String("initial_max_stream_data_bidi_local"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxStreamDataBidiLocal)))
+ }
+ if e.InitialMaxStreamDataBidiRemote != 0 {
+ h.WriteToken(jsontext.String("initial_max_stream_data_bidi_remote"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxStreamDataBidiRemote)))
+ }
+ if e.InitialMaxStreamDataUni != 0 {
+ h.WriteToken(jsontext.String("initial_max_stream_data_uni"))
+ h.WriteToken(jsontext.Int(int64(e.InitialMaxStreamDataUni)))
+ }
+ if e.InitialMaxStreamsBidi != 0 {
+ h.WriteToken(jsontext.String("initial_max_streams_bidi"))
+ h.WriteToken(jsontext.Int(e.InitialMaxStreamsBidi))
+ }
+ if e.InitialMaxStreamsUni != 0 {
+ h.WriteToken(jsontext.String("initial_max_streams_uni"))
+ h.WriteToken(jsontext.Int(e.InitialMaxStreamsUni))
+ }
+ if e.PreferredAddress != nil {
+ h.WriteToken(jsontext.String("preferred_address"))
+ if err := e.PreferredAddress.encode(enc); err != nil {
+ return err
+ }
+ }
+ if e.MaxDatagramFrameSize != protocol.InvalidByteCount {
+ h.WriteToken(jsontext.String("max_datagram_frame_size"))
+ h.WriteToken(jsontext.Int(int64(e.MaxDatagramFrameSize)))
+ }
+ if e.EnableResetStreamAt {
+ h.WriteToken(jsontext.String("reset_stream_at"))
+ h.WriteToken(jsontext.True)
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type PreferredAddress struct {
+ IPv4, IPv6 netip.AddrPort
+ ConnectionID protocol.ConnectionID
+ StatelessResetToken protocol.StatelessResetToken
+}
+
+func (a PreferredAddress) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ if a.IPv4.IsValid() {
+ h.WriteToken(jsontext.String("ip_v4"))
+ h.WriteToken(jsontext.String(a.IPv4.Addr().String()))
+ h.WriteToken(jsontext.String("port_v4"))
+ h.WriteToken(jsontext.Uint(uint64(a.IPv4.Port())))
+ }
+ if a.IPv6.IsValid() {
+ h.WriteToken(jsontext.String("ip_v6"))
+ h.WriteToken(jsontext.String(a.IPv6.Addr().String()))
+ h.WriteToken(jsontext.String("port_v6"))
+ h.WriteToken(jsontext.Uint(uint64(a.IPv6.Port())))
+ }
+ h.WriteToken(jsontext.String("connection_id"))
+ h.WriteToken(jsontext.String(a.ConnectionID.String()))
+ h.WriteToken(jsontext.String("stateless_reset_token"))
+ h.WriteToken(jsontext.String(fmt.Sprintf("%x", a.StatelessResetToken)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type LossTimerUpdated struct {
+ Type LossTimerUpdateType
+ TimerType TimerType
+ EncLevel EncryptionLevel
+ Time time.Time
+}
+
+func (e LossTimerUpdated) Name() string { return "recovery:loss_timer_updated" }
+
+func (e LossTimerUpdated) Encode(enc *jsontext.Encoder, t time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("event_type"))
+ h.WriteToken(jsontext.String(string(e.Type)))
+ h.WriteToken(jsontext.String("timer_type"))
+ h.WriteToken(jsontext.String(string(e.TimerType)))
+ h.WriteToken(jsontext.String("packet_number_space"))
+ h.WriteToken(jsontext.String(encLevelToPacketNumberSpace(e.EncLevel)))
+ if e.Type == LossTimerUpdateTypeSet {
+ h.WriteToken(jsontext.String("delta"))
+ h.WriteToken(jsontext.Float(milliseconds(e.Time.Sub(t))))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type eventLossTimerCanceled struct{}
+
+func (e eventLossTimerCanceled) Name() string { return "recovery:loss_timer_updated" }
+
+func (e eventLossTimerCanceled) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("event_type"))
+ h.WriteToken(jsontext.String("cancelled"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type CongestionStateUpdated struct {
+ State CongestionState
+}
+
+func (e CongestionStateUpdated) Name() string { return "recovery:congestion_state_updated" }
+
+func (e CongestionStateUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("new"))
+ h.WriteToken(jsontext.String(e.State.String()))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type ECNStateUpdated struct {
+ State ECNState
+ Trigger string
+}
+
+func (e ECNStateUpdated) Name() string { return "recovery:ecn_state_updated" }
+
+func (e ECNStateUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("new"))
+ h.WriteToken(jsontext.String(string(e.State)))
+ if e.Trigger != "" {
+ h.WriteToken(jsontext.String("trigger"))
+ h.WriteToken(jsontext.String(e.Trigger))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type ALPNInformation struct {
+ ChosenALPN string
+}
+
+func (e ALPNInformation) Name() string { return "transport:alpn_information" }
+
+func (e ALPNInformation) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("chosen_alpn"))
+ h.WriteToken(jsontext.String(e.ChosenALPN))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// DebugEvent is a generic event that can be used to log arbitrary messages.
+type DebugEvent struct {
+ EventName string
+ Message string
+}
+
+func (e DebugEvent) Name() string {
+ if e.EventName == "" {
+ return "transport:debug"
+ }
+ return fmt.Sprintf("transport:%s", e.EventName)
+}
+
+func (e DebugEvent) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("message"))
+ h.WriteToken(jsontext.String(e.Message))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
diff --git a/vendor/github.com/quic-go/quic-go/qlog/frame.go b/vendor/github.com/quic-go/quic-go/qlog/frame.go
new file mode 100644
index 00000000..b66fedc9
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlog/frame.go
@@ -0,0 +1,481 @@
+package qlog
+
+import (
+ "encoding/hex"
+
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlogwriter/jsontext"
+)
+
+type Frame struct {
+ Frame any
+}
+
+type frames []Frame
+
+type (
+ // An AckFrame is an ACK frame.
+ AckFrame = wire.AckFrame
+ // A ConnectionCloseFrame is a CONNECTION_CLOSE frame.
+ ConnectionCloseFrame = wire.ConnectionCloseFrame
+ // A DataBlockedFrame is a DATA_BLOCKED frame.
+ DataBlockedFrame = wire.DataBlockedFrame
+ // A HandshakeDoneFrame is a HANDSHAKE_DONE frame.
+ HandshakeDoneFrame = wire.HandshakeDoneFrame
+ // A MaxDataFrame is a MAX_DATA frame.
+ MaxDataFrame = wire.MaxDataFrame
+ // A MaxStreamDataFrame is a MAX_STREAM_DATA frame.
+ MaxStreamDataFrame = wire.MaxStreamDataFrame
+ // A MaxStreamsFrame is a MAX_STREAMS_FRAME.
+ MaxStreamsFrame = wire.MaxStreamsFrame
+ // A NewConnectionIDFrame is a NEW_CONNECTION_ID frame.
+ NewConnectionIDFrame = wire.NewConnectionIDFrame
+ // A NewTokenFrame is a NEW_TOKEN frame.
+ NewTokenFrame = wire.NewTokenFrame
+ // A PathChallengeFrame is a PATH_CHALLENGE frame.
+ PathChallengeFrame = wire.PathChallengeFrame
+ // A PathResponseFrame is a PATH_RESPONSE frame.
+ PathResponseFrame = wire.PathResponseFrame
+ // A PingFrame is a PING frame.
+ PingFrame = wire.PingFrame
+ // A ResetStreamFrame is a RESET_STREAM frame.
+ ResetStreamFrame = wire.ResetStreamFrame
+ // A RetireConnectionIDFrame is a RETIRE_CONNECTION_ID frame.
+ RetireConnectionIDFrame = wire.RetireConnectionIDFrame
+ // A StopSendingFrame is a STOP_SENDING frame.
+ StopSendingFrame = wire.StopSendingFrame
+ // A StreamsBlockedFrame is a STREAMS_BLOCKED frame.
+ StreamsBlockedFrame = wire.StreamsBlockedFrame
+ // A StreamDataBlockedFrame is a STREAM_DATA_BLOCKED frame.
+ StreamDataBlockedFrame = wire.StreamDataBlockedFrame
+ // An AckFrequencyFrame is an ACK_FREQUENCY frame.
+ AckFrequencyFrame = wire.AckFrequencyFrame
+ // An ImmediateAckFrame is an IMMEDIATE_ACK frame.
+ ImmediateAckFrame = wire.ImmediateAckFrame
+)
+
+type AckRange = wire.AckRange
+
+// A CryptoFrame is a CRYPTO frame.
+type CryptoFrame struct {
+ Offset int64
+ Length int64
+}
+
+// A StreamFrame is a STREAM frame.
+type StreamFrame struct {
+ StreamID StreamID
+ Offset int64
+ Length int64
+ Fin bool
+}
+
+// A DatagramFrame is a DATAGRAM frame.
+type DatagramFrame struct {
+ Length int64
+}
+
+func (fs frames) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
+ for _, f := range fs {
+ if err := f.Encode(enc); err != nil {
+ return err
+ }
+ }
+ h.WriteToken(jsontext.EndArray)
+ return h.err
+}
+
+func (f Frame) Encode(enc *jsontext.Encoder) error {
+ switch frame := f.Frame.(type) {
+ case *PingFrame:
+ return encodePingFrame(enc, frame)
+ case *AckFrame:
+ return encodeAckFrame(enc, frame)
+ case *ResetStreamFrame:
+ return encodeResetStreamFrame(enc, frame)
+ case *StopSendingFrame:
+ return encodeStopSendingFrame(enc, frame)
+ case *CryptoFrame:
+ return encodeCryptoFrame(enc, frame)
+ case *NewTokenFrame:
+ return encodeNewTokenFrame(enc, frame)
+ case *StreamFrame:
+ return encodeStreamFrame(enc, frame)
+ case *MaxDataFrame:
+ return encodeMaxDataFrame(enc, frame)
+ case *MaxStreamDataFrame:
+ return encodeMaxStreamDataFrame(enc, frame)
+ case *MaxStreamsFrame:
+ return encodeMaxStreamsFrame(enc, frame)
+ case *DataBlockedFrame:
+ return encodeDataBlockedFrame(enc, frame)
+ case *StreamDataBlockedFrame:
+ return encodeStreamDataBlockedFrame(enc, frame)
+ case *StreamsBlockedFrame:
+ return encodeStreamsBlockedFrame(enc, frame)
+ case *NewConnectionIDFrame:
+ return encodeNewConnectionIDFrame(enc, frame)
+ case *RetireConnectionIDFrame:
+ return encodeRetireConnectionIDFrame(enc, frame)
+ case *PathChallengeFrame:
+ return encodePathChallengeFrame(enc, frame)
+ case *PathResponseFrame:
+ return encodePathResponseFrame(enc, frame)
+ case *ConnectionCloseFrame:
+ return encodeConnectionCloseFrame(enc, frame)
+ case *HandshakeDoneFrame:
+ return encodeHandshakeDoneFrame(enc, frame)
+ case *DatagramFrame:
+ return encodeDatagramFrame(enc, frame)
+ case *AckFrequencyFrame:
+ return encodeAckFrequencyFrame(enc, frame)
+ case *ImmediateAckFrame:
+ return encodeImmediateAckFrame(enc, frame)
+ default:
+ panic("unknown frame type")
+ }
+}
+
+func encodePingFrame(enc *jsontext.Encoder, _ *PingFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("ping"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+type ackRanges []wire.AckRange
+
+func (ars ackRanges) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
+ for _, r := range ars {
+ if err := ackRange(r).encode(enc); err != nil {
+ return err
+ }
+ }
+ h.WriteToken(jsontext.EndArray)
+ return h.err
+}
+
+type ackRange wire.AckRange
+
+func (ar ackRange) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginArray)
+ h.WriteToken(jsontext.Int(int64(ar.Smallest)))
+ if ar.Smallest != ar.Largest {
+ h.WriteToken(jsontext.Int(int64(ar.Largest)))
+ }
+ h.WriteToken(jsontext.EndArray)
+ return h.err
+}
+
+func encodeAckFrame(enc *jsontext.Encoder, f *AckFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("ack"))
+ if f.DelayTime > 0 {
+ h.WriteToken(jsontext.String("ack_delay"))
+ h.WriteToken(jsontext.Float(milliseconds(f.DelayTime)))
+ }
+ h.WriteToken(jsontext.String("acked_ranges"))
+ if err := ackRanges(f.AckRanges).encode(enc); err != nil {
+ return err
+ }
+ hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0
+ if hasECN {
+ h.WriteToken(jsontext.String("ect0"))
+ h.WriteToken(jsontext.Uint(f.ECT0))
+ h.WriteToken(jsontext.String("ect1"))
+ h.WriteToken(jsontext.Uint(f.ECT1))
+ h.WriteToken(jsontext.String("ce"))
+ h.WriteToken(jsontext.Uint(f.ECNCE))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeResetStreamFrame(enc *jsontext.Encoder, f *ResetStreamFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ if f.ReliableSize > 0 {
+ h.WriteToken(jsontext.String("reset_stream_at"))
+ } else {
+ h.WriteToken(jsontext.String("reset_stream"))
+ }
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Int(int64(f.StreamID)))
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Int(int64(f.ErrorCode)))
+ h.WriteToken(jsontext.String("final_size"))
+ h.WriteToken(jsontext.Int(int64(f.FinalSize)))
+ if f.ReliableSize > 0 {
+ h.WriteToken(jsontext.String("reliable_size"))
+ h.WriteToken(jsontext.Int(int64(f.ReliableSize)))
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeStopSendingFrame(enc *jsontext.Encoder, f *StopSendingFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("stop_sending"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Int(int64(f.StreamID)))
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Int(int64(f.ErrorCode)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeCryptoFrame(enc *jsontext.Encoder, f *CryptoFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("crypto"))
+ h.WriteToken(jsontext.String("offset"))
+ h.WriteToken(jsontext.Int(f.Offset))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Int(f.Length))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeNewTokenFrame(enc *jsontext.Encoder, f *NewTokenFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("new_token"))
+ h.WriteToken(jsontext.String("token"))
+ if err := (Token{Raw: f.Token}).encode(enc); err != nil {
+ return err
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeStreamFrame(enc *jsontext.Encoder, f *StreamFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("stream"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Int(int64(f.StreamID)))
+ h.WriteToken(jsontext.String("offset"))
+ h.WriteToken(jsontext.Int(f.Offset))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Int(f.Length))
+ if f.Fin {
+ h.WriteToken(jsontext.String("fin"))
+ h.WriteToken(jsontext.True)
+ }
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeMaxDataFrame(enc *jsontext.Encoder, f *MaxDataFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("max_data"))
+ h.WriteToken(jsontext.String("maximum"))
+ h.WriteToken(jsontext.Int(int64(f.MaximumData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeMaxStreamDataFrame(enc *jsontext.Encoder, f *MaxStreamDataFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("max_stream_data"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Int(int64(f.StreamID)))
+ h.WriteToken(jsontext.String("maximum"))
+ h.WriteToken(jsontext.Int(int64(f.MaximumStreamData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeMaxStreamsFrame(enc *jsontext.Encoder, f *MaxStreamsFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("max_streams"))
+ h.WriteToken(jsontext.String("stream_type"))
+ h.WriteToken(jsontext.String(streamType(f.Type).String()))
+ h.WriteToken(jsontext.String("maximum"))
+ h.WriteToken(jsontext.Int(int64(f.MaxStreamNum)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeDataBlockedFrame(enc *jsontext.Encoder, f *DataBlockedFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("data_blocked"))
+ h.WriteToken(jsontext.String("limit"))
+ h.WriteToken(jsontext.Int(int64(f.MaximumData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeStreamDataBlockedFrame(enc *jsontext.Encoder, f *StreamDataBlockedFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("stream_data_blocked"))
+ h.WriteToken(jsontext.String("stream_id"))
+ h.WriteToken(jsontext.Int(int64(f.StreamID)))
+ h.WriteToken(jsontext.String("limit"))
+ h.WriteToken(jsontext.Int(int64(f.MaximumStreamData)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeStreamsBlockedFrame(enc *jsontext.Encoder, f *StreamsBlockedFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("streams_blocked"))
+ h.WriteToken(jsontext.String("stream_type"))
+ h.WriteToken(jsontext.String(streamType(f.Type).String()))
+ h.WriteToken(jsontext.String("limit"))
+ h.WriteToken(jsontext.Int(int64(f.StreamLimit)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeNewConnectionIDFrame(enc *jsontext.Encoder, f *NewConnectionIDFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("new_connection_id"))
+ h.WriteToken(jsontext.String("sequence_number"))
+ h.WriteToken(jsontext.Uint(f.SequenceNumber))
+ h.WriteToken(jsontext.String("retire_prior_to"))
+ h.WriteToken(jsontext.Uint(f.RetirePriorTo))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Int(int64(f.ConnectionID.Len())))
+ h.WriteToken(jsontext.String("connection_id"))
+ h.WriteToken(jsontext.String(f.ConnectionID.String()))
+ h.WriteToken(jsontext.String("stateless_reset_token"))
+ h.WriteToken(jsontext.String(hex.EncodeToString(f.StatelessResetToken[:])))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeRetireConnectionIDFrame(enc *jsontext.Encoder, f *RetireConnectionIDFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("retire_connection_id"))
+ h.WriteToken(jsontext.String("sequence_number"))
+ h.WriteToken(jsontext.Uint(f.SequenceNumber))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodePathChallengeFrame(enc *jsontext.Encoder, f *PathChallengeFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("path_challenge"))
+ h.WriteToken(jsontext.String("data"))
+ h.WriteToken(jsontext.String(hex.EncodeToString(f.Data[:])))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodePathResponseFrame(enc *jsontext.Encoder, f *PathResponseFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("path_response"))
+ h.WriteToken(jsontext.String("data"))
+ h.WriteToken(jsontext.String(hex.EncodeToString(f.Data[:])))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeConnectionCloseFrame(enc *jsontext.Encoder, f *ConnectionCloseFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("connection_close"))
+ h.WriteToken(jsontext.String("error_space"))
+ errorSpace := "transport"
+ if f.IsApplicationError {
+ errorSpace = "application"
+ }
+ h.WriteToken(jsontext.String(errorSpace))
+ errName := transportError(f.ErrorCode).String()
+ if len(errName) > 0 {
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.String(errName))
+ } else {
+ h.WriteToken(jsontext.String("error_code"))
+ h.WriteToken(jsontext.Uint(f.ErrorCode))
+ }
+ h.WriteToken(jsontext.String("raw_error_code"))
+ h.WriteToken(jsontext.Uint(f.ErrorCode))
+ h.WriteToken(jsontext.String("reason"))
+ h.WriteToken(jsontext.String(f.ReasonPhrase))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeHandshakeDoneFrame(enc *jsontext.Encoder, _ *HandshakeDoneFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("handshake_done"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeDatagramFrame(enc *jsontext.Encoder, f *DatagramFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("datagram"))
+ h.WriteToken(jsontext.String("length"))
+ h.WriteToken(jsontext.Int(f.Length))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeAckFrequencyFrame(enc *jsontext.Encoder, f *AckFrequencyFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("ack_frequency"))
+ h.WriteToken(jsontext.String("sequence_number"))
+ h.WriteToken(jsontext.Uint(f.SequenceNumber))
+ h.WriteToken(jsontext.String("ack_eliciting_threshold"))
+ h.WriteToken(jsontext.Uint(f.AckElicitingThreshold))
+ h.WriteToken(jsontext.String("request_max_ack_delay"))
+ h.WriteToken(jsontext.Float(milliseconds(f.RequestMaxAckDelay)))
+ h.WriteToken(jsontext.String("reordering_threshold"))
+ h.WriteToken(jsontext.Int(int64(f.ReorderingThreshold)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+func encodeImmediateAckFrame(enc *jsontext.Encoder, _ *ImmediateAckFrame) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("frame_type"))
+ h.WriteToken(jsontext.String("immediate_ack"))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
diff --git a/vendor/github.com/quic-go/quic-go/qlog/packet_header.go b/vendor/github.com/quic-go/quic-go/qlog/packet_header.go
new file mode 100644
index 00000000..149ebcb6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlog/packet_header.go
@@ -0,0 +1,96 @@
+package qlog
+
+import (
+ "encoding/hex"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/qlogwriter/jsontext"
+)
+
+type Token struct {
+ Raw []byte
+}
+
+func (t Token) encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("data"))
+ h.WriteToken(jsontext.String(hex.EncodeToString(t.Raw)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
+// PacketHeader is a QUIC packet header.
+type PacketHeader struct {
+ PacketType PacketType
+ KeyPhaseBit KeyPhaseBit
+ PacketNumber PacketNumber
+ Version Version
+ SrcConnectionID ConnectionID
+ DestConnectionID ConnectionID
+ Token *Token
+}
+
+func (h PacketHeader) encode(enc *jsontext.Encoder) error {
+ helper := encoderHelper{enc: enc}
+ helper.WriteToken(jsontext.BeginObject)
+ helper.WriteToken(jsontext.String("packet_type"))
+ helper.WriteToken(jsontext.String(string(h.PacketType)))
+ if h.PacketType != PacketTypeRetry && h.PacketType != PacketTypeVersionNegotiation && h.PacketType != "" &&
+ h.PacketNumber != protocol.InvalidPacketNumber {
+ helper.WriteToken(jsontext.String("packet_number"))
+ helper.WriteToken(jsontext.Int(int64(h.PacketNumber)))
+ }
+ if h.Version != 0 {
+ helper.WriteToken(jsontext.String("version"))
+ helper.WriteToken(jsontext.String(version(h.Version).String()))
+ }
+ if h.PacketType != PacketType1RTT {
+ helper.WriteToken(jsontext.String("scil"))
+ helper.WriteToken(jsontext.Int(int64(h.SrcConnectionID.Len())))
+ if h.SrcConnectionID.Len() > 0 {
+ helper.WriteToken(jsontext.String("scid"))
+ helper.WriteToken(jsontext.String(h.SrcConnectionID.String()))
+ }
+ }
+ helper.WriteToken(jsontext.String("dcil"))
+ helper.WriteToken(jsontext.Int(int64(h.DestConnectionID.Len())))
+ if h.DestConnectionID.Len() > 0 {
+ helper.WriteToken(jsontext.String("dcid"))
+ helper.WriteToken(jsontext.String(h.DestConnectionID.String()))
+ }
+ if h.KeyPhaseBit == KeyPhaseZero || h.KeyPhaseBit == KeyPhaseOne {
+ helper.WriteToken(jsontext.String("key_phase_bit"))
+ helper.WriteToken(jsontext.String(h.KeyPhaseBit.String()))
+ }
+ if h.Token != nil {
+ helper.WriteToken(jsontext.String("token"))
+ if err := h.Token.encode(enc); err != nil {
+ return err
+ }
+ }
+ helper.WriteToken(jsontext.EndObject)
+ return helper.err
+}
+
+type PacketHeaderVersionNegotiation struct {
+ SrcConnectionID ArbitraryLenConnectionID
+ DestConnectionID ArbitraryLenConnectionID
+}
+
+func (h PacketHeaderVersionNegotiation) encode(enc *jsontext.Encoder) error {
+ helper := encoderHelper{enc: enc}
+ helper.WriteToken(jsontext.BeginObject)
+ helper.WriteToken(jsontext.String("packet_type"))
+ helper.WriteToken(jsontext.String("version_negotiation"))
+ helper.WriteToken(jsontext.String("scil"))
+ helper.WriteToken(jsontext.Int(int64(h.SrcConnectionID.Len())))
+ helper.WriteToken(jsontext.String("scid"))
+ helper.WriteToken(jsontext.String(h.SrcConnectionID.String()))
+ helper.WriteToken(jsontext.String("dcil"))
+ helper.WriteToken(jsontext.Int(int64(h.DestConnectionID.Len())))
+ helper.WriteToken(jsontext.String("dcid"))
+ helper.WriteToken(jsontext.String(h.DestConnectionID.String()))
+ helper.WriteToken(jsontext.EndObject)
+ return helper.err
+}
diff --git a/vendor/github.com/quic-go/quic-go/qlog/qlog_dir.go b/vendor/github.com/quic-go/quic-go/qlog/qlog_dir.go
new file mode 100644
index 00000000..83bb72b3
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlog/qlog_dir.go
@@ -0,0 +1,61 @@
+package qlog
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "log"
+ "os"
+ "slices"
+ "strings"
+
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+// EventSchema is the qlog event schema for QUIC
+const EventSchema = "urn:ietf:params:qlog:events:quic-12"
+
+// DefaultConnectionTracer creates a qlog file in the qlog directory specified by the QLOGDIR environment variable.
+// File names are _.sqlog.
+// Returns nil if QLOGDIR is not set.
+func DefaultConnectionTracer(_ context.Context, isClient bool, connID ConnectionID) qlogwriter.Trace {
+ return defaultConnectionTracerWithSchemas(isClient, connID, []string{EventSchema})
+}
+
+func DefaultConnectionTracerWithSchemas(_ context.Context, isClient bool, connID ConnectionID, eventSchemas []string) qlogwriter.Trace {
+ if !slices.Contains(eventSchemas, EventSchema) {
+ eventSchemas = append([]string{EventSchema}, eventSchemas...)
+ }
+ return defaultConnectionTracerWithSchemas(isClient, connID, eventSchemas)
+}
+
+func defaultConnectionTracerWithSchemas(isClient bool, connID ConnectionID, eventSchemas []string) qlogwriter.Trace {
+ qlogDir := os.Getenv("QLOGDIR")
+ if qlogDir == "" {
+ return nil
+ }
+ if _, err := os.Stat(qlogDir); os.IsNotExist(err) {
+ if err := os.MkdirAll(qlogDir, 0o755); err != nil {
+ log.Fatalf("failed to create qlog dir %s: %v", qlogDir, err)
+ }
+ }
+ label := "server"
+ if isClient {
+ label = "client"
+ }
+ path := fmt.Sprintf("%s/%s_%s.sqlog", strings.TrimRight(qlogDir, "/"), connID, label)
+ f, err := os.Create(path)
+ if err != nil {
+ log.Printf("Failed to create qlog file %s: %s", path, err.Error())
+ return nil
+ }
+ fileSeq := qlogwriter.NewConnectionFileSeq(
+ utils.NewBufferedWriteCloser(bufio.NewWriter(f), f),
+ isClient,
+ connID,
+ eventSchemas,
+ )
+ go fileSeq.Run()
+ return fileSeq
+}
diff --git a/vendor/github.com/quic-go/quic-go/qlog/types.go b/vendor/github.com/quic-go/quic-go/qlog/types.go
new file mode 100644
index 00000000..dfa4066d
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlog/types.go
@@ -0,0 +1,304 @@
+package qlog
+
+import (
+ "fmt"
+ "hash/crc32"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+)
+
+type (
+ ConnectionID = protocol.ConnectionID
+ ArbitraryLenConnectionID = protocol.ArbitraryLenConnectionID
+ Version = protocol.Version
+ PacketNumber = protocol.PacketNumber
+ EncryptionLevel = protocol.EncryptionLevel
+ KeyPhaseBit = protocol.KeyPhaseBit
+ KeyPhase = protocol.KeyPhase
+ StreamID = protocol.StreamID
+ TransportErrorCode = qerr.TransportErrorCode
+ ApplicationErrorCode = qerr.ApplicationErrorCode
+)
+
+const (
+ // KeyPhaseZero is key phase bit 0
+ KeyPhaseZero = protocol.KeyPhaseZero
+ // KeyPhaseOne is key phase bit 1
+ KeyPhaseOne = protocol.KeyPhaseOne
+)
+
+// ECN represents the Explicit Congestion Notification value.
+type ECN string
+
+const (
+ // ECNUnsupported means that no ECN value was set / received
+ ECNUnsupported ECN = ""
+ // ECTNot is Not-ECT
+ ECTNot ECN = "Not-ECT"
+ // ECT0 is ECT(0)
+ ECT0 ECN = "ECT(0)"
+ // ECT1 is ECT(1)
+ ECT1 ECN = "ECT(1)"
+ // ECNCE is CE
+ ECNCE ECN = "CE"
+)
+
+type Initiator string
+
+const (
+ InitiatorLocal Initiator = "local"
+ InitiatorRemote Initiator = "remote"
+)
+
+type streamType protocol.StreamType
+
+func (s streamType) String() string {
+ switch protocol.StreamType(s) {
+ case protocol.StreamTypeUni:
+ return "unidirectional"
+ case protocol.StreamTypeBidi:
+ return "bidirectional"
+ default:
+ return "unknown stream type"
+ }
+}
+
+type version protocol.Version
+
+func (v version) String() string {
+ return fmt.Sprintf("%x", uint32(v))
+}
+
+func encLevelToPacketNumberSpace(encLevel protocol.EncryptionLevel) string {
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return "initial"
+ case protocol.EncryptionHandshake:
+ return "handshake"
+ case protocol.Encryption0RTT, protocol.Encryption1RTT:
+ return "application_data"
+ default:
+ return "unknown encryption level"
+ }
+}
+
+// KeyType represents the type of cryptographic key used in QUIC connections.
+type KeyType string
+
+const (
+ // KeyTypeServerInitial represents the server's initial secret key.
+ KeyTypeServerInitial KeyType = "server_initial_secret"
+ // KeyTypeClientInitial represents the client's initial secret key.
+ KeyTypeClientInitial KeyType = "client_initial_secret"
+ // KeyTypeServerHandshake represents the server's handshake secret key.
+ KeyTypeServerHandshake KeyType = "server_handshake_secret"
+ // KeyTypeClientHandshake represents the client's handshake secret key.
+ KeyTypeClientHandshake KeyType = "client_handshake_secret"
+ // KeyTypeServer0RTT represents the server's 0-RTT secret key.
+ KeyTypeServer0RTT KeyType = "server_0rtt_secret"
+ // KeyTypeClient0RTT represents the client's 0-RTT secret key.
+ KeyTypeClient0RTT KeyType = "client_0rtt_secret"
+ // KeyTypeServer1RTT represents the server's 1-RTT secret key.
+ KeyTypeServer1RTT KeyType = "server_1rtt_secret"
+ // KeyTypeClient1RTT represents the client's 1-RTT secret key.
+ KeyTypeClient1RTT KeyType = "client_1rtt_secret"
+)
+
+// KeyUpdateTrigger describes what caused a key update event.
+type KeyUpdateTrigger string
+
+const (
+ // KeyUpdateTLS indicates the key update was triggered by TLS.
+ KeyUpdateTLS KeyUpdateTrigger = "tls"
+ // KeyUpdateRemote indicates the key update was triggered by the remote peer.
+ KeyUpdateRemote KeyUpdateTrigger = "remote_update"
+ // KeyUpdateLocal indicates the key update was triggered locally.
+ KeyUpdateLocal KeyUpdateTrigger = "local_update"
+)
+
+type transportError uint64
+
+func (e transportError) String() string {
+ switch qerr.TransportErrorCode(e) {
+ case qerr.NoError:
+ return "no_error"
+ case qerr.InternalError:
+ return "internal_error"
+ case qerr.ConnectionRefused:
+ return "connection_refused"
+ case qerr.FlowControlError:
+ return "flow_control_error"
+ case qerr.StreamLimitError:
+ return "stream_limit_error"
+ case qerr.StreamStateError:
+ return "stream_state_error"
+ case qerr.FinalSizeError:
+ return "final_size_error"
+ case qerr.FrameEncodingError:
+ return "frame_encoding_error"
+ case qerr.TransportParameterError:
+ return "transport_parameter_error"
+ case qerr.ConnectionIDLimitError:
+ return "connection_id_limit_error"
+ case qerr.ProtocolViolation:
+ return "protocol_violation"
+ case qerr.InvalidToken:
+ return "invalid_token"
+ case qerr.ApplicationErrorErrorCode:
+ return "application_error"
+ case qerr.CryptoBufferExceeded:
+ return "crypto_buffer_exceeded"
+ case qerr.KeyUpdateError:
+ return "key_update_error"
+ case qerr.AEADLimitReached:
+ return "aead_limit_reached"
+ case qerr.NoViablePathError:
+ return "no_viable_path"
+ default:
+ return ""
+ }
+}
+
+type PacketType string
+
+const (
+ // PacketTypeInitial represents an Initial packet
+ PacketTypeInitial PacketType = "initial"
+ // PacketTypeHandshake represents a Handshake packet
+ PacketTypeHandshake PacketType = "handshake"
+ // PacketTypeRetry represents a Retry packet
+ PacketTypeRetry PacketType = "retry"
+ // PacketType0RTT represents a 0-RTT packet
+ PacketType0RTT PacketType = "0RTT"
+ // PacketTypeVersionNegotiation represents a Version Negotiation packet
+ PacketTypeVersionNegotiation PacketType = "version_negotiation"
+ // PacketTypeStatelessReset represents a Stateless Reset packet
+ PacketTypeStatelessReset PacketType = "stateless_reset"
+ // PacketType1RTT represents a 1-RTT packet
+ PacketType1RTT PacketType = "1RTT"
+ // // PacketTypeNotDetermined represents a packet type that could not be determined
+ // PacketTypeNotDetermined packetType = ""
+)
+
+func EncryptionLevelToPacketType(l EncryptionLevel) PacketType {
+ switch l {
+ case protocol.EncryptionInitial:
+ return PacketTypeInitial
+ case protocol.EncryptionHandshake:
+ return PacketTypeHandshake
+ case protocol.Encryption0RTT:
+ return PacketType0RTT
+ case protocol.Encryption1RTT:
+ return PacketType1RTT
+ default:
+ panic(fmt.Sprintf("unknown encryption level: %d", l))
+ }
+}
+
+type PacketLossReason string
+
+const (
+ // PacketLossReorderingThreshold is used when a packet is declared lost due to reordering threshold
+ PacketLossReorderingThreshold PacketLossReason = "reordering_threshold"
+ // PacketLossTimeThreshold is used when a packet is declared lost due to time threshold
+ PacketLossTimeThreshold PacketLossReason = "time_threshold"
+)
+
+type PacketDropReason string
+
+const (
+ // PacketDropKeyUnavailable is used when a packet is dropped because keys are unavailable
+ PacketDropKeyUnavailable PacketDropReason = "key_unavailable"
+ // PacketDropUnknownConnectionID is used when a packet is dropped because the connection ID is unknown
+ PacketDropUnknownConnectionID PacketDropReason = "unknown_connection_id"
+ // PacketDropHeaderParseError is used when a packet is dropped because header parsing failed
+ PacketDropHeaderParseError PacketDropReason = "header_parse_error"
+ // PacketDropPayloadDecryptError is used when a packet is dropped because decrypting the payload failed
+ PacketDropPayloadDecryptError PacketDropReason = "payload_decrypt_error"
+ // PacketDropProtocolViolation is used when a packet is dropped due to a protocol violation
+ PacketDropProtocolViolation PacketDropReason = "protocol_violation"
+ // PacketDropDOSPrevention is used when a packet is dropped to mitigate a DoS attack
+ PacketDropDOSPrevention PacketDropReason = "dos_prevention"
+ // PacketDropUnsupportedVersion is used when a packet is dropped because the version is not supported
+ PacketDropUnsupportedVersion PacketDropReason = "unsupported_version"
+ // PacketDropUnexpectedPacket is used when an unexpected packet is received
+ PacketDropUnexpectedPacket PacketDropReason = "unexpected_packet"
+ // PacketDropUnexpectedSourceConnectionID is used when a packet with an unexpected source connection ID is received
+ PacketDropUnexpectedSourceConnectionID PacketDropReason = "unexpected_source_connection_id"
+ // PacketDropUnexpectedVersion is used when a packet with an unexpected version is received
+ PacketDropUnexpectedVersion PacketDropReason = "unexpected_version"
+ // PacketDropDuplicate is used when a duplicate packet is received
+ PacketDropDuplicate PacketDropReason = "duplicate"
+)
+
+type LossTimerUpdateType string
+
+const (
+ LossTimerUpdateTypeSet LossTimerUpdateType = "set"
+ LossTimerUpdateTypeExpired LossTimerUpdateType = "expired"
+ LossTimerUpdateTypeCancelled LossTimerUpdateType = "cancelled"
+)
+
+type TimerType string
+
+const (
+ // TimerTypeACK represents an ACK timer
+ TimerTypeACK TimerType = "ack"
+ // TimerTypePTO represents a PTO (Probe Timeout) timer
+ TimerTypePTO TimerType = "pto"
+ // TimerTypePathProbe represents a path probe timer
+ TimerTypePathProbe TimerType = "path_probe"
+)
+
+type CongestionState string
+
+const (
+ // CongestionStateSlowStart is the slow start phase of Reno / Cubic
+ CongestionStateSlowStart CongestionState = "slow_start"
+ // CongestionStateCongestionAvoidance is the congestion avoidance phase of Reno / Cubic
+ CongestionStateCongestionAvoidance CongestionState = "congestion_avoidance"
+ // CongestionStateRecovery is the recovery phase of Reno / Cubic
+ CongestionStateRecovery CongestionState = "recovery"
+ // CongestionStateApplicationLimited means that the congestion controller is application limited
+ CongestionStateApplicationLimited CongestionState = "application_limited"
+)
+
+func (s CongestionState) String() string {
+ return string(s)
+}
+
+// ECNState is the state of the ECN state machine (see Appendix A.4 of RFC 9000)
+type ECNState string
+
+const (
+ // ECNStateTesting is the testing state
+ ECNStateTesting ECNState = "testing"
+ // ECNStateUnknown is the unknown state
+ ECNStateUnknown ECNState = "unknown"
+ // ECNStateFailed is the failed state
+ ECNStateFailed ECNState = "failed"
+ // ECNStateCapable is the capable state
+ ECNStateCapable ECNState = "capable"
+)
+
+type ConnectionCloseTrigger string
+
+const (
+ // IdleTimeout indicates the connection was closed due to idle timeout
+ ConnectionCloseTriggerIdleTimeout ConnectionCloseTrigger = "idle_timeout"
+ // Application indicates the connection was closed by the application
+ ConnectionCloseTriggerApplication ConnectionCloseTrigger = "application"
+ // VersionMismatch indicates the connection was closed due to a QUIC version mismatch
+ ConnectionCloseTriggerVersionMismatch ConnectionCloseTrigger = "version_mismatch"
+ // StatelessReset indicates the connection was closed due to receiving a stateless reset from the peer
+ ConnectionCloseTriggerStatelessReset ConnectionCloseTrigger = "stateless_reset"
+)
+
+// DatagramID is a unique identifier for a datagram
+type DatagramID uint32
+
+// CalculateDatagramID computes a DatagramID for a given packet
+func CalculateDatagramID(packet []byte) DatagramID {
+ return DatagramID(crc32.ChecksumIEEE(packet))
+}
diff --git a/vendor/github.com/quic-go/quic-go/qlogwriter/jsontext/encoder.go b/vendor/github.com/quic-go/quic-go/qlogwriter/jsontext/encoder.go
new file mode 100644
index 00000000..4f715bbd
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlogwriter/jsontext/encoder.go
@@ -0,0 +1,324 @@
+// Package jsontext provides a fast JSON encoder providing only the necessary features
+// for qlog encoding. No efforts are made to add any features beyond qlog's requirements.
+//
+// The API aims to be compatible with the standard library's encoding/json/jsontext package.
+package jsontext
+
+import (
+ "fmt"
+ "io"
+ "strconv"
+ "unsafe"
+)
+
+type kind uint8
+
+const (
+ kindString kind = iota
+ kindInt
+ kindUint
+ kindFloat
+ kindBool
+ kindNull
+ kindObjectStart
+ kindObjectEnd
+ kindArrayStart
+ kindArrayEnd
+)
+
+// Token represents a JSON token.
+type Token struct {
+ kind kind
+ str string
+ i64 int64
+ u64 uint64
+ f64 float64
+ b bool
+}
+
+// String creates a string token.
+func String(s string) Token {
+ return Token{kind: kindString, str: s}
+}
+
+// Int creates an int token.
+func Int(i int64) Token {
+ return Token{kind: kindInt, i64: i}
+}
+
+// Uint creates a uint token.
+func Uint(u uint64) Token {
+ return Token{kind: kindUint, u64: u}
+}
+
+// Float creates a float token.
+func Float(f float64) Token {
+ return Token{kind: kindFloat, f64: f}
+}
+
+// Bool creates a bool token.
+func Bool(b bool) Token {
+ return Token{kind: kindBool, b: b}
+}
+
+// Null is a null token.
+var Null Token = Token{kind: kindNull}
+
+// BeginObject is the begin object token.
+var BeginObject Token = Token{kind: kindObjectStart}
+
+// EndObject is the end object token.
+var EndObject Token = Token{kind: kindObjectEnd}
+
+// BeginArray is the begin array token.
+var BeginArray Token = Token{kind: kindArrayStart}
+
+// EndArray is the end array token.
+var EndArray Token = Token{kind: kindArrayEnd}
+
+// True is a true token.
+var True Token = Bool(true)
+
+// False is a false token.
+var False Token = Bool(false)
+
+var hexDigits = [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
+
+var (
+ commaByte = []byte(",")
+ quoteByte = []byte(`"`)
+ colonByte = []byte(":")
+ trueByte = []byte("true")
+ falseByte = []byte("false")
+ nullByte = []byte("null")
+ openObjectByte = []byte("{")
+ closeObjectByte = []byte("}")
+ openArrayByte = []byte("[")
+ closeArrayByte = []byte("]")
+ newlineByte = []byte("\n")
+ escapeQuote = []byte(`\"`)
+ escapeBackslash = []byte(`\\`)
+ escapeBackspace = []byte(`\b`)
+ escapeFormfeed = []byte(`\f`)
+ escapeNewline = []byte(`\n`)
+ escapeCarriage = []byte(`\r`)
+ escapeTab = []byte(`\t`)
+ escapeUnicode = []byte(`\u00`)
+)
+
+type context struct {
+ isObject bool
+ needsComma bool
+ expectKey bool
+}
+
+// Encoder encodes JSON to an io.Writer.
+type Encoder struct {
+ w io.Writer
+ buf [64]byte // scratch buffer for number formatting
+ stack []context
+}
+
+// NewEncoder creates a new Encoder.
+func NewEncoder(w io.Writer) *Encoder {
+ stack := make([]context, 0, 8)
+ stack = append(stack, context{isObject: false, needsComma: false, expectKey: false})
+ return &Encoder{
+ w: w,
+ stack: stack,
+ }
+}
+
+// WriteToken writes a token to the encoder.
+func (e *Encoder) WriteToken(t Token) error {
+ if len(e.stack) == 0 {
+ return fmt.Errorf("empty stack")
+ }
+ curr := &e.stack[len(e.stack)-1]
+ isClosing := t.kind == kindObjectEnd || t.kind == kindArrayEnd
+ if !isClosing && curr.needsComma {
+ if _, err := e.w.Write(commaByte); err != nil {
+ return err
+ }
+ curr.needsComma = false
+ }
+ var err error
+ switch t.kind {
+ case kindString:
+ data := stringToBytes(t.str)
+ needsEscape := false
+ for _, b := range data {
+ if b == '"' || b == '\\' || b < 0x20 {
+ needsEscape = true
+ break
+ }
+ }
+ if !needsEscape {
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ if _, err = e.w.Write(data); err != nil {
+ return err
+ }
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ } else {
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ for i := 0; i < len(t.str); i++ {
+ c := t.str[i]
+ switch c {
+ case '"':
+ if _, err = e.w.Write(escapeQuote); err != nil {
+ return err
+ }
+ case '\\':
+ if _, err = e.w.Write(escapeBackslash); err != nil {
+ return err
+ }
+ case '\b':
+ if _, err = e.w.Write(escapeBackspace); err != nil {
+ return err
+ }
+ case '\f':
+ if _, err = e.w.Write(escapeFormfeed); err != nil {
+ return err
+ }
+ case '\n':
+ if _, err = e.w.Write(escapeNewline); err != nil {
+ return err
+ }
+ case '\r':
+ if _, err = e.w.Write(escapeCarriage); err != nil {
+ return err
+ }
+ case '\t':
+ if _, err = e.w.Write(escapeTab); err != nil {
+ return err
+ }
+ default:
+ if c < 0x20 {
+ if _, err = e.w.Write(escapeUnicode); err != nil {
+ return err
+ }
+ if _, err = e.w.Write([]byte{hexDigits[c>>4], hexDigits[c&0xf]}); err != nil {
+ return err
+ }
+ } else {
+ if _, err = e.w.Write([]byte{c}); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ if _, err = e.w.Write(quoteByte); err != nil {
+ return err
+ }
+ }
+ if curr.isObject {
+ if curr.expectKey {
+ // key
+ if _, err = e.w.Write(colonByte); err != nil {
+ return err
+ }
+ curr.expectKey = false
+ return nil // do not call afterValue for keys
+ } else {
+ // value
+ e.afterValue()
+ }
+ } else {
+ e.afterValue()
+ }
+ case kindInt:
+ b := strconv.AppendInt(e.buf[:0], t.i64, 10)
+ if _, err = e.w.Write(b); err != nil {
+ return err
+ }
+ e.afterValue()
+ case kindUint:
+ b := strconv.AppendUint(e.buf[:0], t.u64, 10)
+ if _, err = e.w.Write(b); err != nil {
+ return err
+ }
+ e.afterValue()
+ case kindFloat:
+ b := strconv.AppendFloat(e.buf[:0], t.f64, 'g', -1, 64)
+ if _, err = e.w.Write(b); err != nil {
+ return err
+ }
+ e.afterValue()
+ case kindBool:
+ if t.b {
+ if _, err = e.w.Write(trueByte); err != nil {
+ return err
+ }
+ } else {
+ if _, err = e.w.Write(falseByte); err != nil {
+ return err
+ }
+ }
+ e.afterValue()
+ case kindNull:
+ if _, err = e.w.Write(nullByte); err != nil {
+ return err
+ }
+ e.afterValue()
+ case kindObjectStart:
+ if _, err = e.w.Write(openObjectByte); err != nil {
+ return err
+ }
+ e.stack = append(e.stack, context{isObject: true, needsComma: false, expectKey: true})
+ return nil
+ case kindObjectEnd:
+ if _, err = e.w.Write(closeObjectByte); err != nil {
+ return err
+ }
+ e.stack = e.stack[:len(e.stack)-1]
+ e.afterValue()
+ if len(e.stack) == 1 {
+ if _, err = e.w.Write(newlineByte); err != nil {
+ return err
+ }
+ }
+ return nil
+ case kindArrayStart:
+ if _, err = e.w.Write(openArrayByte); err != nil {
+ return err
+ }
+ e.stack = append(e.stack, context{isObject: false, needsComma: false, expectKey: false})
+ return nil
+ case kindArrayEnd:
+ if _, err = e.w.Write(closeArrayByte); err != nil {
+ return err
+ }
+ e.stack = e.stack[:len(e.stack)-1]
+ e.afterValue()
+ if len(e.stack) == 1 {
+ if _, err = e.w.Write(newlineByte); err != nil {
+ return err
+ }
+ }
+ return nil
+ default:
+ return fmt.Errorf("unknown token kind")
+ }
+ return err
+}
+
+// afterValue updates the state after encoding a value
+func (e *Encoder) afterValue() {
+ if len(e.stack) > 1 {
+ curr := &e.stack[len(e.stack)-1]
+ curr.needsComma = true
+ if curr.isObject {
+ curr.expectKey = true
+ }
+ }
+}
+
+func stringToBytes(s string) []byte {
+ return unsafe.Slice(unsafe.StringData(s), len(s))
+}
diff --git a/vendor/github.com/quic-go/quic-go/qlogwriter/trace.go b/vendor/github.com/quic-go/quic-go/qlogwriter/trace.go
new file mode 100644
index 00000000..eebcbaad
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlogwriter/trace.go
@@ -0,0 +1,124 @@
+package qlogwriter
+
+import (
+ "runtime/debug"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/qlogwriter/jsontext"
+)
+
+type ConnectionID = protocol.ConnectionID
+
+// Setting of this only works when quic-go is used as a library.
+// When building a binary from this repository, the version can be set using the following go build flag:
+// -ldflags="-X github.com/quic-go/quic-go/qlogwriter.quicGoVersion=foobar"
+var quicGoVersion = "(devel)"
+
+func init() {
+ if quicGoVersion != "(devel)" { // variable set by ldflags
+ return
+ }
+ info, ok := debug.ReadBuildInfo()
+ if !ok { // no build info available. This happens when quic-go is not used as a library.
+ return
+ }
+ for _, d := range info.Deps {
+ if d.Path == "github.com/quic-go/quic-go" {
+ quicGoVersion = d.Version
+ if d.Replace != nil {
+ if len(d.Replace.Version) > 0 {
+ quicGoVersion = d.Version
+ } else {
+ quicGoVersion += " (replaced)"
+ }
+ }
+ break
+ }
+ }
+}
+
+type encoderHelper struct {
+ enc *jsontext.Encoder
+ err error
+}
+
+func (h *encoderHelper) WriteToken(t jsontext.Token) {
+ if h.err != nil {
+ return
+ }
+ h.err = h.enc.WriteToken(t)
+}
+
+type traceHeader struct {
+ VantagePointType string
+ GroupID *ConnectionID
+ ReferenceTime time.Time
+ EventSchemas []string
+}
+
+func (l traceHeader) Encode(enc *jsontext.Encoder) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("file_schema"))
+ h.WriteToken(jsontext.String("urn:ietf:params:qlog:file:sequential"))
+ h.WriteToken(jsontext.String("serialization_format"))
+ h.WriteToken(jsontext.String("application/qlog+json-seq"))
+ h.WriteToken(jsontext.String("title"))
+ h.WriteToken(jsontext.String("quic-go qlog"))
+ h.WriteToken(jsontext.String("code_version"))
+ h.WriteToken(jsontext.String(quicGoVersion))
+
+ h.WriteToken(jsontext.String("trace"))
+ // trace
+ h.WriteToken(jsontext.BeginObject)
+ if len(l.EventSchemas) > 0 {
+ h.WriteToken(jsontext.String("event_schemas"))
+ h.WriteToken(jsontext.BeginArray)
+ for _, schema := range l.EventSchemas {
+ h.WriteToken(jsontext.String(schema))
+ }
+ h.WriteToken(jsontext.EndArray)
+ }
+
+ h.WriteToken(jsontext.String("vantage_point"))
+ // -- vantage_point
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("type"))
+ h.WriteToken(jsontext.String(l.VantagePointType))
+ // -- end vantage_point
+ h.WriteToken(jsontext.EndObject)
+
+ h.WriteToken(jsontext.String("common_fields"))
+ // -- common_fields
+ h.WriteToken(jsontext.BeginObject)
+ if l.GroupID != nil {
+ h.WriteToken(jsontext.String("group_id"))
+ h.WriteToken(jsontext.String(l.GroupID.String()))
+ }
+ h.WriteToken(jsontext.String("reference_time"))
+ // ---- reference_time
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("clock_type"))
+ h.WriteToken(jsontext.String("monotonic"))
+ h.WriteToken(jsontext.String("epoch"))
+ h.WriteToken(jsontext.String("unknown"))
+ h.WriteToken(jsontext.String("wall_clock_time"))
+ h.WriteToken(jsontext.String(l.ReferenceTime.Format(time.RFC3339Nano)))
+ // ---- end reference_time
+ h.WriteToken(jsontext.EndObject)
+ // -- end common_fields
+ h.WriteToken(jsontext.EndObject)
+ // end trace
+ h.WriteToken(jsontext.EndObject)
+
+ // The following fields are not required by the qlog draft anymore,
+ // but qvis still requires them to be present.
+ h.WriteToken(jsontext.String("qlog_format"))
+ h.WriteToken(jsontext.String("JSON-SEQ"))
+ h.WriteToken(jsontext.String("qlog_version"))
+ h.WriteToken(jsontext.String("0.3"))
+
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
diff --git a/vendor/github.com/quic-go/quic-go/qlogwriter/writer.go b/vendor/github.com/quic-go/quic-go/qlogwriter/writer.go
new file mode 100644
index 00000000..d728f596
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/qlogwriter/writer.go
@@ -0,0 +1,229 @@
+package qlogwriter
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "slices"
+ "sync"
+ "time"
+
+ "github.com/quic-go/quic-go/qlogwriter/jsontext"
+)
+
+// Trace represents a qlog trace that can have multiple event producers.
+// Each producer can record events to the trace independently.
+// When the last producer is closed, the underlying trace is closed as well.
+type Trace interface {
+ // AddProducer creates a new Recorder for this trace.
+ // Each Recorder can record events independently.
+ AddProducer() Recorder
+
+ // SupportsSchemas returns true if the trace supports the given schema.
+ SupportsSchemas(schema string) bool
+}
+
+// Recorder is used to record events to a qlog trace.
+// It is safe for concurrent use by multiple goroutines.
+type Recorder interface {
+ // RecordEvent records a single Event to the trace.
+ // It must not be called after Close.
+ RecordEvent(Event)
+ // Close signals that this producer is done recording events.
+ // When all producers are closed, the underlying trace is closed.
+ // It must not be called concurrently with RecordEvent.
+ io.Closer
+}
+
+// Event represents a qlog event that can be encoded to JSON.
+// Each event must provide its name and a method to encode itself using a jsontext.Encoder.
+type Event interface {
+ // Name returns the name of the event, as it should appear in the qlog output
+ Name() string
+ // Encode writes the event's data to the provided jsontext.Encoder
+ Encode(encoder *jsontext.Encoder, eventTime time.Time) error
+}
+
+// RecordSeparator is the record separator byte for the JSON-SEQ format
+const RecordSeparator byte = 0x1e
+
+var recordSeparator = []byte{RecordSeparator}
+
+type event struct {
+ Time time.Time
+ Event Event
+}
+
+const eventChanSize = 50
+
+// FileSeq represents a qlog trace using the JSON-SEQ format,
+// https://www.ietf.org/archive/id/draft-ietf-quic-qlog-main-schema-12.html#section-5
+// qlog event producers can be created by calling AddProducer.
+// The underlying io.WriteCloser is closed when the last producer is removed.
+type FileSeq struct {
+ w io.WriteCloser
+ enc *jsontext.Encoder
+ referenceTime time.Time
+
+ runStopped chan struct{}
+ encodeErr error
+ events chan event
+ done chan struct{}
+
+ mx sync.Mutex
+ producers int
+ closed bool
+
+ eventSchemas []string
+}
+
+var _ Trace = &FileSeq{}
+
+// NewFileSeq creates a new JSON-SEQ qlog trace to log transport events.
+func NewFileSeq(w io.WriteCloser) *FileSeq {
+ return newFileSeq(w, "transport", nil, nil)
+}
+
+// NewConnectionFileSeq creates a new qlog trace to log connection events.
+func NewConnectionFileSeq(w io.WriteCloser, isClient bool, odcid ConnectionID, eventSchemas []string) *FileSeq {
+ pers := "server"
+ if isClient {
+ pers = "client"
+ }
+ return newFileSeq(w, pers, &odcid, eventSchemas)
+}
+
+func newFileSeq(w io.WriteCloser, pers string, odcid *ConnectionID, eventSchemas []string) *FileSeq {
+ now := time.Now()
+ buf := &bytes.Buffer{}
+ enc := jsontext.NewEncoder(buf)
+ if _, err := buf.Write(recordSeparator); err != nil {
+ panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
+ }
+ if err := (&traceHeader{
+ VantagePointType: pers,
+ GroupID: odcid,
+ ReferenceTime: now,
+ EventSchemas: eventSchemas,
+ }).Encode(enc); err != nil {
+ panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
+ }
+ _, encodeErr := w.Write(buf.Bytes())
+
+ return &FileSeq{
+ w: w,
+ referenceTime: now,
+ enc: jsontext.NewEncoder(w),
+ runStopped: make(chan struct{}),
+ encodeErr: encodeErr,
+ events: make(chan event, eventChanSize),
+ done: make(chan struct{}),
+ eventSchemas: eventSchemas,
+ }
+}
+
+func (t *FileSeq) SupportsSchemas(schema string) bool {
+ return slices.Contains(t.eventSchemas, schema)
+}
+
+func (t *FileSeq) AddProducer() Recorder {
+ t.mx.Lock()
+ defer t.mx.Unlock()
+ if t.closed {
+ return nil
+ }
+
+ t.producers++
+
+ return &Writer{t: t}
+}
+
+func (t *FileSeq) record(eventTime time.Time, details Event) {
+ t.mx.Lock()
+
+ if t.closed {
+ t.mx.Unlock()
+ return
+ }
+ t.mx.Unlock()
+
+ t.events <- event{Time: eventTime, Event: details}
+}
+
+func (t *FileSeq) Run() {
+ defer close(t.runStopped)
+
+ for {
+ select {
+ case <-t.done:
+ for {
+ select {
+ case e := <-t.events:
+ t.encodeEvent(e)
+ default:
+ if t.encodeErr != nil {
+ log.Printf("exporting qlog failed: %s\n", t.encodeErr)
+ }
+ return
+ }
+ }
+ case e := <-t.events:
+ t.encodeEvent(e)
+ }
+ }
+}
+
+func (t *FileSeq) encodeEvent(e event) {
+ if t.encodeErr != nil {
+ return
+ }
+ if _, err := t.w.Write(recordSeparator); err != nil {
+ t.encodeErr = err
+ return
+ }
+ h := encoderHelper{enc: t.enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("time"))
+ h.WriteToken(jsontext.Float(float64(e.Time.Sub(t.referenceTime).Nanoseconds()) / 1e6))
+ h.WriteToken(jsontext.String("name"))
+ h.WriteToken(jsontext.String(e.Event.Name()))
+ h.WriteToken(jsontext.String("data"))
+ if err := e.Event.Encode(t.enc, e.Time); err != nil {
+ t.encodeErr = err
+ return
+ }
+ h.WriteToken(jsontext.EndObject)
+ if h.err != nil {
+ t.encodeErr = h.err
+ }
+}
+
+func (t *FileSeq) removeProducer() {
+ t.mx.Lock()
+ t.producers--
+ last := t.producers == 0
+ if last {
+ t.closed = true
+ }
+ t.mx.Unlock()
+
+ if last {
+ close(t.done)
+ <-t.runStopped // wait for Run to drain and exit
+ _ = t.w.Close()
+ }
+}
+
+type Writer struct {
+ t *FileSeq
+}
+
+func (w *Writer) Close() error {
+ w.t.removeProducer()
+ return nil
+}
+
+func (w *Writer) RecordEvent(ev Event) {
+ w.t.record(time.Now(), ev)
+}
diff --git a/vendor/github.com/quic-go/quic-go/quicvarint/io.go b/vendor/github.com/quic-go/quic-go/quicvarint/io.go
new file mode 100644
index 00000000..8ea10acd
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/quicvarint/io.go
@@ -0,0 +1,98 @@
+package quicvarint
+
+import (
+ "bytes"
+ "io"
+)
+
+// Reader implements both the io.ByteReader and io.Reader interfaces.
+type Reader interface {
+ io.ByteReader
+ io.Reader
+}
+
+var _ Reader = &bytes.Reader{}
+
+// A Peeker can peek bytes without consuming them.
+type Peeker interface {
+ Peek(b []byte) (int, error)
+}
+
+// Peek reads a number in the QUIC varint format without consuming bytes.
+func Peek(p Peeker) (uint64, error) {
+ var b [8]byte
+
+ // first peek 1 byte to determine the varint length
+ if _, err := p.Peek(b[:1]); err != nil {
+ return 0, err
+ }
+
+ l := 1 << (b[0] >> 6) // 1, 2, 4, or 8 bytes
+ if l == 1 {
+ return uint64(b[0] & 0b00111111), nil
+ }
+ if _, err := p.Peek(b[:l]); err != nil {
+ return 0, err
+ }
+ val, _, err := Parse(b[:l])
+ return val, err
+}
+
+type byteReader struct {
+ io.Reader
+}
+
+var _ Reader = &byteReader{}
+
+// NewReader returns a Reader for r.
+// If r already implements both io.ByteReader and io.Reader, NewReader returns r.
+// Otherwise, r is wrapped to add the missing interfaces.
+func NewReader(r io.Reader) Reader {
+ if r, ok := r.(Reader); ok {
+ return r
+ }
+ return &byteReader{r}
+}
+
+func (r *byteReader) ReadByte() (byte, error) {
+ var b [1]byte
+ var n int
+ var err error
+ for n == 0 && err == nil {
+ n, err = r.Read(b[:])
+ }
+
+ if n == 1 && err == io.EOF {
+ err = nil
+ }
+ return b[0], err
+}
+
+// Writer implements both the io.ByteWriter and io.Writer interfaces.
+type Writer interface {
+ io.ByteWriter
+ io.Writer
+}
+
+var _ Writer = &bytes.Buffer{}
+
+type byteWriter struct {
+ io.Writer
+}
+
+var _ Writer = &byteWriter{}
+
+// NewWriter returns a Writer for w.
+// If w already implements both io.ByteWriter and io.Writer, NewWriter returns w.
+// Otherwise, w is wrapped to add the missing interfaces.
+func NewWriter(w io.Writer) Writer {
+ if w, ok := w.(Writer); ok {
+ return w
+ }
+ return &byteWriter{w}
+}
+
+func (w *byteWriter) WriteByte(c byte) error {
+ _, err := w.Write([]byte{c})
+ return err
+}
diff --git a/vendor/github.com/quic-go/quic-go/quicvarint/varint.go b/vendor/github.com/quic-go/quic-go/quicvarint/varint.go
new file mode 100644
index 00000000..52fb153c
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/quicvarint/varint.go
@@ -0,0 +1,180 @@
+package quicvarint
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+)
+
+// taken from the QUIC draft
+const (
+ // Min is the minimum value allowed for a QUIC varint.
+ Min = 0
+
+ // Max is the maximum allowed value for a QUIC varint (2^62-1).
+ Max = maxVarInt8
+
+ maxVarInt1 = 63
+ maxVarInt2 = 16383
+ maxVarInt4 = 1073741823
+ maxVarInt8 = 4611686018427387903
+)
+
+type varintLengthError struct {
+ Num uint64
+}
+
+func (e *varintLengthError) Error() string {
+ return fmt.Sprintf("value doesn't fit into 62 bits: %d", e.Num)
+}
+
+// Read reads a number in the QUIC varint format from r.
+func Read(r io.ByteReader) (uint64, error) {
+ firstByte, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ // the first two bits of the first byte encode the length
+ l := 1 << ((firstByte & 0xc0) >> 6)
+ b1 := firstByte & (0xff - 0xc0)
+ if l == 1 {
+ return uint64(b1), nil
+ }
+ b2, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if l == 2 {
+ return uint64(b2) + uint64(b1)<<8, nil
+ }
+ b3, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b4, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if l == 4 {
+ return uint64(b4) + uint64(b3)<<8 + uint64(b2)<<16 + uint64(b1)<<24, nil
+ }
+ b5, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b6, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b7, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b8, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil
+}
+
+// Parse reads a number in the QUIC varint format.
+// It returns the number of bytes consumed.
+func Parse(b []byte) (uint64 /* value */, int /* bytes consumed */, error) {
+ if len(b) == 0 {
+ return 0, 0, io.EOF
+ }
+
+ first := b[0]
+ switch first >> 6 {
+ case 0: // 1-byte encoding: 00xxxxxx
+ return uint64(first & 0b00111111), 1, nil
+ case 1: // 2-byte encoding: 01xxxxxx
+ if len(b) < 2 {
+ return 0, 0, io.ErrUnexpectedEOF
+ }
+ return uint64(b[1]) | uint64(first&0b00111111)<<8, 2, nil
+ case 2: // 4-byte encoding: 10xxxxxx
+ if len(b) < 4 {
+ return 0, 0, io.ErrUnexpectedEOF
+ }
+ return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(first&0b00111111)<<24, 4, nil
+ case 3: // 8-byte encoding: 00xxxxxx
+ if len(b) < 8 {
+ return 0, 0, io.ErrUnexpectedEOF
+ }
+ // binary.BigEndian.Uint64 only reads the first 8 bytes. Passing the full slice avoids slicing overhead.
+ return binary.BigEndian.Uint64(b) & 0x3fffffffffffffff, 8, nil
+ }
+
+ panic("unreachable")
+}
+
+// Append appends i in the QUIC varint format.
+func Append(b []byte, i uint64) []byte {
+ if i <= maxVarInt1 {
+ return append(b, uint8(i))
+ }
+ if i <= maxVarInt2 {
+ return append(b, []byte{uint8(i>>8) | 0x40, uint8(i)}...)
+ }
+ if i <= maxVarInt4 {
+ return append(b, []byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}...)
+ }
+ if i <= maxVarInt8 {
+ return append(b, []byte{
+ uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32),
+ uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i),
+ }...)
+ }
+ panic(&varintLengthError{Num: i})
+}
+
+// AppendWithLen append i in the QUIC varint format with the desired length.
+func AppendWithLen(b []byte, i uint64, length int) []byte {
+ if length != 1 && length != 2 && length != 4 && length != 8 {
+ panic("invalid varint length")
+ }
+ l := Len(i)
+ if l == length {
+ return Append(b, i)
+ }
+ if l > length {
+ panic(fmt.Sprintf("cannot encode %d in %d bytes", i, length))
+ }
+ switch length {
+ case 2:
+ b = append(b, 0b01000000)
+ case 4:
+ b = append(b, 0b10000000)
+ case 8:
+ b = append(b, 0b11000000)
+ }
+ for range length - l - 1 {
+ b = append(b, 0)
+ }
+ for j := range l {
+ b = append(b, uint8(i>>(8*(l-1-j))))
+ }
+ return b
+}
+
+// Len determines the number of bytes that will be needed to write the number i.
+//
+//gcassert:inline
+func Len(i uint64) int {
+ if i <= maxVarInt1 {
+ return 1
+ }
+ if i <= maxVarInt2 {
+ return 2
+ }
+ if i <= maxVarInt4 {
+ return 4
+ }
+ if i <= maxVarInt8 {
+ return 8
+ }
+ // Don't use a fmt.Sprintf here to format the error message.
+ // The function would then exceed the inlining budget.
+ panic(&varintLengthError{Num: i})
+}
diff --git a/vendor/github.com/quic-go/quic-go/receive_stream.go b/vendor/github.com/quic-go/quic-go/receive_stream.go
new file mode 100644
index 00000000..10a8777f
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/receive_stream.go
@@ -0,0 +1,528 @@
+package quic
+
+import (
+ "fmt"
+ "io"
+ "sync"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/flowcontrol"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+// A ReceiveStream is a unidirectional Receive Stream.
+type ReceiveStream struct {
+ mutex sync.Mutex
+
+ streamID protocol.StreamID
+
+ sender streamSender
+
+ frameQueue *frameSorter
+ finalOffset protocol.ByteCount
+
+ currentFrame []byte
+ currentFrameDone func()
+ readPosInFrame int
+ currentFrameIsLast bool // is the currentFrame the last frame on this stream
+
+ queuedStopSending bool
+ queuedMaxStreamData bool
+
+ // Set once we read the io.EOF or the cancellation error.
+ // Note that for local cancellations, this doesn't necessarily mean that we know the final offset yet.
+ errorRead bool
+ completed bool // set once we've called streamSender.onStreamCompleted
+ cancelledRemotely bool
+ cancelledLocally bool
+ cancelErr *StreamError
+ closeForShutdownErr error
+
+ readPos protocol.ByteCount
+ reliableSize protocol.ByteCount
+
+ readChan chan struct{}
+ readOnce chan struct{} // cap: 1, to protect against concurrent use of Read
+ deadline monotime.Time
+
+ flowController flowcontrol.StreamFlowController
+}
+
+var (
+ _ streamControlFrameGetter = &ReceiveStream{}
+ _ receiveStreamFrameHandler = &ReceiveStream{}
+)
+
+func newReceiveStream(
+ streamID protocol.StreamID,
+ sender streamSender,
+ flowController flowcontrol.StreamFlowController,
+) *ReceiveStream {
+ return &ReceiveStream{
+ streamID: streamID,
+ sender: sender,
+ flowController: flowController,
+ frameQueue: newFrameSorter(),
+ readChan: make(chan struct{}, 1),
+ readOnce: make(chan struct{}, 1),
+ finalOffset: protocol.MaxByteCount,
+ }
+}
+
+// StreamID returns the stream ID.
+func (s *ReceiveStream) StreamID() protocol.StreamID {
+ return s.streamID
+}
+
+// Read reads data from the stream.
+// Read can be made to time out using [ReceiveStream.SetReadDeadline].
+// If the stream was canceled, the error is a [StreamError].
+func (s *ReceiveStream) Read(p []byte) (int, error) {
+ // Concurrent use of Read is not permitted (and doesn't make any sense),
+ // but sometimes people do it anyway.
+ // Make sure that we only execute one call at any given time to avoid hard to debug failures.
+ s.readOnce <- struct{}{}
+ defer func() { <-s.readOnce }()
+
+ s.mutex.Lock()
+ queuedStreamWindowUpdate, queuedConnWindowUpdate, n, err := s.readImpl(p)
+ completed := s.isNewlyCompleted()
+ s.mutex.Unlock()
+
+ if completed {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+ if queuedStreamWindowUpdate {
+ s.sender.onHasStreamControlFrame(s.streamID, s)
+ }
+ if queuedConnWindowUpdate {
+ s.sender.onHasConnectionData()
+ }
+ return n, err
+}
+
+func (s *ReceiveStream) isNewlyCompleted() bool {
+ if s.completed {
+ return false
+ }
+ // We need to know the final offset (either via FIN or RESET_STREAM) for flow control accounting.
+ if s.finalOffset == protocol.MaxByteCount {
+ return false
+ }
+ // We're done with the stream if it was cancelled locally...
+ if s.cancelledLocally {
+ s.completed = true
+ return true
+ }
+ // ... or if the error (either io.EOF or the reset error) was read
+ if s.errorRead {
+ s.completed = true
+ return true
+ }
+ return false
+}
+
+func (s *ReceiveStream) readImpl(p []byte) (hasStreamWindowUpdate bool, hasConnWindowUpdate bool, _ int, _ error) {
+ if s.currentFrameIsLast && s.currentFrame == nil {
+ s.errorRead = true
+ return false, false, 0, io.EOF
+ }
+ if s.cancelledLocally || s.isRemoteCancellationEffective() {
+ s.errorRead = true
+ return false, false, 0, s.cancelErr
+ }
+ if s.closeForShutdownErr != nil {
+ return false, false, 0, s.closeForShutdownErr
+ }
+
+ var bytesRead int
+ var deadlineTimer *time.Timer
+ for bytesRead < len(p) {
+ if s.currentFrame == nil || s.readPosInFrame >= len(s.currentFrame) {
+ s.dequeueNextFrame()
+ }
+ if s.currentFrame == nil && bytesRead > 0 {
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, s.closeForShutdownErr
+ }
+
+ for {
+ // Stop waiting on errors
+ if s.closeForShutdownErr != nil {
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, s.closeForShutdownErr
+ }
+ if s.cancelledLocally || s.isRemoteCancellationEffective() {
+ s.errorRead = true
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, s.cancelErr
+ }
+
+ deadline := s.deadline
+ if !deadline.IsZero() && !monotime.Now().Before(deadline) {
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, errDeadline
+ }
+
+ if s.currentFrame != nil || s.currentFrameIsLast {
+ break
+ }
+
+ s.mutex.Unlock()
+ if deadline.IsZero() {
+ <-s.readChan
+ } else {
+ if deadlineTimer == nil {
+ deadlineTimer = time.NewTimer(monotime.Until(deadline))
+ defer deadlineTimer.Stop()
+ } else {
+ deadlineTimer.Reset(monotime.Until(deadline))
+ }
+ select {
+ case <-s.readChan:
+ case <-deadlineTimer.C:
+ }
+ }
+ s.mutex.Lock()
+ s.dequeueNextFrame()
+ }
+
+ if bytesRead > len(p) {
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, fmt.Errorf("BUG: bytesRead (%d) > len(p) (%d) in stream.Read", bytesRead, len(p))
+ }
+ if s.readPosInFrame > len(s.currentFrame) {
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, fmt.Errorf("BUG: readPosInFrame (%d) > frame.DataLen (%d) in stream.Read", s.readPosInFrame, len(s.currentFrame))
+ }
+ m := copy(p[bytesRead:], s.currentFrame[s.readPosInFrame:])
+
+ // when a RESET_STREAM was received, the flow controller was already
+ // informed about the final offset for this stream
+ if !s.isRemoteCancellationEffective() {
+ hasStream, hasConn := s.flowController.AddBytesRead(protocol.ByteCount(m))
+ if hasStream {
+ s.queuedMaxStreamData = true
+ hasStreamWindowUpdate = true
+ }
+ if hasConn {
+ hasConnWindowUpdate = true
+ }
+ }
+
+ s.readPosInFrame += m
+ s.readPos += protocol.ByteCount(m)
+ bytesRead += m
+
+ if s.isRemoteCancellationEffective() {
+ s.flowController.Abandon()
+ }
+
+ if s.readPosInFrame >= len(s.currentFrame) && s.currentFrameIsLast {
+ s.currentFrame = nil
+ if s.currentFrameDone != nil {
+ s.currentFrameDone()
+ }
+ s.errorRead = true
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, io.EOF
+ }
+ }
+ if s.isRemoteCancellationEffective() {
+ s.errorRead = true
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, s.cancelErr
+ }
+ return hasStreamWindowUpdate, hasConnWindowUpdate, bytesRead, nil
+}
+
+// isRemoteCancellationEffective returns whether the stream was cancelled remotely
+// and all reliable data has been read.
+func (s *ReceiveStream) isRemoteCancellationEffective() bool {
+ return s.cancelledRemotely && s.readPos >= s.reliableSize
+}
+
+// Peek fills b with stream data, without consuming the stream data.
+// It blocks until len(b) bytes are available, or an error occurs.
+// It respects the stream deadline set by SetReadDeadline.
+// If the stream ends before len(b) bytes are available,
+// it returns the number of bytes peeked along with io.EOF.
+func (s *ReceiveStream) Peek(b []byte) (int, error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
+
+ // prevent concurrent use with Read
+ s.readOnce <- struct{}{}
+ defer func() { <-s.readOnce }()
+
+ return s.peekImpl(b)
+}
+
+func (s *ReceiveStream) peekImpl(b []byte) (int, error) {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ var deadlineTimer *time.Timer
+
+ for {
+ if s.currentFrameIsLast && s.currentFrame == nil {
+ return 0, io.EOF
+ }
+ if s.cancelledLocally || s.isRemoteCancellationEffective() {
+ return 0, s.cancelErr
+ }
+ if s.closeForShutdownErr != nil {
+ return 0, s.closeForShutdownErr
+ }
+
+ deadline := s.deadline
+ if !deadline.IsZero() && !monotime.Now().Before(deadline) {
+ return 0, errDeadline
+ }
+
+ if s.currentFrame == nil || s.readPosInFrame >= len(s.currentFrame) {
+ s.dequeueNextFrame()
+ }
+
+ if s.currentFrame != nil && s.readPosInFrame < len(s.currentFrame) {
+ availableInCurrentFrame := len(s.currentFrame) - s.readPosInFrame
+
+ if availableInCurrentFrame >= len(b) {
+ copy(b, s.currentFrame[s.readPosInFrame:])
+ return len(b), nil
+ }
+
+ offset := s.readPos + protocol.ByteCount(availableInCurrentFrame)
+ // First peek, then copy.
+ // This avoids copying data if there's not enough data in the queue.
+ if err := s.frameQueue.Peek(offset, b[availableInCurrentFrame:]); err == nil {
+ copy(b[:availableInCurrentFrame], s.currentFrame[s.readPosInFrame:])
+ return len(b), nil
+ }
+
+ if s.currentFrameIsLast {
+ copy(b[:availableInCurrentFrame], s.currentFrame[s.readPosInFrame:])
+ return availableInCurrentFrame, io.EOF
+ }
+
+ // If the stream was remotely cancelled and the request extends beyond the reliable size,
+ // return the data available with the cancel error (once it's all received).
+ if s.cancelledRemotely && s.readPos+protocol.ByteCount(len(b)) > s.reliableSize {
+ total := int(s.reliableSize - s.readPos)
+ needed := total - availableInCurrentFrame
+ // only return once all available data is contiguous
+ if needed <= 0 || s.frameQueue.Peek(offset, b[availableInCurrentFrame:total]) == nil {
+ copy(b[:availableInCurrentFrame], s.currentFrame[s.readPosInFrame:])
+ return total, s.cancelErr
+ }
+ }
+
+ // If the request extends beyond the stream's final offset,
+ // return the data available with EOF (once it's all received).
+ if s.readPos+protocol.ByteCount(len(b)) > s.finalOffset {
+ total := int(s.finalOffset - s.readPos)
+ needed := total - availableInCurrentFrame
+ // only return once all available data is contiguous
+ if needed <= 0 || s.frameQueue.Peek(offset, b[availableInCurrentFrame:total]) == nil {
+ copy(b[:availableInCurrentFrame], s.currentFrame[s.readPosInFrame:])
+ return total, io.EOF
+ }
+ }
+ }
+
+ if s.currentFrameIsLast || s.readPos >= s.finalOffset {
+ return 0, io.EOF
+ }
+
+ s.mutex.Unlock()
+ if deadline.IsZero() {
+ <-s.readChan
+ } else {
+ if deadlineTimer == nil {
+ deadlineTimer = time.NewTimer(monotime.Until(deadline))
+ defer deadlineTimer.Stop()
+ } else {
+ deadlineTimer.Reset(monotime.Until(deadline))
+ }
+ select {
+ case <-s.readChan:
+ case <-deadlineTimer.C:
+ }
+ }
+ s.mutex.Lock()
+ if s.currentFrame == nil || s.readPosInFrame >= len(s.currentFrame) {
+ s.dequeueNextFrame()
+ }
+ }
+}
+
+func (s *ReceiveStream) dequeueNextFrame() {
+ var offset protocol.ByteCount
+ // We're done with the last frame. Release the buffer.
+ if s.currentFrameDone != nil {
+ s.currentFrameDone()
+ }
+ offset, s.currentFrame, s.currentFrameDone = s.frameQueue.Pop()
+ s.currentFrameIsLast = offset+protocol.ByteCount(len(s.currentFrame)) >= s.finalOffset && !s.cancelledRemotely
+ s.readPosInFrame = 0
+}
+
+// CancelRead aborts receiving on this stream.
+// It instructs the peer to stop transmitting stream data.
+// Read will unblock immediately, and future Read calls will fail.
+// When called multiple times or after reading the io.EOF it is a no-op.
+func (s *ReceiveStream) CancelRead(errorCode StreamErrorCode) {
+ s.mutex.Lock()
+ queuedNewControlFrame := s.cancelReadImpl(errorCode)
+ completed := s.isNewlyCompleted()
+ s.mutex.Unlock()
+
+ if queuedNewControlFrame {
+ s.sender.onHasStreamControlFrame(s.streamID, s)
+ }
+ if completed {
+ s.flowController.Abandon()
+ s.sender.onStreamCompleted(s.streamID)
+ }
+}
+
+func (s *ReceiveStream) cancelReadImpl(errorCode qerr.StreamErrorCode) (queuedNewControlFrame bool) {
+ if s.cancelledLocally { // duplicate call to CancelRead
+ return false
+ }
+ if s.closeForShutdownErr != nil {
+ return false
+ }
+ s.cancelledLocally = true
+ if s.errorRead || s.cancelledRemotely {
+ return false
+ }
+ s.queuedStopSending = true
+ s.cancelErr = &StreamError{StreamID: s.streamID, ErrorCode: errorCode, Remote: false}
+ s.signalRead()
+ return true
+}
+
+func (s *ReceiveStream) handleStreamFrame(frame *wire.StreamFrame, now monotime.Time) error {
+ s.mutex.Lock()
+ err := s.handleStreamFrameImpl(frame, now)
+ completed := s.isNewlyCompleted()
+ s.mutex.Unlock()
+
+ if completed {
+ s.flowController.Abandon()
+ s.sender.onStreamCompleted(s.streamID)
+ }
+ return err
+}
+
+func (s *ReceiveStream) handleStreamFrameImpl(frame *wire.StreamFrame, now monotime.Time) error {
+ maxOffset := frame.Offset + frame.DataLen()
+ if err := s.flowController.UpdateHighestReceived(maxOffset, frame.Fin, now); err != nil {
+ return err
+ }
+ if frame.Fin {
+ s.finalOffset = maxOffset
+ }
+ if s.cancelledLocally {
+ return nil
+ }
+ if err := s.frameQueue.Push(frame.Data, frame.Offset, frame.PutBack); err != nil {
+ return err
+ }
+ s.signalRead()
+ return nil
+}
+
+func (s *ReceiveStream) handleResetStreamFrame(frame *wire.ResetStreamFrame, now monotime.Time) error {
+ s.mutex.Lock()
+ err := s.handleResetStreamFrameImpl(frame, now)
+ completed := s.isNewlyCompleted()
+ s.mutex.Unlock()
+
+ if completed {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+ return err
+}
+
+func (s *ReceiveStream) handleResetStreamFrameImpl(frame *wire.ResetStreamFrame, now monotime.Time) error {
+ if s.closeForShutdownErr != nil {
+ return nil
+ }
+ if err := s.flowController.UpdateHighestReceived(frame.FinalSize, true, now); err != nil {
+ return err
+ }
+ s.finalOffset = frame.FinalSize
+
+ // senders are allowed to reduce the reliable size, but frames might have been reordered
+ if (!s.cancelledRemotely && s.reliableSize == 0) || frame.ReliableSize < s.reliableSize {
+ s.reliableSize = frame.ReliableSize
+ }
+ if s.readPos >= s.reliableSize {
+ // calling Abandon multiple times is a no-op
+ s.flowController.Abandon()
+ }
+ // ignore duplicate RESET_STREAM frames for this stream (after checking their final offset)
+ if s.cancelledRemotely {
+ return nil
+ }
+
+ // don't save the error if the RESET_STREAM frames was received after CancelRead was called
+ if s.cancelledLocally {
+ return nil
+ }
+ s.cancelledRemotely = true
+ s.cancelErr = &StreamError{StreamID: s.streamID, ErrorCode: frame.ErrorCode, Remote: true}
+ s.signalRead()
+ return nil
+}
+
+func (s *ReceiveStream) getControlFrame(now monotime.Time) (_ ackhandler.Frame, ok, hasMore bool) {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ if !s.queuedStopSending && !s.queuedMaxStreamData {
+ return ackhandler.Frame{}, false, false
+ }
+ if s.queuedStopSending {
+ s.queuedStopSending = false
+ return ackhandler.Frame{
+ Frame: &wire.StopSendingFrame{StreamID: s.streamID, ErrorCode: s.cancelErr.ErrorCode},
+ }, true, s.queuedMaxStreamData
+ }
+
+ s.queuedMaxStreamData = false
+ return ackhandler.Frame{
+ Frame: &wire.MaxStreamDataFrame{
+ StreamID: s.streamID,
+ MaximumStreamData: s.flowController.GetWindowUpdate(now),
+ },
+ }, true, false
+}
+
+// SetReadDeadline sets the deadline for future Read calls and
+// any currently-blocked Read call.
+// A zero value for t means Read will not time out.
+func (s *ReceiveStream) SetReadDeadline(t time.Time) error {
+ s.mutex.Lock()
+ s.deadline = monotime.FromTime(t)
+ s.mutex.Unlock()
+ s.signalRead()
+ return nil
+}
+
+// CloseForShutdown closes a stream abruptly.
+// It makes Read unblock (and return the error) immediately.
+// The peer will NOT be informed about this: the stream is closed without sending a FIN or RESET.
+func (s *ReceiveStream) closeForShutdown(err error) {
+ s.mutex.Lock()
+ s.closeForShutdownErr = err
+ s.mutex.Unlock()
+ s.signalRead()
+}
+
+// signalRead performs a non-blocking send on the readChan
+func (s *ReceiveStream) signalRead() {
+ select {
+ case s.readChan <- struct{}{}:
+ default:
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/retransmission_queue.go b/vendor/github.com/quic-go/quic-go/retransmission_queue.go
new file mode 100644
index 00000000..323af5b0
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/retransmission_queue.go
@@ -0,0 +1,158 @@
+package quic
+
+import (
+ "fmt"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type framesToRetransmit struct {
+ crypto []*wire.CryptoFrame
+ other []wire.Frame
+}
+
+type retransmissionQueue struct {
+ initial *framesToRetransmit
+ handshake *framesToRetransmit
+ appData framesToRetransmit
+}
+
+func newRetransmissionQueue() *retransmissionQueue {
+ return &retransmissionQueue{
+ initial: &framesToRetransmit{},
+ handshake: &framesToRetransmit{},
+ }
+}
+
+func (q *retransmissionQueue) addInitial(f wire.Frame) {
+ if q.initial == nil {
+ return
+ }
+ if cf, ok := f.(*wire.CryptoFrame); ok {
+ q.initial.crypto = append(q.initial.crypto, cf)
+ return
+ }
+ q.initial.other = append(q.initial.other, f)
+}
+
+func (q *retransmissionQueue) addHandshake(f wire.Frame) {
+ if q.handshake == nil {
+ return
+ }
+ if cf, ok := f.(*wire.CryptoFrame); ok {
+ q.handshake.crypto = append(q.handshake.crypto, cf)
+ return
+ }
+ q.handshake.other = append(q.handshake.other, f)
+}
+
+func (q *retransmissionQueue) addAppData(f wire.Frame) {
+ switch f := f.(type) {
+ case *wire.StreamFrame:
+ panic("STREAM frames are handled with their respective streams.")
+ case *wire.CryptoFrame:
+ q.appData.crypto = append(q.appData.crypto, f)
+ default:
+ q.appData.other = append(q.appData.other, f)
+ }
+}
+
+func (q *retransmissionQueue) HasData(encLevel protocol.EncryptionLevel) bool {
+ //nolint:exhaustive // 0-RTT data is retransmitted in 1-RTT packets.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return q.initial != nil &&
+ (len(q.initial.crypto) > 0 || len(q.initial.other) > 0)
+ case protocol.EncryptionHandshake:
+ return q.handshake != nil &&
+ (len(q.handshake.crypto) > 0 || len(q.handshake.other) > 0)
+ case protocol.Encryption1RTT:
+ return len(q.appData.crypto) > 0 || len(q.appData.other) > 0
+ }
+ return false
+}
+
+func (q *retransmissionQueue) GetFrame(encLevel protocol.EncryptionLevel, maxLen protocol.ByteCount, v protocol.Version) wire.Frame {
+ var r *framesToRetransmit
+ //nolint:exhaustive // 0-RTT data is retransmitted in 1-RTT packets.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ r = q.initial
+ case protocol.EncryptionHandshake:
+ r = q.handshake
+ case protocol.Encryption1RTT:
+ r = &q.appData
+ }
+ if r == nil {
+ return nil
+ }
+
+ if len(r.crypto) > 0 {
+ f := r.crypto[0]
+ newFrame, needsSplit := f.MaybeSplitOffFrame(maxLen, v)
+ if newFrame == nil && !needsSplit { // the whole frame fits
+ r.crypto = r.crypto[1:]
+ return f
+ }
+ if newFrame != nil { // frame was split. Leave the original frame in the queue.
+ return newFrame
+ }
+ }
+ if len(r.other) == 0 {
+ return nil
+ }
+ f := r.other[0]
+ if f.Length(v) > maxLen {
+ return nil
+ }
+ r.other = r.other[1:]
+ return f
+}
+
+func (q *retransmissionQueue) DropPackets(encLevel protocol.EncryptionLevel) {
+ //nolint:exhaustive // Can only drop Initial and Handshake packet number space.
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ q.initial = nil
+ case protocol.EncryptionHandshake:
+ q.handshake = nil
+ default:
+ panic(fmt.Sprintf("unexpected encryption level: %s", encLevel))
+ }
+}
+
+func (q *retransmissionQueue) AckHandler(encLevel protocol.EncryptionLevel) ackhandler.FrameHandler {
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return (*retransmissionQueueInitialAckHandler)(q)
+ case protocol.EncryptionHandshake:
+ return (*retransmissionQueueHandshakeAckHandler)(q)
+ case protocol.Encryption0RTT, protocol.Encryption1RTT:
+ return (*retransmissionQueueAppDataAckHandler)(q)
+ }
+ return nil
+}
+
+type retransmissionQueueInitialAckHandler retransmissionQueue
+
+func (q *retransmissionQueueInitialAckHandler) OnAcked(wire.Frame) {}
+func (q *retransmissionQueueInitialAckHandler) OnLost(f wire.Frame) {
+ (*retransmissionQueue)(q).addInitial(f)
+}
+
+type retransmissionQueueHandshakeAckHandler retransmissionQueue
+
+func (q *retransmissionQueueHandshakeAckHandler) OnAcked(wire.Frame) {}
+func (q *retransmissionQueueHandshakeAckHandler) OnLost(f wire.Frame) {
+ (*retransmissionQueue)(q).addHandshake(f)
+}
+
+type retransmissionQueueAppDataAckHandler retransmissionQueue
+
+func (q *retransmissionQueueAppDataAckHandler) OnAcked(wire.Frame) {}
+func (q *retransmissionQueueAppDataAckHandler) OnLost(f wire.Frame) {
+ (*retransmissionQueue)(q).addAppData(f)
+}
diff --git a/vendor/github.com/quic-go/quic-go/send_conn.go b/vendor/github.com/quic-go/quic-go/send_conn.go
new file mode 100644
index 00000000..4cbffc71
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/send_conn.go
@@ -0,0 +1,124 @@
+package quic
+
+import (
+ "net"
+ "sync/atomic"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+// A sendConn allows sending using a simple Write() on a non-connected packet conn.
+type sendConn interface {
+ Write(b []byte, gsoSize uint16, ecn protocol.ECN) error
+ WriteTo([]byte, net.Addr, packetInfo) error
+ Close() error
+ LocalAddr() net.Addr
+ RemoteAddr() net.Addr
+ ChangeRemoteAddr(addr net.Addr, info packetInfo)
+
+ capabilities() connCapabilities
+}
+
+type remoteAddrInfo struct {
+ addr net.Addr
+ oob []byte
+}
+
+type sconn struct {
+ rawConn
+
+ localAddr net.Addr
+
+ remoteAddrInfo atomic.Pointer[remoteAddrInfo]
+
+ logger utils.Logger
+
+ // If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled.
+ gotGSOError bool
+ // Used to catch the error sometimes returned by the first sendmsg call on Linux,
+ // see https://github.com/golang/go/issues/63322.
+ wroteFirstPacket bool
+}
+
+var _ sendConn = &sconn{}
+
+func newSendConn(c rawConn, remote net.Addr, info packetInfo, logger utils.Logger) *sconn {
+ localAddr := c.LocalAddr()
+ if info.addr.IsValid() {
+ if udpAddr, ok := localAddr.(*net.UDPAddr); ok {
+ addrCopy := *udpAddr
+ addrCopy.IP = info.addr.AsSlice()
+ localAddr = &addrCopy
+ }
+ }
+
+ oob := info.OOB()
+ // increase oob slice capacity, so we can add the UDP_SEGMENT and ECN control messages without allocating
+ l := len(oob)
+ oob = append(oob, make([]byte, 64)...)[:l]
+ sc := &sconn{
+ rawConn: c,
+ localAddr: localAddr,
+ logger: logger,
+ }
+ sc.remoteAddrInfo.Store(&remoteAddrInfo{
+ addr: remote,
+ oob: oob,
+ })
+ return sc
+}
+
+func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
+ ai := c.remoteAddrInfo.Load()
+ err := c.writePacket(p, ai.addr, ai.oob, gsoSize, ecn)
+ if err != nil && isGSOError(err) {
+ // disable GSO for future calls
+ c.gotGSOError = true
+ if c.logger.Debug() {
+ c.logger.Debugf("GSO failed when sending to %s", ai.addr)
+ }
+ // send out the packets one by one
+ for len(p) > 0 {
+ l := min(len(p), int(gsoSize))
+ if err := c.writePacket(p[:l], ai.addr, ai.oob, 0, ecn); err != nil {
+ return err
+ }
+ p = p[l:]
+ }
+ return nil
+ }
+ return err
+}
+
+func (c *sconn) writePacket(p []byte, addr net.Addr, oob []byte, gsoSize uint16, ecn protocol.ECN) error {
+ _, err := c.WritePacket(p, addr, oob, gsoSize, ecn)
+ if err != nil && !c.wroteFirstPacket && isPermissionError(err) {
+ _, err = c.WritePacket(p, addr, oob, gsoSize, ecn)
+ }
+ c.wroteFirstPacket = true
+ return err
+}
+
+func (c *sconn) WriteTo(b []byte, addr net.Addr, info packetInfo) error {
+ _, err := c.WritePacket(b, addr, info.OOB(), 0, protocol.ECNUnsupported)
+ return err
+}
+
+func (c *sconn) capabilities() connCapabilities {
+ capabilities := c.rawConn.capabilities()
+ if capabilities.GSO {
+ capabilities.GSO = !c.gotGSOError
+ }
+ return capabilities
+}
+
+func (c *sconn) ChangeRemoteAddr(addr net.Addr, info packetInfo) {
+ c.remoteAddrInfo.Store(&remoteAddrInfo{
+ addr: addr,
+ oob: info.OOB(),
+ })
+}
+
+func (c *sconn) RemoteAddr() net.Addr { return c.remoteAddrInfo.Load().addr }
+func (c *sconn) LocalAddr() net.Addr { return c.localAddr }
diff --git a/vendor/github.com/quic-go/quic-go/send_queue.go b/vendor/github.com/quic-go/quic-go/send_queue.go
new file mode 100644
index 00000000..c8060cb3
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/send_queue.go
@@ -0,0 +1,112 @@
+package quic
+
+import (
+ "net"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+type sender interface {
+ Send(p *packetBuffer, gsoSize uint16, ecn protocol.ECN)
+ SendProbe(*packetBuffer, net.Addr, packetInfo)
+ Run() error
+ WouldBlock() bool
+ Available() <-chan struct{}
+ Close()
+}
+
+type queueEntry struct {
+ buf *packetBuffer
+ gsoSize uint16
+ ecn protocol.ECN
+}
+
+type sendQueue struct {
+ queue chan queueEntry
+ closeCalled chan struct{} // runStopped when Close() is called
+ runStopped chan struct{} // runStopped when the run loop returns
+ available chan struct{}
+ conn sendConn
+}
+
+var _ sender = &sendQueue{}
+
+const sendQueueCapacity = 8
+
+func newSendQueue(conn sendConn) sender {
+ return &sendQueue{
+ conn: conn,
+ runStopped: make(chan struct{}),
+ closeCalled: make(chan struct{}),
+ available: make(chan struct{}, 1),
+ queue: make(chan queueEntry, sendQueueCapacity),
+ }
+}
+
+// Send sends out a packet. It's guaranteed to not block.
+// Callers need to make sure that there's actually space in the send queue by calling WouldBlock.
+// Otherwise Send will panic.
+func (h *sendQueue) Send(p *packetBuffer, gsoSize uint16, ecn protocol.ECN) {
+ select {
+ case h.queue <- queueEntry{buf: p, gsoSize: gsoSize, ecn: ecn}:
+ // clear available channel if we've reached capacity
+ if len(h.queue) == sendQueueCapacity {
+ select {
+ case <-h.available:
+ default:
+ }
+ }
+ case <-h.runStopped:
+ default:
+ panic("sendQueue.Send would have blocked")
+ }
+}
+
+func (h *sendQueue) SendProbe(p *packetBuffer, addr net.Addr, info packetInfo) {
+ h.conn.WriteTo(p.Data, addr, info)
+}
+
+func (h *sendQueue) WouldBlock() bool {
+ return len(h.queue) == sendQueueCapacity
+}
+
+func (h *sendQueue) Available() <-chan struct{} {
+ return h.available
+}
+
+func (h *sendQueue) Run() error {
+ defer close(h.runStopped)
+ var shouldClose bool
+ for {
+ if shouldClose && len(h.queue) == 0 {
+ return nil
+ }
+ select {
+ case <-h.closeCalled:
+ h.closeCalled = nil // prevent this case from being selected again
+ // make sure that all queued packets are actually sent out
+ shouldClose = true
+ case e := <-h.queue:
+ if err := h.conn.Write(e.buf.Data, e.gsoSize, e.ecn); err != nil {
+ // This additional check enables:
+ // 1. Checking for "datagram too large" message from the kernel, as such,
+ // 2. Path MTU discovery,and
+ // 3. Eventual detection of loss PingFrame.
+ if !isSendMsgSizeErr(err) {
+ return err
+ }
+ }
+ e.buf.Release()
+ select {
+ case h.available <- struct{}{}:
+ default:
+ }
+ }
+ }
+}
+
+func (h *sendQueue) Close() {
+ close(h.closeCalled)
+ // wait until the run loop returned
+ <-h.runStopped
+}
diff --git a/vendor/github.com/quic-go/quic-go/send_stream.go b/vendor/github.com/quic-go/quic-go/send_stream.go
new file mode 100644
index 00000000..2da51fc5
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/send_stream.go
@@ -0,0 +1,768 @@
+package quic
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/flowcontrol"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+// A SendStream is a unidirectional Send Stream.
+type SendStream struct {
+ mutex sync.Mutex
+
+ numOutstandingFrames int64 // outstanding STREAM and RESET_STREAM frames
+ retransmissionQueue []*wire.StreamFrame
+
+ ctx context.Context
+ ctxCancel context.CancelCauseFunc
+
+ streamID protocol.StreamID
+ sender streamSender
+
+ // reliableSize is the portion of the stream that needs to be transmitted reliably,
+ // even if the stream is cancelled.
+ // This requires the peer to support RESET_STREAM_AT.
+ // This value should not be accessed directly, but only through the reliableOffset method.
+ // This method returns 0 if the peer doesn't support the RESET_STREAM_AT extension.
+ reliableSize protocol.ByteCount
+ writeOffset protocol.ByteCount
+
+ shutdownErr error
+ resetErr *StreamError
+ queuedResetStreamFrame *wire.ResetStreamFrame
+
+ supportsResetStreamAt bool
+ finishedWriting bool // set once Close() is called
+ finSent bool // set when a STREAM_FRAME with FIN bit has been sent
+ // Set when the application knows about the cancellation.
+ // This can happen because the application called CancelWrite,
+ // or because Write returned the error (for remote cancellations).
+ cancellationFlagged bool
+ completed bool // set when this stream has been reported to the streamSender as completed
+
+ dataForWriting []byte // during a Write() call, this slice is the part of p that still needs to be sent out
+ nextFrame *wire.StreamFrame
+
+ writeChan chan struct{}
+ writeOnce chan struct{}
+ deadline monotime.Time
+
+ flowController flowcontrol.StreamFlowController
+}
+
+var (
+ _ streamControlFrameGetter = &SendStream{}
+ _ outgoingStream = &SendStream{}
+ _ sendStreamFrameHandler = &SendStream{}
+)
+
+func newSendStream(
+ ctx context.Context,
+ streamID protocol.StreamID,
+ sender streamSender,
+ flowController flowcontrol.StreamFlowController,
+ supportsResetStreamAt bool,
+) *SendStream {
+ s := &SendStream{
+ streamID: streamID,
+ sender: sender,
+ flowController: flowController,
+ writeChan: make(chan struct{}, 1),
+ writeOnce: make(chan struct{}, 1), // cap: 1, to protect against concurrent use of Write
+ supportsResetStreamAt: supportsResetStreamAt,
+ }
+ s.ctx, s.ctxCancel = context.WithCancelCause(ctx)
+ return s
+}
+
+// StreamID returns the stream ID.
+func (s *SendStream) StreamID() StreamID {
+ return s.streamID // same for receiveStream and sendStream
+}
+
+// Write writes data to the stream.
+// Write can be made to time out using [SendStream.SetWriteDeadline].
+// If the stream was canceled, the error is a [StreamError].
+func (s *SendStream) Write(p []byte) (int, error) {
+ // Concurrent use of Write is not permitted (and doesn't make any sense),
+ // but sometimes people do it anyway.
+ // Make sure that we only execute one call at any given time to avoid hard to debug failures.
+ s.writeOnce <- struct{}{}
+ defer func() { <-s.writeOnce }()
+
+ isNewlyCompleted, n, err := s.write(p)
+ if isNewlyCompleted {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+ return n, err
+}
+
+func (s *SendStream) write(p []byte) (bool /* is newly completed */, int, error) {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ if s.resetErr != nil {
+ s.cancellationFlagged = true
+ return s.isNewlyCompleted(), 0, s.resetErr
+ }
+ if s.shutdownErr != nil {
+ return false, 0, s.shutdownErr
+ }
+ if s.finishedWriting {
+ return false, 0, fmt.Errorf("write on closed stream %d", s.streamID)
+ }
+ if !s.deadline.IsZero() && !monotime.Now().Before(s.deadline) {
+ return false, 0, errDeadline
+ }
+ if len(p) == 0 {
+ return false, 0, nil
+ }
+
+ s.dataForWriting = p
+
+ var (
+ deadlineTimer *time.Timer
+ bytesWritten int
+ notifiedSender bool
+ )
+ for {
+ var copied bool
+ var deadline monotime.Time
+ // As soon as dataForWriting becomes smaller than a certain size x, we copy all the data to a STREAM frame (s.nextFrame),
+ // which can then be popped the next time we assemble a packet.
+ // This allows us to return Write() when all data but x bytes have been sent out.
+ // When the user now calls Close(), this is much more likely to happen before we popped that last STREAM frame,
+ // allowing us to set the FIN bit on that frame (instead of sending an empty STREAM frame with FIN).
+ if s.canBufferStreamFrame() && len(s.dataForWriting) > 0 {
+ if s.nextFrame == nil {
+ f := wire.GetStreamFrame()
+ f.Offset = s.writeOffset
+ f.StreamID = s.streamID
+ f.DataLenPresent = true
+ f.Data = f.Data[:len(s.dataForWriting)]
+ copy(f.Data, s.dataForWriting)
+ s.nextFrame = f
+ } else {
+ l := len(s.nextFrame.Data)
+ s.nextFrame.Data = s.nextFrame.Data[:l+len(s.dataForWriting)]
+ copy(s.nextFrame.Data[l:], s.dataForWriting)
+ }
+ s.dataForWriting = nil
+ bytesWritten = len(p)
+ copied = true
+ } else {
+ bytesWritten = len(p) - len(s.dataForWriting)
+ deadline = s.deadline
+ if !deadline.IsZero() {
+ if !monotime.Now().Before(deadline) {
+ s.dataForWriting = nil
+ return false, bytesWritten, errDeadline
+ }
+ if deadlineTimer == nil {
+ deadlineTimer = time.NewTimer(monotime.Until(deadline))
+ defer deadlineTimer.Stop()
+ } else {
+ deadlineTimer.Reset(monotime.Until(deadline))
+ }
+ }
+ if s.dataForWriting == nil || s.shutdownErr != nil || s.resetErr != nil {
+ break
+ }
+ }
+
+ s.mutex.Unlock()
+ if !notifiedSender {
+ s.sender.onHasStreamData(s.streamID, s) // must be called without holding the mutex
+ notifiedSender = true
+ }
+ if copied {
+ s.mutex.Lock()
+ break
+ }
+ if deadline.IsZero() {
+ <-s.writeChan
+ } else {
+ select {
+ case <-s.writeChan:
+ case <-deadlineTimer.C:
+ }
+ }
+ s.mutex.Lock()
+ }
+
+ if bytesWritten == len(p) {
+ return false, bytesWritten, nil
+ }
+ if s.shutdownErr != nil {
+ return false, bytesWritten, s.shutdownErr
+ }
+ if s.resetErr != nil {
+ s.cancellationFlagged = true
+ return s.isNewlyCompleted(), bytesWritten, s.resetErr
+ }
+ return false, bytesWritten, nil
+}
+
+func (s *SendStream) canBufferStreamFrame() bool {
+ var l protocol.ByteCount
+ if s.nextFrame != nil {
+ l = s.nextFrame.DataLen()
+ }
+ return l+protocol.ByteCount(len(s.dataForWriting)) <= protocol.MaxPacketBufferSize
+}
+
+// popStreamFrame returns the next STREAM frame that is supposed to be sent on this stream
+// maxBytes is the maximum length this frame (including frame header) will have.
+func (s *SendStream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ ackhandler.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMore bool) {
+ s.mutex.Lock()
+ f, blocked, hasMoreData := s.popNewOrRetransmittedStreamFrame(maxBytes, v)
+ if f != nil {
+ s.numOutstandingFrames++
+ }
+ s.mutex.Unlock()
+
+ if f == nil {
+ return ackhandler.StreamFrame{}, blocked, hasMoreData
+ }
+ return ackhandler.StreamFrame{
+ Frame: f,
+ Handler: (*sendStreamAckHandler)(s),
+ }, blocked, hasMoreData
+}
+
+func (s *SendStream) popNewOrRetransmittedStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ *wire.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMoreData bool) {
+ if s.shutdownErr != nil {
+ return nil, nil, false
+ }
+ if s.resetErr != nil {
+ reliableOffset := s.reliableOffset()
+ if reliableOffset == 0 || (s.writeOffset >= reliableOffset && len(s.retransmissionQueue) == 0) {
+ return nil, nil, false
+ }
+ }
+
+ if len(s.retransmissionQueue) > 0 {
+ f, hasMoreRetransmissions := s.maybeGetRetransmission(maxBytes, v)
+ if f != nil || hasMoreRetransmissions {
+ if f == nil {
+ return nil, nil, true
+ }
+ // We always claim that we have more data to send.
+ // This might be incorrect, in which case there'll be a spurious call to popStreamFrame in the future.
+ return f, nil, true
+ }
+ }
+
+ if len(s.dataForWriting) == 0 && s.nextFrame == nil {
+ if s.finishedWriting && !s.finSent {
+ s.finSent = true
+ return &wire.StreamFrame{
+ StreamID: s.streamID,
+ Offset: s.writeOffset,
+ DataLenPresent: true,
+ Fin: true,
+ }, nil, false
+ }
+ return nil, nil, false
+ }
+
+ maxDataLen := s.flowController.SendWindowSize()
+ if maxDataLen == 0 {
+ return nil, nil, true
+ }
+
+ // if the stream is canceled, only data up to the reliable size needs to be sent
+ reliableOffset := s.reliableOffset()
+ if s.resetErr != nil && reliableOffset > 0 {
+ maxDataLen = min(maxDataLen, reliableOffset-s.writeOffset)
+ }
+ f, hasMoreData := s.popNewStreamFrame(maxBytes, maxDataLen, v)
+ if f == nil {
+ return nil, nil, hasMoreData
+ }
+ if f.DataLen() > 0 {
+ s.writeOffset += f.DataLen()
+ s.flowController.AddBytesSent(f.DataLen())
+ }
+ if s.resetErr != nil && s.writeOffset >= reliableOffset {
+ hasMoreData = false
+ }
+ var blocked *wire.StreamDataBlockedFrame
+ // If the entire send window is used, the stream might have become blocked on stream-level flow control.
+ // This is not guaranteed though, because the stream might also have been blocked on connection-level flow control.
+ if f.DataLen() == maxDataLen && s.flowController.IsNewlyBlocked() {
+ blocked = &wire.StreamDataBlockedFrame{StreamID: s.streamID, MaximumStreamData: s.writeOffset}
+ }
+ f.Fin = s.finishedWriting && s.dataForWriting == nil && s.nextFrame == nil && !s.finSent
+ if f.Fin {
+ s.finSent = true
+ }
+ return f, blocked, hasMoreData
+}
+
+// popNewStreamFrame returns a new STREAM frame to send for this stream
+// hasMoreData says if there's more data to send, *not* taking into account the reliable size
+func (s *SendStream) popNewStreamFrame(maxBytes, maxDataLen protocol.ByteCount, v protocol.Version) (_ *wire.StreamFrame, hasMoreData bool) {
+ if s.nextFrame != nil {
+ maxDataLen := min(maxDataLen, s.nextFrame.MaxDataLen(maxBytes, v))
+ if maxDataLen == 0 {
+ return nil, true
+ }
+ nextFrame := s.nextFrame
+ s.nextFrame = nil
+ if nextFrame.DataLen() > maxDataLen {
+ s.nextFrame = wire.GetStreamFrame()
+ s.nextFrame.StreamID = s.streamID
+ s.nextFrame.Offset = s.writeOffset + maxDataLen
+ s.nextFrame.Data = s.nextFrame.Data[:nextFrame.DataLen()-maxDataLen]
+ s.nextFrame.DataLenPresent = true
+ copy(s.nextFrame.Data, nextFrame.Data[maxDataLen:])
+ nextFrame.Data = nextFrame.Data[:maxDataLen]
+ } else {
+ s.signalWrite()
+ }
+ return nextFrame, s.nextFrame != nil || s.dataForWriting != nil
+ }
+
+ f := wire.GetStreamFrame()
+ f.Fin = false
+ f.StreamID = s.streamID
+ f.Offset = s.writeOffset
+ f.DataLenPresent = true
+ f.Data = f.Data[:0]
+
+ hasMoreData = s.popNewStreamFrameWithoutBuffer(f, maxBytes, maxDataLen, v)
+ if len(f.Data) == 0 && !f.Fin {
+ f.PutBack()
+ return nil, hasMoreData
+ }
+ return f, hasMoreData
+}
+
+func (s *SendStream) popNewStreamFrameWithoutBuffer(f *wire.StreamFrame, maxBytes, sendWindow protocol.ByteCount, v protocol.Version) bool {
+ maxDataLen := f.MaxDataLen(maxBytes, v)
+ if maxDataLen == 0 { // a STREAM frame must have at least one byte of data
+ return s.dataForWriting != nil || s.nextFrame != nil || s.finishedWriting
+ }
+ s.getDataForWriting(f, min(maxDataLen, sendWindow))
+
+ return s.dataForWriting != nil || s.nextFrame != nil || s.finishedWriting
+}
+
+func (s *SendStream) maybeGetRetransmission(maxBytes protocol.ByteCount, v protocol.Version) (*wire.StreamFrame, bool /* has more retransmissions */) {
+ f := s.retransmissionQueue[0]
+ newFrame, needsSplit := f.MaybeSplitOffFrame(maxBytes, v)
+ if needsSplit {
+ return newFrame, true
+ }
+ s.retransmissionQueue = s.retransmissionQueue[1:]
+ return f, len(s.retransmissionQueue) > 0
+}
+
+func (s *SendStream) getDataForWriting(f *wire.StreamFrame, maxBytes protocol.ByteCount) {
+ if protocol.ByteCount(len(s.dataForWriting)) <= maxBytes {
+ f.Data = f.Data[:len(s.dataForWriting)]
+ copy(f.Data, s.dataForWriting)
+ s.dataForWriting = nil
+ s.signalWrite()
+ return
+ }
+ f.Data = f.Data[:maxBytes]
+ copy(f.Data, s.dataForWriting)
+ s.dataForWriting = s.dataForWriting[maxBytes:]
+ if s.canBufferStreamFrame() {
+ s.signalWrite()
+ }
+}
+
+func (s *SendStream) isNewlyCompleted() bool {
+ if s.completed {
+ return false
+ }
+ if s.nextFrame != nil && s.nextFrame.DataLen() > 0 {
+ return false
+ }
+ // We need to keep the stream around until all frames have been sent and acknowledged.
+ if s.numOutstandingFrames > 0 || len(s.retransmissionQueue) > 0 || s.queuedResetStreamFrame != nil {
+ return false
+ }
+ // The stream is completed if we sent the FIN.
+ if s.finSent {
+ s.completed = true
+ return true
+ }
+ // The stream is also completed if:
+ // 1. the application called CancelWrite, or
+ // 2. we received a STOP_SENDING, and
+ // * the application consumed the error via Write, or
+ // * the application called Close
+ if s.resetErr != nil && (s.cancellationFlagged || s.finishedWriting) {
+ s.completed = true
+ return true
+ }
+ return false
+}
+
+// Close closes the write-direction of the stream.
+// Future calls to Write are not permitted after calling Close.
+// It must not be called concurrently with Write.
+// It must not be called after calling CancelWrite.
+func (s *SendStream) Close() error {
+ s.mutex.Lock()
+ if s.shutdownErr != nil || s.finishedWriting {
+ s.mutex.Unlock()
+ return nil
+ }
+ s.finishedWriting = true
+ cancelled := s.resetErr != nil
+ if cancelled {
+ s.cancellationFlagged = true
+ }
+ completed := s.isNewlyCompleted()
+ s.mutex.Unlock()
+
+ if completed {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+ if cancelled {
+ return fmt.Errorf("close called for canceled stream %d", s.streamID)
+ }
+ s.sender.onHasStreamData(s.streamID, s) // need to send the FIN, must be called without holding the mutex
+
+ s.ctxCancel(nil)
+ return nil
+}
+
+// SetReliableBoundary marks the data written to this stream so far as reliable.
+// It is valid to call this function multiple times, thereby increasing the reliable size.
+// It only has an effect if the peer enabled support for the RESET_STREAM_AT extension,
+// otherwise, it is a no-op.
+func (s *SendStream) SetReliableBoundary() {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ s.reliableSize = s.writeOffset
+ if s.nextFrame != nil {
+ s.reliableSize += s.nextFrame.DataLen()
+ }
+}
+
+// returnFramesToPool returns all queued frames to the sync.Pool
+func (s *SendStream) returnFramesToPool() {
+ for _, f := range s.retransmissionQueue {
+ f.PutBack()
+ }
+ clear(s.retransmissionQueue)
+ s.retransmissionQueue = nil
+ if s.nextFrame != nil {
+ s.nextFrame.PutBack()
+ s.nextFrame = nil
+ }
+}
+
+// CancelWrite aborts sending on this stream.
+// Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably.
+// Write will unblock immediately, and future calls to Write will fail.
+// When called multiple times it is a no-op.
+// When called after Close, it aborts reliable delivery of outstanding stream data.
+// Note that there is no guarantee if the peer will receive the FIN or the cancellation error first.
+func (s *SendStream) CancelWrite(errorCode StreamErrorCode) {
+ s.mutex.Lock()
+ if s.shutdownErr != nil {
+ s.mutex.Unlock()
+ return
+ }
+
+ s.cancellationFlagged = true
+
+ if s.resetErr != nil {
+ completed := s.isNewlyCompleted()
+ s.mutex.Unlock()
+ // The user has called CancelWrite. If the previous cancellation was because of a
+ // STOP_SENDING, we don't need to flag the error to the user anymore.
+ if completed {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+ return
+ }
+ s.resetErr = &StreamError{StreamID: s.streamID, ErrorCode: errorCode, Remote: false}
+ s.ctxCancel(s.resetErr)
+
+ reliableOffset := s.reliableOffset()
+ if reliableOffset == 0 {
+ s.numOutstandingFrames = 0
+ s.returnFramesToPool()
+ }
+ s.queuedResetStreamFrame = &wire.ResetStreamFrame{
+ StreamID: s.streamID,
+ FinalSize: max(s.writeOffset, reliableOffset),
+ ErrorCode: errorCode,
+ // if the peer doesn't support the extension, the reliable offset will always be 0
+ ReliableSize: reliableOffset,
+ }
+ if reliableOffset > 0 {
+ if s.nextFrame != nil {
+ if s.nextFrame.Offset >= reliableOffset {
+ s.nextFrame.PutBack()
+ s.nextFrame = nil
+ } else if s.nextFrame.Offset+s.nextFrame.DataLen() > reliableOffset {
+ s.nextFrame.Data = s.nextFrame.Data[:reliableOffset-s.nextFrame.Offset]
+ }
+ }
+ if len(s.retransmissionQueue) > 0 {
+ retransmissionQueue := make([]*wire.StreamFrame, 0, len(s.retransmissionQueue))
+ for _, f := range s.retransmissionQueue {
+ if f.Offset >= reliableOffset {
+ f.PutBack()
+ continue
+ }
+ if f.Offset+f.DataLen() <= reliableOffset {
+ retransmissionQueue = append(retransmissionQueue, f)
+ } else {
+ f.Data = f.Data[:reliableOffset-f.Offset]
+ retransmissionQueue = append(retransmissionQueue, f)
+ }
+ }
+ s.retransmissionQueue = retransmissionQueue
+ }
+ }
+ s.mutex.Unlock()
+
+ s.signalWrite()
+ s.sender.onHasStreamControlFrame(s.streamID, s)
+}
+
+func (s *SendStream) enableResetStreamAt() {
+ s.mutex.Lock()
+ s.supportsResetStreamAt = true
+ s.mutex.Unlock()
+}
+
+func (s *SendStream) updateSendWindow(limit protocol.ByteCount) {
+ updated := s.flowController.UpdateSendWindow(limit)
+ if !updated { // duplicate or reordered MAX_STREAM_DATA frame
+ return
+ }
+ s.mutex.Lock()
+ hasStreamData := s.dataForWriting != nil || s.nextFrame != nil
+ s.mutex.Unlock()
+ if hasStreamData {
+ s.sender.onHasStreamData(s.streamID, s)
+ }
+}
+
+func (s *SendStream) handleStopSendingFrame(f *wire.StopSendingFrame) {
+ s.mutex.Lock()
+ if s.shutdownErr != nil {
+ s.mutex.Unlock()
+ return
+ }
+
+ // If the stream was already cancelled (either locally, or due to a previous STOP_SENDING frame),
+ // there's nothing else to do.
+ if s.resetErr != nil && s.reliableOffset() == 0 {
+ s.mutex.Unlock()
+ return
+ }
+ // if the peer stopped reading from the stream, there's no need to transmit any data reliably
+ s.reliableSize = 0
+ s.numOutstandingFrames = 0
+ s.returnFramesToPool()
+ if s.resetErr == nil {
+ s.resetErr = &StreamError{StreamID: s.streamID, ErrorCode: f.ErrorCode, Remote: true}
+ s.ctxCancel(s.resetErr)
+ }
+ s.queuedResetStreamFrame = &wire.ResetStreamFrame{
+ StreamID: s.streamID,
+ FinalSize: s.writeOffset,
+ ErrorCode: s.resetErr.ErrorCode,
+ }
+ s.mutex.Unlock()
+
+ s.signalWrite()
+ s.sender.onHasStreamControlFrame(s.streamID, s)
+}
+
+func (s *SendStream) getControlFrame(monotime.Time) (_ ackhandler.Frame, ok, hasMore bool) {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ if s.queuedResetStreamFrame == nil {
+ return ackhandler.Frame{}, false, false
+ }
+ s.numOutstandingFrames++
+ f := ackhandler.Frame{
+ Frame: s.queuedResetStreamFrame,
+ Handler: (*sendStreamResetStreamHandler)(s),
+ }
+ s.queuedResetStreamFrame = nil
+ return f, true, false
+}
+
+func (s *SendStream) reliableOffset() protocol.ByteCount {
+ if !s.supportsResetStreamAt {
+ return 0
+ }
+ return s.reliableSize
+}
+
+// The Context is canceled as soon as the write-side of the stream is closed.
+// This happens when Close() or CancelWrite() is called, or when the peer
+// cancels the read-side of their stream.
+// The cancellation cause is set to the error that caused the stream to
+// close, or `context.Canceled` in case the stream is closed without error.
+func (s *SendStream) Context() context.Context {
+ return s.ctx
+}
+
+// SetWriteDeadline sets the deadline for future Write calls
+// and any currently-blocked Write call.
+// Even if write times out, it may return n > 0, indicating that
+// some data was successfully written.
+// A zero value for t means Write will not time out.
+func (s *SendStream) SetWriteDeadline(t time.Time) error {
+ s.mutex.Lock()
+ s.deadline = monotime.FromTime(t)
+ s.mutex.Unlock()
+ s.signalWrite()
+ return nil
+}
+
+// CloseForShutdown closes a stream abruptly.
+// It makes Write unblock (and return the error) immediately.
+// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST.
+func (s *SendStream) closeForShutdown(err error) {
+ s.mutex.Lock()
+ if s.shutdownErr == nil && !s.finishedWriting {
+ s.shutdownErr = err
+ s.returnFramesToPool()
+ }
+ s.mutex.Unlock()
+ s.ctxCancel(err)
+ s.signalWrite()
+}
+
+// signalWrite performs a non-blocking send on the writeChan
+func (s *SendStream) signalWrite() {
+ select {
+ case s.writeChan <- struct{}{}:
+ default:
+ }
+}
+
+type sendStreamAckHandler SendStream
+
+var _ ackhandler.FrameHandler = &sendStreamAckHandler{}
+
+func (s *sendStreamAckHandler) OnAcked(f wire.Frame) {
+ sf := f.(*wire.StreamFrame)
+ sf.PutBack()
+
+ s.mutex.Lock()
+ if s.resetErr != nil && (*SendStream)(s).reliableOffset() == 0 {
+ s.mutex.Unlock()
+ return
+ }
+ s.numOutstandingFrames--
+ if s.numOutstandingFrames < 0 {
+ panic("numOutStandingFrames negative")
+ }
+ completed := (*SendStream)(s).isNewlyCompleted()
+ s.mutex.Unlock()
+
+ if completed {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+}
+
+func (s *sendStreamAckHandler) OnLost(f wire.Frame) {
+ sf := f.(*wire.StreamFrame)
+ s.mutex.Lock()
+ // If the reliable size was 0 when the stream was cancelled,
+ // the number of outstanding frames was immediately set to 0, and the retransmission queue was dropped.
+ if s.resetErr != nil && (*SendStream)(s).reliableOffset() == 0 {
+ // Return the frame to pool since it won't be retransmitted
+ sf.PutBack()
+ s.mutex.Unlock()
+ return
+ }
+ s.numOutstandingFrames--
+ if s.numOutstandingFrames < 0 {
+ panic("numOutStandingFrames negative")
+ }
+
+ if s.resetErr != nil && (*SendStream)(s).reliableOffset() > 0 {
+ // If the stream was reset, and this frame is beyond the reliable offset,
+ // it doesn't need to be retransmitted.
+ if sf.Offset >= (*SendStream)(s).reliableOffset() {
+ sf.PutBack()
+ // If this frame was the last one tracked, losing it might cause the stream to be completed.
+ completed := (*SendStream)(s).isNewlyCompleted()
+ s.mutex.Unlock()
+ if completed {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+ return
+ }
+ // If the payload of the frame extends beyond the reliable size,
+ // truncate the frame to the reliable size.
+ if sf.Offset+sf.DataLen() > (*SendStream)(s).reliableOffset() {
+ sf.Data = sf.Data[:(*SendStream)(s).reliableOffset()-sf.Offset]
+ }
+ }
+
+ sf.DataLenPresent = true
+ s.retransmissionQueue = append(s.retransmissionQueue, sf)
+ s.mutex.Unlock()
+
+ s.sender.onHasStreamData(s.streamID, (*SendStream)(s))
+}
+
+type sendStreamResetStreamHandler SendStream
+
+var _ ackhandler.FrameHandler = &sendStreamResetStreamHandler{}
+
+func (s *sendStreamResetStreamHandler) OnAcked(f wire.Frame) {
+ rsf := f.(*wire.ResetStreamFrame)
+ s.mutex.Lock()
+ // If the peer sent a STOP_SENDING after we sent a RESET_STREAM_AT frame,
+ // we sent 1. reduced the reliable size to 0 and 2. sent a RESET_STREAM frame.
+ // In this case, we don't care about the acknowledgment of this frame.
+ if rsf.ReliableSize != (*SendStream)(s).reliableOffset() {
+ s.mutex.Unlock()
+ return
+ }
+ s.numOutstandingFrames--
+ if s.numOutstandingFrames < 0 {
+ panic("numOutStandingFrames negative")
+ }
+ completed := (*SendStream)(s).isNewlyCompleted()
+ s.mutex.Unlock()
+
+ if completed {
+ s.sender.onStreamCompleted(s.streamID)
+ }
+}
+
+func (s *sendStreamResetStreamHandler) OnLost(f wire.Frame) {
+ rsf := f.(*wire.ResetStreamFrame)
+ s.mutex.Lock()
+ // If the peer sent a STOP_SENDING after we sent a RESET_STREAM_AT frame,
+ // we sent 1. reduced the reliable size to 0 and 2. sent a RESET_STREAM frame.
+ // In this case, the loss of the RESET_STREAM_AT frame can be ignored.
+ if rsf.ReliableSize != (*SendStream)(s).reliableOffset() {
+ s.mutex.Unlock()
+ return
+ }
+ s.queuedResetStreamFrame = rsf
+ s.numOutstandingFrames--
+ s.mutex.Unlock()
+ s.sender.onHasStreamControlFrame(s.streamID, (*SendStream)(s))
+}
diff --git a/vendor/github.com/quic-go/quic-go/server.go b/vendor/github.com/quic-go/quic-go/server.go
new file mode 100644
index 00000000..3cd28b7c
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/server.go
@@ -0,0 +1,1119 @@
+package quic
+
+import (
+ "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "net"
+ "sync"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/handshake"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+// ErrServerClosed is returned by the [Listener] or [EarlyListener]'s Accept method after a call to Close.
+var ErrServerClosed = errServerClosed{}
+
+type errServerClosed struct{}
+
+func (errServerClosed) Error() string { return "quic: server closed" }
+func (errServerClosed) Unwrap() error { return net.ErrClosed }
+
+// packetHandler handles packets
+type packetHandler interface {
+ handlePacket(receivedPacket)
+ destroy(error)
+ closeWithTransportError(qerr.TransportErrorCode)
+}
+
+type zeroRTTQueue struct {
+ packets []receivedPacket
+ expiration monotime.Time
+}
+
+type rejectedPacket struct {
+ receivedPacket
+ hdr *wire.Header
+}
+
+// A Listener of QUIC
+type baseServer struct {
+ tr *packetHandlerMap
+ disableVersionNegotiation bool
+ acceptEarlyConns bool
+
+ tlsConf *tls.Config
+ config *Config
+
+ conn rawConn
+
+ tokenGenerator *handshake.TokenGenerator
+ maxTokenAge time.Duration
+
+ connIDGenerator ConnectionIDGenerator
+ statelessResetter *statelessResetter
+ onClose func()
+
+ receivedPackets chan receivedPacket
+
+ nextZeroRTTCleanup monotime.Time
+ zeroRTTQueues map[protocol.ConnectionID]*zeroRTTQueue // only initialized if acceptEarlyConns == true
+
+ connContext func(context.Context, *ClientInfo) (context.Context, error)
+
+ // set as a member, so they can be set in the tests
+ newConn func(
+ context.Context,
+ context.CancelCauseFunc,
+ sendConn,
+ connRunner,
+ protocol.ConnectionID, /* original dest connection ID */
+ *protocol.ConnectionID, /* retry src connection ID */
+ protocol.ConnectionID, /* client dest connection ID */
+ protocol.ConnectionID, /* destination connection ID */
+ protocol.ConnectionID, /* source connection ID */
+ ConnectionIDGenerator,
+ *statelessResetter,
+ *Config,
+ *tls.Config,
+ *handshake.TokenGenerator,
+ bool, /* client address validated by an address validation token */
+ time.Duration,
+ qlogwriter.Trace,
+ utils.Logger,
+ protocol.Version,
+ ) *wrappedConn
+
+ closeMx sync.Mutex
+ // errorChan is closed when Close is called. This has two effects:
+ // 1. it cancels handshakes that are still in flight (using CONNECTION_REFUSED) errors
+ // 2. it stops handling of packets passed to this server
+ errorChan chan struct{}
+ // acceptChan is closed when Close returns.
+ // This only happens once all handshake in flight have either completed and canceled.
+ // Calls to Accept will first drain the queue of connections that have completed the handshake,
+ // and then return ErrServerClosed.
+ stopAccepting chan struct{}
+ closeErr error
+ running chan struct{} // closed as soon as run() returns
+
+ versionNegotiationQueue chan receivedPacket
+ invalidTokenQueue chan rejectedPacket
+ connectionRefusedQueue chan rejectedPacket
+ retryQueue chan rejectedPacket
+ handshakingCount sync.WaitGroup
+
+ verifySourceAddress func(net.Addr) bool
+
+ connQueue chan *Conn
+
+ qlogger qlogwriter.Recorder
+
+ logger utils.Logger
+}
+
+// A Listener listens for incoming QUIC connections.
+// It returns connections once the handshake has completed.
+type Listener struct {
+ baseServer *baseServer
+}
+
+// Accept returns new connections. It should be called in a loop.
+func (l *Listener) Accept(ctx context.Context) (*Conn, error) {
+ return l.baseServer.Accept(ctx)
+}
+
+// Close closes the listener.
+// Accept will return [ErrServerClosed] as soon as all connections in the accept queue have been accepted.
+// QUIC handshakes that are still in flight will be rejected with a CONNECTION_REFUSED error.
+// Already established (accepted) connections will be unaffected.
+func (l *Listener) Close() error {
+ return l.baseServer.Close()
+}
+
+// Addr returns the local network address that the server is listening on.
+func (l *Listener) Addr() net.Addr {
+ return l.baseServer.Addr()
+}
+
+// An EarlyListener listens for incoming QUIC connections, and returns them before the handshake completes.
+// For connections that don't use 0-RTT, this allows the server to send 0.5-RTT data.
+// This data is encrypted with forward-secure keys, however, the client's identity has not yet been verified.
+// For connection using 0-RTT, this allows the server to accept and respond to streams that the client opened in the
+// 0-RTT data it sent. Note that at this point during the handshake, the live-ness of the
+// client has not yet been confirmed, and the 0-RTT data could have been replayed by an attacker.
+type EarlyListener struct {
+ baseServer *baseServer
+}
+
+// Accept returns a new connections. It should be called in a loop.
+func (l *EarlyListener) Accept(ctx context.Context) (*Conn, error) {
+ conn, err := l.baseServer.accept(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return conn, nil
+}
+
+// Close closes the listener.
+// Accept will return [ErrServerClosed] as soon as all connections in the accept queue have been accepted.
+// Early connections that are still in flight will be rejected with a CONNECTION_REFUSED error.
+// Already established (accepted) connections will be unaffected.
+func (l *EarlyListener) Close() error {
+ return l.baseServer.Close()
+}
+
+// Addr returns the local network addr that the server is listening on.
+func (l *EarlyListener) Addr() net.Addr {
+ return l.baseServer.Addr()
+}
+
+// ListenAddr creates a QUIC server listening on a given address.
+// See [Listen] for more details.
+func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (*Listener, error) {
+ conn, err := listenUDP(addr)
+ if err != nil {
+ return nil, err
+ }
+ return (&Transport{
+ Conn: conn,
+ createdConn: true,
+ isSingleUse: true,
+ }).Listen(tlsConf, config)
+}
+
+// ListenAddrEarly works like [ListenAddr], but it returns connections before the handshake completes.
+func ListenAddrEarly(addr string, tlsConf *tls.Config, config *Config) (*EarlyListener, error) {
+ conn, err := listenUDP(addr)
+ if err != nil {
+ return nil, err
+ }
+ return (&Transport{
+ Conn: conn,
+ createdConn: true,
+ isSingleUse: true,
+ }).ListenEarly(tlsConf, config)
+}
+
+func listenUDP(addr string) (*net.UDPConn, error) {
+ udpAddr, err := net.ResolveUDPAddr("udp", addr)
+ if err != nil {
+ return nil, err
+ }
+ return net.ListenUDP("udp", udpAddr)
+}
+
+// Listen listens for QUIC connections on a given net.PacketConn.
+// If the PacketConn satisfies the [OOBCapablePacketConn] interface (as a [net.UDPConn] does),
+// ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP
+// will be used instead of ReadFrom and WriteTo to read/write packets.
+// A single net.PacketConn can only be used for a single call to Listen.
+//
+// The tls.Config must not be nil and must contain a certificate configuration.
+// Furthermore, it must define an application control (using [NextProtos]).
+// The quic.Config may be nil, in that case the default values will be used.
+//
+// This is a convenience function. More advanced use cases should instantiate a [Transport],
+// which offers configuration options for a more fine-grained control of the connection establishment,
+// including reusing the underlying UDP socket for outgoing QUIC connections.
+// When closing a listener created with Listen, all established QUIC connections will be closed immediately.
+func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*Listener, error) {
+ tr := &Transport{Conn: conn, isSingleUse: true}
+ return tr.Listen(tlsConf, config)
+}
+
+// ListenEarly works like [Listen], but it returns connections before the handshake completes.
+func ListenEarly(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*EarlyListener, error) {
+ tr := &Transport{Conn: conn, isSingleUse: true}
+ return tr.ListenEarly(tlsConf, config)
+}
+
+func newServer(
+ conn rawConn,
+ tr *packetHandlerMap,
+ connIDGenerator ConnectionIDGenerator,
+ statelessResetter *statelessResetter,
+ connContext func(context.Context, *ClientInfo) (context.Context, error),
+ tlsConf *tls.Config,
+ config *Config,
+ qlogger qlogwriter.Recorder,
+ onClose func(),
+ tokenGeneratorKey TokenGeneratorKey,
+ maxTokenAge time.Duration,
+ verifySourceAddress func(net.Addr) bool,
+ disableVersionNegotiation bool,
+ acceptEarly bool,
+) *baseServer {
+ s := &baseServer{
+ conn: conn,
+ connContext: connContext,
+ tr: tr,
+ tlsConf: tlsConf,
+ config: config,
+ tokenGenerator: handshake.NewTokenGenerator(tokenGeneratorKey),
+ maxTokenAge: maxTokenAge,
+ verifySourceAddress: verifySourceAddress,
+ connIDGenerator: connIDGenerator,
+ statelessResetter: statelessResetter,
+ connQueue: make(chan *Conn, protocol.MaxAcceptQueueSize),
+ errorChan: make(chan struct{}),
+ stopAccepting: make(chan struct{}),
+ running: make(chan struct{}),
+ receivedPackets: make(chan receivedPacket, protocol.MaxServerUnprocessedPackets),
+ versionNegotiationQueue: make(chan receivedPacket, 4),
+ invalidTokenQueue: make(chan rejectedPacket, 4),
+ connectionRefusedQueue: make(chan rejectedPacket, 4),
+ retryQueue: make(chan rejectedPacket, 8),
+ newConn: newConnection,
+ qlogger: qlogger,
+ logger: utils.DefaultLogger.WithPrefix("server"),
+ acceptEarlyConns: acceptEarly,
+ disableVersionNegotiation: disableVersionNegotiation,
+ onClose: onClose,
+ }
+ if acceptEarly {
+ s.zeroRTTQueues = map[protocol.ConnectionID]*zeroRTTQueue{}
+ }
+ go s.run()
+ go s.runSendQueue()
+ s.logger.Debugf("Listening for %s connections on %s", conn.LocalAddr().Network(), conn.LocalAddr().String())
+ return s
+}
+
+func (s *baseServer) run() {
+ defer close(s.running)
+ for {
+ select {
+ case <-s.errorChan:
+ return
+ default:
+ }
+ select {
+ case <-s.errorChan:
+ return
+ case p := <-s.receivedPackets:
+ if bufferStillInUse := s.handlePacketImpl(p); !bufferStillInUse {
+ p.buffer.Release()
+ }
+ }
+ }
+}
+
+func (s *baseServer) runSendQueue() {
+ for {
+ select {
+ case <-s.running:
+ return
+ case p := <-s.versionNegotiationQueue:
+ s.maybeSendVersionNegotiationPacket(p)
+ case p := <-s.invalidTokenQueue:
+ s.maybeSendInvalidToken(p)
+ case p := <-s.connectionRefusedQueue:
+ s.sendConnectionRefused(p)
+ case p := <-s.retryQueue:
+ s.sendRetry(p)
+ }
+ }
+}
+
+// Accept returns connections that already completed the handshake.
+// It is only valid if acceptEarlyConns is false.
+func (s *baseServer) Accept(ctx context.Context) (*Conn, error) {
+ return s.accept(ctx)
+}
+
+func (s *baseServer) accept(ctx context.Context) (*Conn, error) {
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ case conn := <-s.connQueue:
+ return conn, nil
+ case <-s.stopAccepting:
+ // first drain the queue
+ select {
+ case conn := <-s.connQueue:
+ return conn, nil
+ default:
+ }
+ return nil, s.closeErr
+ }
+}
+
+func (s *baseServer) Close() error {
+ s.close(ErrServerClosed, false)
+ return nil
+}
+
+// close closes the server. The Transport mutex must not be held while calling this method.
+// This method closes any handshaking connections which requires the tranpsort mutex.
+func (s *baseServer) close(e error, transportClose bool) {
+ s.closeMx.Lock()
+ if s.closeErr != nil {
+ s.closeMx.Unlock()
+ return
+ }
+ s.closeErr = e
+ close(s.errorChan)
+ <-s.running
+ s.closeMx.Unlock()
+
+ if !transportClose {
+ s.onClose()
+ }
+
+ // wait until all handshakes in flight have terminated
+ s.handshakingCount.Wait()
+ close(s.stopAccepting)
+
+ if transportClose {
+ // if the transport is closing, drain the connQueue. All connections in the queue
+ // will be closed by the transport.
+ for {
+ select {
+ case <-s.connQueue:
+ default:
+ return
+ }
+ }
+ }
+}
+
+// Addr returns the server's network address
+func (s *baseServer) Addr() net.Addr {
+ return s.conn.LocalAddr()
+}
+
+func (s *baseServer) handlePacket(p receivedPacket) {
+ select {
+ case s.receivedPackets <- p:
+ case <-s.errorChan:
+ return
+ default:
+ s.logger.Debugf("Dropping packet from %s (%d bytes). Server receive queue full.", p.remoteAddr, p.Size())
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
+ }
+ }
+}
+
+func (s *baseServer) handlePacketImpl(p receivedPacket) bool /* is the buffer still in use? */ {
+ if !s.nextZeroRTTCleanup.IsZero() && p.rcvTime.After(s.nextZeroRTTCleanup) {
+ defer s.cleanupZeroRTTQueues(p.rcvTime)
+ }
+
+ if wire.IsVersionNegotiationPacket(p.data) {
+ s.logger.Debugf("Dropping Version Negotiation packet.")
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return false
+ }
+ // Short header packets should never end up here in the first place
+ if !wire.IsLongHeaderPacket(p.data[0]) {
+ panic(fmt.Sprintf("misrouted packet: %#v", p.data))
+ }
+ v, err := wire.ParseVersion(p.data)
+ // drop the packet if we failed to parse the protocol version
+ if err != nil {
+ s.logger.Debugf("Dropping a packet with an unknown version")
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return false
+ }
+ // send a Version Negotiation Packet if the client is speaking a different protocol version
+ if !protocol.IsSupportedVersion(s.config.Versions, v) {
+ if s.disableVersionNegotiation {
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{Version: v},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedVersion,
+ })
+ }
+ return false
+ }
+
+ if p.Size() < protocol.MinUnknownVersionPacketSize {
+ s.logger.Debugf("Dropping a packet with an unsupported version number %d that is too small (%d bytes)", v, p.Size())
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{Version: v},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return false
+ }
+ return s.enqueueVersionNegotiationPacket(p)
+ }
+
+ if wire.Is0RTTPacket(p.data) {
+ if !s.acceptEarlyConns {
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType0RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return false
+ }
+ return s.handle0RTTPacket(p)
+ }
+
+ // If we're creating a new connection, the packet will be passed to the connection.
+ // The header will then be parsed again.
+ hdr, _, _, err := wire.ParsePacket(p.data)
+ if err != nil {
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ s.logger.Debugf("Error parsing packet: %s", err)
+ return false
+ }
+ if hdr.Type == protocol.PacketTypeInitial && p.Size() < protocol.MinInitialPacketSize {
+ s.logger.Debugf("Dropping a packet that is too small to be a valid Initial (%d bytes)", p.Size())
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeInitial,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: v,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return false
+ }
+
+ if hdr.Type != protocol.PacketTypeInitial {
+ // Drop long header packets.
+ // There's little point in sending a Stateless Reset, since the client
+ // might not have received the token yet.
+ s.logger.Debugf("Dropping long header packet of type %s (%d bytes)", hdr.Type, len(p.data))
+ if s.qlogger != nil {
+ var pt qlog.PacketType
+ switch hdr.Type {
+ case protocol.PacketTypeInitial:
+ pt = qlog.PacketTypeInitial
+ case protocol.PacketTypeHandshake:
+ pt = qlog.PacketTypeHandshake
+ case protocol.PacketType0RTT:
+ pt = qlog.PacketType0RTT
+ case protocol.PacketTypeRetry:
+ pt = qlog.PacketTypeRetry
+ }
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: v,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return false
+ }
+
+ s.logger.Debugf("<- Received Initial packet.")
+
+ if err := s.handleInitialImpl(p, hdr); err != nil {
+ s.logger.Errorf("Error occurred handling initial packet: %s", err)
+ }
+ // Don't put the packet buffer back.
+ // handleInitialImpl deals with the buffer.
+ return true
+}
+
+func (s *baseServer) handle0RTTPacket(p receivedPacket) bool {
+ connID, err := wire.ParseConnectionID(p.data, 0)
+ if err != nil {
+ if s.qlogger != nil {
+ v, _ := wire.ParseVersion(p.data)
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType0RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: v,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ return false
+ }
+
+ // check again if we might have a connection now
+ if handler, ok := s.tr.Get(connID); ok {
+ handler.handlePacket(p)
+ return true
+ }
+
+ if q, ok := s.zeroRTTQueues[connID]; ok {
+ if len(q.packets) >= protocol.Max0RTTQueueLen {
+ if s.qlogger != nil {
+ v, _ := wire.ParseVersion(p.data)
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType0RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: v,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
+ }
+ return false
+ }
+ q.packets = append(q.packets, p)
+ return true
+ }
+
+ if len(s.zeroRTTQueues) >= protocol.Max0RTTQueues {
+ if s.qlogger != nil {
+ v, _ := wire.ParseVersion(p.data)
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType0RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: v,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
+ }
+ return false
+ }
+ queue := &zeroRTTQueue{packets: make([]receivedPacket, 1, 8)}
+ queue.packets[0] = p
+ expiration := p.rcvTime.Add(protocol.Max0RTTQueueingDuration)
+ queue.expiration = expiration
+ if s.nextZeroRTTCleanup.IsZero() || s.nextZeroRTTCleanup.After(expiration) {
+ s.nextZeroRTTCleanup = expiration
+ }
+ s.zeroRTTQueues[connID] = queue
+ return true
+}
+
+func (s *baseServer) cleanupZeroRTTQueues(now monotime.Time) {
+ // Iterate over all queues to find those that are expired.
+ // This is ok since we're placing a pretty low limit on the number of queues.
+ var nextCleanup monotime.Time
+ for connID, q := range s.zeroRTTQueues {
+ if q.expiration.After(now) {
+ if nextCleanup.IsZero() || nextCleanup.After(q.expiration) {
+ nextCleanup = q.expiration
+ }
+ continue
+ }
+ for _, p := range q.packets {
+ if s.qlogger != nil {
+ v, _ := wire.ParseVersion(p.data)
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType0RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: v,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
+ }
+ p.buffer.Release()
+ }
+ delete(s.zeroRTTQueues, connID)
+ if s.logger.Debug() {
+ s.logger.Debugf("Removing 0-RTT queue for %s.", connID)
+ }
+ }
+ s.nextZeroRTTCleanup = nextCleanup
+}
+
+// validateToken returns false if:
+// - address is invalid
+// - token is expired
+// - token is null
+func (s *baseServer) validateToken(token *handshake.Token, addr net.Addr) bool {
+ if token == nil {
+ return false
+ }
+ if !token.ValidateRemoteAddr(addr) {
+ return false
+ }
+ if !token.IsRetryToken && time.Since(token.SentTime) > s.maxTokenAge {
+ return false
+ }
+ if token.IsRetryToken && time.Since(token.SentTime) > s.config.maxRetryTokenAge() {
+ return false
+ }
+ return true
+}
+
+func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error {
+ if len(hdr.Token) == 0 && hdr.DestConnectionID.Len() < protocol.MinConnectionIDLenInitial {
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeInitial,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ p.buffer.Release()
+ return errors.New("too short connection ID")
+ }
+
+ // The server queues packets for a while, and we might already have established a connection by now.
+ // This results in a second check in the connection map.
+ // That's ok since it's not the hot path (it's only taken by some Initial and 0-RTT packets).
+ if handler, ok := s.tr.Get(hdr.DestConnectionID); ok {
+ handler.handlePacket(p)
+ return nil
+ }
+
+ var (
+ token *handshake.Token
+ retrySrcConnID *protocol.ConnectionID
+ clientAddrVerified bool
+ )
+ origDestConnID := hdr.DestConnectionID
+ if len(hdr.Token) > 0 {
+ tok, err := s.tokenGenerator.DecodeToken(hdr.Token)
+ if err == nil {
+ if tok.IsRetryToken {
+ origDestConnID = tok.OriginalDestConnectionID
+ retrySrcConnID = &tok.RetrySrcConnectionID
+ }
+ token = tok
+ }
+ }
+ if token != nil {
+ clientAddrVerified = s.validateToken(token, p.remoteAddr)
+ if !clientAddrVerified {
+ // For invalid and expired non-retry tokens, we don't send an INVALID_TOKEN error.
+ // We just ignore them, and act as if there was no token on this packet at all.
+ // This also means we might send a Retry later.
+ if !token.IsRetryToken {
+ token = nil
+ } else {
+ // For Retry tokens, we send an INVALID_ERROR if
+ // * the token is too old, or
+ // * the token is invalid, in case of a retry token.
+ select {
+ case s.invalidTokenQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
+ default:
+ // drop packet if we can't send out the INVALID_TOKEN packets fast enough
+ p.buffer.Release()
+ }
+ return nil
+ }
+ }
+ }
+
+ if token == nil && s.verifySourceAddress != nil && s.verifySourceAddress(p.remoteAddr) {
+ // Retry invalidates all 0-RTT packets sent.
+ delete(s.zeroRTTQueues, hdr.DestConnectionID)
+ select {
+ case s.retryQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
+ default:
+ // drop packet if we can't send out Retry packets fast enough
+ p.buffer.Release()
+ }
+ return nil
+ }
+
+ // restore RTT from token
+ var rtt time.Duration
+ if token != nil && !token.IsRetryToken {
+ rtt = token.RTT
+ }
+
+ config := s.config
+ clientInfo := &ClientInfo{
+ RemoteAddr: p.remoteAddr,
+ AddrVerified: clientAddrVerified,
+ }
+ if s.config.GetConfigForClient != nil {
+ conf, err := s.config.GetConfigForClient(clientInfo)
+ if err != nil {
+ s.logger.Debugf("Rejecting new connection due to GetConfigForClient callback")
+ s.refuseNewConn(p, hdr)
+ return nil
+ }
+ config = populateConfig(conf)
+ }
+
+ var conn *wrappedConn
+ var cancel context.CancelCauseFunc
+ ctx, cancel1 := context.WithCancelCause(context.Background())
+ if s.connContext != nil {
+ var err error
+ ctx, err = s.connContext(ctx, clientInfo)
+ if err != nil {
+ cancel1(err)
+ s.logger.Debugf("Rejecting new connection due to ConnContext callback: %s", err)
+ s.refuseNewConn(p, hdr)
+ return nil
+ }
+ if ctx == nil {
+ panic("quic: ConnContext returned nil")
+ }
+ // There's no guarantee that the application returns a context
+ // that's derived from the context we passed into ConnContext.
+ // We need to make sure that both contexts are cancelled.
+ var cancel2 context.CancelCauseFunc
+ ctx, cancel2 = context.WithCancelCause(ctx)
+ cancel = func(cause error) {
+ cancel1(cause)
+ cancel2(cause)
+ }
+ } else {
+ cancel = cancel1
+ }
+ var qlogTrace qlogwriter.Trace
+ if config.Tracer != nil {
+ // Use the same connection ID that is passed to the client's GetLogWriter callback.
+ connID := hdr.DestConnectionID
+ if origDestConnID.Len() > 0 {
+ connID = origDestConnID
+ }
+ qlogTrace = config.Tracer(ctx, false, connID)
+ }
+ connID, err := s.connIDGenerator.GenerateConnectionID()
+ if err != nil {
+ return err
+ }
+ s.logger.Debugf("Changing connection ID to %s.", connID)
+ conn = s.newConn(
+ ctx,
+ cancel,
+ newSendConn(s.conn, p.remoteAddr, p.info, s.logger),
+ s.tr,
+ origDestConnID,
+ retrySrcConnID,
+ hdr.DestConnectionID,
+ hdr.SrcConnectionID,
+ connID,
+ s.connIDGenerator,
+ s.statelessResetter,
+ config,
+ s.tlsConf,
+ s.tokenGenerator,
+ clientAddrVerified,
+ rtt,
+ qlogTrace,
+ s.logger,
+ hdr.Version,
+ )
+ conn.handlePacket(p)
+ // Adding the connection will fail if the client's chosen Destination Connection ID is already in use.
+ // This is very unlikely: Even if an attacker chooses a connection ID that's already in use,
+ // under normal circumstances the packet would just be routed to that connection.
+ // The only time this collision will occur if we receive the two Initial packets at the same time.
+ if added := s.tr.AddWithConnID(hdr.DestConnectionID, connID, conn); !added {
+ delete(s.zeroRTTQueues, hdr.DestConnectionID)
+ conn.closeWithTransportError(ConnectionRefused)
+ return nil
+ }
+ // Pass queued 0-RTT to the newly established connection.
+ if q, ok := s.zeroRTTQueues[hdr.DestConnectionID]; ok {
+ for _, p := range q.packets {
+ conn.handlePacket(p)
+ }
+ delete(s.zeroRTTQueues, hdr.DestConnectionID)
+ }
+
+ s.handshakingCount.Go(func() { s.handleNewConn(conn) })
+ go conn.run()
+ return nil
+}
+
+func (s *baseServer) refuseNewConn(p receivedPacket, hdr *wire.Header) {
+ delete(s.zeroRTTQueues, hdr.DestConnectionID)
+ select {
+ case s.connectionRefusedQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
+ default:
+ // drop packet if we can't send out the CONNECTION_REFUSED fast enough
+ p.buffer.Release()
+ }
+}
+
+func (s *baseServer) handleNewConn(conn *wrappedConn) {
+ if s.acceptEarlyConns {
+ // wait until the early connection is ready, the handshake fails, or the server is closed
+ select {
+ case <-s.errorChan:
+ conn.closeWithTransportError(ConnectionRefused)
+ return
+ case <-conn.Context().Done():
+ return
+ case <-conn.earlyConnReady():
+ }
+ } else {
+ // wait until the handshake completes, fails, or the server is closed
+ select {
+ case <-s.errorChan:
+ conn.closeWithTransportError(ConnectionRefused)
+ return
+ case <-conn.Context().Done():
+ return
+ case <-conn.HandshakeComplete():
+ }
+ }
+
+ select {
+ case s.connQueue <- conn.Conn:
+ default:
+ conn.closeWithTransportError(ConnectionRefused)
+ }
+}
+
+func (s *baseServer) sendRetry(p rejectedPacket) {
+ if err := s.sendRetryPacket(p); err != nil {
+ s.logger.Debugf("Error sending Retry packet: %s", err)
+ }
+}
+
+func (s *baseServer) sendRetryPacket(p rejectedPacket) error {
+ hdr := p.hdr
+ // Log the Initial packet now.
+ // If no Retry is sent, the packet will be logged by the connection.
+ (&wire.ExtendedHeader{Header: *hdr}).Log(s.logger)
+ srcConnID, err := s.connIDGenerator.GenerateConnectionID()
+ if err != nil {
+ return err
+ }
+ token, err := s.tokenGenerator.NewRetryToken(p.remoteAddr, hdr.DestConnectionID, srcConnID)
+ if err != nil {
+ return err
+ }
+ replyHdr := &wire.ExtendedHeader{}
+ replyHdr.Type = protocol.PacketTypeRetry
+ replyHdr.Version = hdr.Version
+ replyHdr.SrcConnectionID = srcConnID
+ replyHdr.DestConnectionID = hdr.SrcConnectionID
+ replyHdr.Token = token
+ if s.logger.Debug() {
+ s.logger.Debugf("Changing connection ID to %s.", srcConnID)
+ s.logger.Debugf("-> Sending Retry")
+ replyHdr.Log(s.logger)
+ }
+
+ buf := getPacketBuffer()
+ defer buf.Release()
+ buf.Data, err = replyHdr.Append(buf.Data, hdr.Version)
+ if err != nil {
+ return err
+ }
+ // append the Retry integrity tag
+ tag := handshake.GetRetryIntegrityTag(buf.Data, hdr.DestConnectionID, hdr.Version)
+ buf.Data = append(buf.Data, tag[:]...)
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketSent{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: replyHdr.SrcConnectionID,
+ DestConnectionID: replyHdr.DestConnectionID,
+ Version: replyHdr.Version,
+ Token: &qlog.Token{Raw: token},
+ },
+ Raw: qlog.RawInfo{
+ Length: len(buf.Data),
+ PayloadLength: int(replyHdr.Length),
+ },
+ })
+ }
+ _, err = s.conn.WritePacket(buf.Data, p.remoteAddr, p.info.OOB(), 0, protocol.ECNUnsupported)
+ return err
+}
+
+func (s *baseServer) maybeSendInvalidToken(p rejectedPacket) {
+ defer p.buffer.Release()
+
+ // Only send INVALID_TOKEN if we can unprotect the packet.
+ // This makes sure that we won't send it for packets that were corrupted.
+ hdr := p.hdr
+ sealer, opener := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version)
+ data := p.data[:hdr.ParsedLen()+hdr.Length]
+ extHdr, err := unpackLongHeader(opener, hdr, data)
+ // Only send INVALID_TOKEN if we can unprotect the packet.
+ // This makes sure that we won't send it for packets that were corrupted.
+ if err != nil {
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeInitial,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ return
+ }
+ hdrLen := extHdr.ParsedLen()
+ if _, err := opener.Open(data[hdrLen:hdrLen], data[hdrLen:], extHdr.PacketNumber, data[:hdrLen]); err != nil {
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeInitial,
+ PacketNumber: protocol.InvalidPacketNumber,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropPayloadDecryptError,
+ })
+ }
+ return
+ }
+ if s.logger.Debug() {
+ s.logger.Debugf("Client sent an invalid retry token. Sending INVALID_TOKEN to %s.", p.remoteAddr)
+ }
+ if err := s.sendError(p.remoteAddr, hdr, sealer, InvalidToken, p.info); err != nil {
+ s.logger.Debugf("Error sending INVALID_TOKEN error: %s", err)
+ }
+}
+
+func (s *baseServer) sendConnectionRefused(p rejectedPacket) {
+ defer p.buffer.Release()
+ sealer, _ := handshake.NewInitialAEAD(p.hdr.DestConnectionID, protocol.PerspectiveServer, p.hdr.Version)
+ if err := s.sendError(p.remoteAddr, p.hdr, sealer, ConnectionRefused, p.info); err != nil {
+ s.logger.Debugf("Error sending CONNECTION_REFUSED error: %s", err)
+ }
+}
+
+// sendError sends the error as a response to the packet received with header hdr
+func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer handshake.LongHeaderSealer, errorCode qerr.TransportErrorCode, info packetInfo) error {
+ b := getPacketBuffer()
+ defer b.Release()
+
+ ccf := &wire.ConnectionCloseFrame{ErrorCode: uint64(errorCode)}
+
+ replyHdr := &wire.ExtendedHeader{}
+ replyHdr.Type = protocol.PacketTypeInitial
+ replyHdr.Version = hdr.Version
+ replyHdr.SrcConnectionID = hdr.DestConnectionID
+ replyHdr.DestConnectionID = hdr.SrcConnectionID
+ replyHdr.PacketNumberLen = protocol.PacketNumberLen4
+ replyHdr.Length = 4 /* packet number len */ + ccf.Length(hdr.Version) + protocol.ByteCount(sealer.Overhead())
+ var err error
+ b.Data, err = replyHdr.Append(b.Data, hdr.Version)
+ if err != nil {
+ return err
+ }
+ payloadOffset := len(b.Data)
+
+ b.Data, err = ccf.Append(b.Data, hdr.Version)
+ if err != nil {
+ return err
+ }
+
+ _ = sealer.Seal(b.Data[payloadOffset:payloadOffset], b.Data[payloadOffset:], replyHdr.PacketNumber, b.Data[:payloadOffset])
+ b.Data = b.Data[0 : len(b.Data)+sealer.Overhead()]
+
+ pnOffset := payloadOffset - int(replyHdr.PacketNumberLen)
+ sealer.EncryptHeader(
+ b.Data[pnOffset+4:pnOffset+4+16],
+ &b.Data[0],
+ b.Data[pnOffset:payloadOffset],
+ )
+
+ replyHdr.Log(s.logger)
+ wire.LogFrame(s.logger, ccf, true)
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketSent{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeInitial,
+ SrcConnectionID: replyHdr.SrcConnectionID,
+ DestConnectionID: replyHdr.DestConnectionID,
+ PacketNumber: replyHdr.PacketNumber,
+ Version: replyHdr.Version,
+ },
+ Raw: qlog.RawInfo{
+ Length: len(b.Data),
+ PayloadLength: int(replyHdr.Length),
+ },
+ Frames: []qlog.Frame{{Frame: ccf}},
+ })
+ }
+ _, err = s.conn.WritePacket(b.Data, remoteAddr, info.OOB(), 0, protocol.ECNUnsupported)
+ return err
+}
+
+func (s *baseServer) enqueueVersionNegotiationPacket(p receivedPacket) (bufferInUse bool) {
+ select {
+ case s.versionNegotiationQueue <- p:
+ return true
+ default:
+ // it's fine to not send version negotiation packets when we are busy
+ }
+ return false
+}
+
+func (s *baseServer) maybeSendVersionNegotiationPacket(p receivedPacket) {
+ defer p.buffer.Release()
+
+ v, err := wire.ParseVersion(p.data)
+ if err != nil {
+ s.logger.Debugf("failed to parse version for sending version negotiation packet: %s", err)
+ return
+ }
+
+ _, src, dest, err := wire.ParseArbitraryLenConnectionIDs(p.data)
+ if err != nil { // should never happen
+ s.logger.Debugf("Dropping a packet with an unknown version for which we failed to parse connection IDs")
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
+ }
+ return
+ }
+
+ s.logger.Debugf("Client offered version %s, sending Version Negotiation", v)
+
+ data := wire.ComposeVersionNegotiation(dest, src, s.config.Versions)
+ if s.qlogger != nil {
+ s.qlogger.RecordEvent(qlog.VersionNegotiationSent{
+ Header: qlog.PacketHeaderVersionNegotiation{
+ SrcConnectionID: src,
+ DestConnectionID: dest,
+ },
+ SupportedVersions: s.config.Versions,
+ })
+ }
+ if _, err := s.conn.WritePacket(data, p.remoteAddr, p.info.OOB(), 0, protocol.ECNUnsupported); err != nil {
+ s.logger.Debugf("Error sending Version Negotiation: %s", err)
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/sni.go b/vendor/github.com/quic-go/quic-go/sni.go
new file mode 100644
index 00000000..f63023f9
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sni.go
@@ -0,0 +1,136 @@
+package quic
+
+import (
+ "encoding/binary"
+ "errors"
+ "io"
+)
+
+const (
+ extTypeSNI = 0
+ extTypeECH = 0xfe0d
+)
+
+// findSNIAndECH parses the given byte slice as a ClientHello, and locates:
+// - the position and length of the Server Name Indication (SNI) extension,
+// - the position of the Encrypted Client Hello (ECH) extension.
+// If no SNI extension is found, it returns -1 for the SNI position.
+// If no ECH extension is found, it returns -1 for the ECH position.
+func findSNIAndECH(data []byte) (sniPos, sniLen, echPos int, err error) {
+ if len(data) < 4 {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ if data[0] != 1 {
+ return 0, 0, 0, errors.New("not a ClientHello")
+ }
+ handshakeLen := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if len(data) != 4+handshakeLen {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+
+ parsePos := 4
+ // Skip protocol version (2 bytes)
+ if parsePos+2 > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ parsePos += 2
+ // skip random (32 bytes)
+ if parsePos+32 > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ parsePos += 32
+ // session ID
+ if parsePos+1 > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ sessionIDLen := int(data[parsePos])
+ parsePos++
+ if parsePos+sessionIDLen > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ parsePos += sessionIDLen
+ // cipher suites
+ if parsePos+2 > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ cipherSuitesLen := int(binary.BigEndian.Uint16(data[parsePos:]))
+ parsePos += 2
+ if parsePos+cipherSuitesLen > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ parsePos += cipherSuitesLen
+ // compression methods
+ if parsePos+1 > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ compressionMethodsLen := int(data[parsePos])
+ parsePos++
+ if parsePos+compressionMethodsLen > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ parsePos += compressionMethodsLen
+
+ // extensions
+ if parsePos+2 > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ extensionsLen := int(binary.BigEndian.Uint16(data[parsePos:]))
+ parsePos += 2
+ if parsePos+extensionsLen > len(data) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ extensionsStart := parsePos
+ extensions := data[extensionsStart : extensionsStart+extensionsLen]
+
+ // parse extensions
+ var extPos int
+ sniPos = -1
+ echPos = -1
+ for extPos+4 <= extensionsLen {
+ extType := binary.BigEndian.Uint16(extensions[extPos:])
+ extLen := int(binary.BigEndian.Uint16(extensions[extPos+2:]))
+ if extPos+4+extLen > extensionsLen {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ switch extType {
+ case extTypeSNI:
+ if sniPos != -1 {
+ return 0, 0, 0, errors.New("multiple SNI extensions")
+ }
+ sniData := extensions[extPos+4 : extPos+4+extLen]
+ if len(sniData) < 2 {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ nameListLen := int(binary.BigEndian.Uint16(sniData))
+ if len(sniData) != 2+nameListLen {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ listPos := 2
+ for listPos+3 <= nameListLen+2 {
+ nameType := sniData[listPos]
+ sniLen = int(binary.BigEndian.Uint16(sniData[listPos+1:]))
+ if listPos+3+sniLen > len(sniData) {
+ return 0, 0, 0, io.ErrUnexpectedEOF
+ }
+ if nameType == 0 { // host_name
+ sniPos = extensionsStart + extPos + 4 + listPos + 3
+ break // stop after first host_name
+ }
+ listPos += 3 + sniLen
+ }
+ if sniPos == 0 {
+ return 0, 0, 0, errors.New("SNI host_name not found")
+ }
+ case extTypeECH:
+ if echPos != -1 {
+ return 0, 0, 0, errors.New("multiple ECH extensions")
+ }
+ echPos = extensionsStart + extPos
+ }
+ extPos += 4 + extLen
+ if sniPos != -1 && echPos != -1 {
+ break
+ }
+ }
+ return sniPos, sniLen, echPos, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/stateless_reset.go b/vendor/github.com/quic-go/quic-go/stateless_reset.go
new file mode 100644
index 00000000..cd0059a5
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/stateless_reset.go
@@ -0,0 +1,42 @@
+package quic
+
+import (
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha256"
+ "hash"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+)
+
+type statelessResetter struct {
+ mx sync.Mutex
+ h hash.Hash
+}
+
+// newStatelessRetter creates a new stateless reset generator.
+// It is valid to use a nil key. In that case, a random key will be used.
+// This makes is impossible for on-path attackers to shut down established connections.
+func newStatelessResetter(key *StatelessResetKey) *statelessResetter {
+ var h hash.Hash
+ if key != nil {
+ h = hmac.New(sha256.New, key[:])
+ } else {
+ b := make([]byte, 32)
+ _, _ = rand.Read(b)
+ h = hmac.New(sha256.New, b)
+ }
+ return &statelessResetter{h: h}
+}
+
+func (r *statelessResetter) GetStatelessResetToken(connID protocol.ConnectionID) protocol.StatelessResetToken {
+ r.mx.Lock()
+ defer r.mx.Unlock()
+
+ var token protocol.StatelessResetToken
+ r.h.Write(connID.Bytes())
+ copy(token[:], r.h.Sum(nil))
+ r.h.Reset()
+ return token
+}
diff --git a/vendor/github.com/quic-go/quic-go/stream.go b/vendor/github.com/quic-go/quic-go/stream.go
new file mode 100644
index 00000000..7248f76e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/stream.go
@@ -0,0 +1,234 @@
+package quic
+
+import (
+ "context"
+ "net"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/ackhandler"
+ "github.com/quic-go/quic-go/internal/flowcontrol"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type deadlineError struct{}
+
+func (deadlineError) Error() string { return "deadline exceeded" }
+func (deadlineError) Temporary() bool { return true }
+func (deadlineError) Timeout() bool { return true }
+func (deadlineError) Unwrap() error { return os.ErrDeadlineExceeded }
+
+var errDeadline net.Error = &deadlineError{}
+
+// The streamSender is notified by the stream about various events.
+type streamSender interface {
+ onHasConnectionData()
+ onHasStreamData(protocol.StreamID, *SendStream)
+ onHasStreamControlFrame(protocol.StreamID, streamControlFrameGetter)
+ // must be called without holding the mutex that is acquired by closeForShutdown
+ onStreamCompleted(protocol.StreamID)
+}
+
+// Each of the both stream halves gets its own uniStreamSender.
+// This is necessary in order to keep track when both halves have been completed.
+type uniStreamSender struct {
+ streamSender
+ onStreamCompletedImpl func()
+ onHasStreamControlFrameImpl func(protocol.StreamID, streamControlFrameGetter)
+}
+
+func (s *uniStreamSender) onHasStreamData(id protocol.StreamID, str *SendStream) {
+ s.streamSender.onHasStreamData(id, str)
+}
+func (s *uniStreamSender) onStreamCompleted(protocol.StreamID) { s.onStreamCompletedImpl() }
+func (s *uniStreamSender) onHasStreamControlFrame(id protocol.StreamID, str streamControlFrameGetter) {
+ s.onHasStreamControlFrameImpl(id, str)
+}
+
+var _ streamSender = &uniStreamSender{}
+
+type Stream struct {
+ receiveStr *ReceiveStream
+ sendStr *SendStream
+
+ completedMutex sync.Mutex
+ sender streamSender
+ receiveStreamCompleted bool
+ sendStreamCompleted bool
+}
+
+var (
+ _ outgoingStream = &Stream{}
+ _ sendStreamFrameHandler = &Stream{}
+ _ receiveStreamFrameHandler = &Stream{}
+)
+
+// newStream creates a new Stream
+func newStream(
+ ctx context.Context,
+ streamID protocol.StreamID,
+ sender streamSender,
+ flowController flowcontrol.StreamFlowController,
+ supportsResetStreamAt bool,
+) *Stream {
+ s := &Stream{sender: sender}
+ senderForSendStream := &uniStreamSender{
+ streamSender: sender,
+ onStreamCompletedImpl: func() {
+ s.completedMutex.Lock()
+ s.sendStreamCompleted = true
+ s.checkIfCompleted()
+ s.completedMutex.Unlock()
+ },
+ onHasStreamControlFrameImpl: func(id protocol.StreamID, str streamControlFrameGetter) {
+ sender.onHasStreamControlFrame(streamID, s)
+ },
+ }
+ s.sendStr = newSendStream(ctx, streamID, senderForSendStream, flowController, supportsResetStreamAt)
+ senderForReceiveStream := &uniStreamSender{
+ streamSender: sender,
+ onStreamCompletedImpl: func() {
+ s.completedMutex.Lock()
+ s.receiveStreamCompleted = true
+ s.checkIfCompleted()
+ s.completedMutex.Unlock()
+ },
+ onHasStreamControlFrameImpl: func(id protocol.StreamID, str streamControlFrameGetter) {
+ sender.onHasStreamControlFrame(streamID, s)
+ },
+ }
+ s.receiveStr = newReceiveStream(streamID, senderForReceiveStream, flowController)
+ return s
+}
+
+// StreamID returns the stream ID.
+func (s *Stream) StreamID() protocol.StreamID {
+ // the result is same for receiveStream and sendStream
+ return s.sendStr.StreamID()
+}
+
+// Read reads data from the stream.
+// Read can be made to time out using [Stream.SetReadDeadline] and [Stream.SetDeadline].
+// If the stream was canceled, the error is a [StreamError].
+func (s *Stream) Read(p []byte) (int, error) {
+ return s.receiveStr.Read(p)
+}
+
+// Peek fills b with stream data, without consuming the stream data.
+// It blocks until len(b) bytes are available, or an error occurs.
+// It respects the stream deadline set by SetReadDeadline.
+// If the stream ends before len(b) bytes are available,
+// it returns the number of bytes peeked along with io.EOF.
+func (s *Stream) Peek(b []byte) (int, error) {
+ return s.receiveStr.Peek(b)
+}
+
+// Write writes data to the stream.
+// Write can be made to time out using [Stream.SetWriteDeadline] or [Stream.SetDeadline].
+// If the stream was canceled, the error is a [StreamError].
+func (s *Stream) Write(p []byte) (int, error) {
+ return s.sendStr.Write(p)
+}
+
+// SetReliableBoundary marks the data written to this stream so far as reliable.
+// It is valid to call this function multiple times, thereby increasing the reliable size.
+// It only has an effect if the peer enabled support for the RESET_STREAM_AT extension,
+// otherwise, it is a no-op.
+func (s *Stream) SetReliableBoundary() {
+ s.sendStr.SetReliableBoundary()
+}
+
+// CancelWrite aborts sending on this stream.
+// See [SendStream.CancelWrite] for more details.
+func (s *Stream) CancelWrite(errorCode StreamErrorCode) {
+ s.sendStr.CancelWrite(errorCode)
+}
+
+// CancelRead aborts receiving on this stream.
+// See [ReceiveStream.CancelRead] for more details.
+func (s *Stream) CancelRead(errorCode StreamErrorCode) {
+ s.receiveStr.CancelRead(errorCode)
+}
+
+// The Context is canceled as soon as the write-side of the stream is closed.
+// See [SendStream.Context] for more details.
+func (s *Stream) Context() context.Context {
+ return s.sendStr.Context()
+}
+
+// Close closes the send-direction of the stream.
+// It does not close the receive-direction of the stream.
+func (s *Stream) Close() error {
+ return s.sendStr.Close()
+}
+
+func (s *Stream) handleResetStreamFrame(frame *wire.ResetStreamFrame, rcvTime monotime.Time) error {
+ return s.receiveStr.handleResetStreamFrame(frame, rcvTime)
+}
+
+func (s *Stream) handleStreamFrame(frame *wire.StreamFrame, rcvTime monotime.Time) error {
+ return s.receiveStr.handleStreamFrame(frame, rcvTime)
+}
+
+func (s *Stream) handleStopSendingFrame(frame *wire.StopSendingFrame) {
+ s.sendStr.handleStopSendingFrame(frame)
+}
+
+func (s *Stream) updateSendWindow(limit protocol.ByteCount) {
+ s.sendStr.updateSendWindow(limit)
+}
+
+func (s *Stream) enableResetStreamAt() {
+ s.sendStr.enableResetStreamAt()
+}
+
+func (s *Stream) popStreamFrame(maxBytes protocol.ByteCount, v protocol.Version) (_ ackhandler.StreamFrame, _ *wire.StreamDataBlockedFrame, hasMore bool) {
+ return s.sendStr.popStreamFrame(maxBytes, v)
+}
+
+func (s *Stream) getControlFrame(now monotime.Time) (_ ackhandler.Frame, ok, hasMore bool) {
+ f, ok, _ := s.sendStr.getControlFrame(now)
+ if ok {
+ return f, true, true
+ }
+ return s.receiveStr.getControlFrame(now)
+}
+
+// SetReadDeadline sets the deadline for future Read calls.
+// See [ReceiveStream.SetReadDeadline] for more details.
+func (s *Stream) SetReadDeadline(t time.Time) error {
+ return s.receiveStr.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the deadline for future Write calls.
+// See [SendStream.SetWriteDeadline] for more details.
+func (s *Stream) SetWriteDeadline(t time.Time) error {
+ return s.sendStr.SetWriteDeadline(t)
+}
+
+// SetDeadline sets the read and write deadlines associated with the stream.
+// It is equivalent to calling both SetReadDeadline and SetWriteDeadline.
+func (s *Stream) SetDeadline(t time.Time) error {
+ _ = s.receiveStr.SetReadDeadline(t) // SetReadDeadline never errors
+ _ = s.sendStr.SetWriteDeadline(t) // SetWriteDeadline never errors
+ return nil
+}
+
+// CloseForShutdown closes a stream abruptly.
+// It makes Read and Write unblock (and return the error) immediately.
+// The peer will NOT be informed about this: the stream is closed without sending a FIN or RST.
+func (s *Stream) closeForShutdown(err error) {
+ s.sendStr.closeForShutdown(err)
+ s.receiveStr.closeForShutdown(err)
+}
+
+// checkIfCompleted is called from the uniStreamSender, when one of the stream halves is completed.
+// It makes sure that the onStreamCompleted callback is only called if both receive and send side have completed.
+func (s *Stream) checkIfCompleted() {
+ if s.sendStreamCompleted && s.receiveStreamCompleted {
+ s.sender.onStreamCompleted(s.StreamID())
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/streams_map.go b/vendor/github.com/quic-go/quic-go/streams_map.go
new file mode 100644
index 00000000..92023ac2
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/streams_map.go
@@ -0,0 +1,354 @@
+package quic
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/flowcontrol"
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+// StreamLimitReachedError is returned from Conn.OpenStream and Conn.OpenUniStream
+// when it is not possible to open a new stream because the number of opens streams reached
+// the peer's stream limit.
+type StreamLimitReachedError struct{}
+
+func (e StreamLimitReachedError) Error() string { return "too many open streams" }
+
+type streamsMap struct {
+ ctx context.Context // not used for cancellations, but carries the values associated with the connection
+ perspective protocol.Perspective
+
+ maxIncomingBidiStreams uint64
+ maxIncomingUniStreams uint64
+
+ sender streamSender
+ queueControlFrame func(wire.Frame)
+ newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController
+
+ mutex sync.Mutex
+ outgoingBidiStreams *outgoingStreamsMap[*Stream]
+ outgoingUniStreams *outgoingStreamsMap[*SendStream]
+ incomingBidiStreams *incomingStreamsMap[*Stream]
+ incomingUniStreams *incomingStreamsMap[*ReceiveStream]
+ reset bool
+ supportsResetStreamAt bool
+}
+
+func newStreamsMap(
+ ctx context.Context,
+ sender streamSender,
+ queueControlFrame func(wire.Frame),
+ newFlowController func(protocol.StreamID) flowcontrol.StreamFlowController,
+ maxIncomingBidiStreams uint64,
+ maxIncomingUniStreams uint64,
+ perspective protocol.Perspective,
+) *streamsMap {
+ m := &streamsMap{
+ ctx: ctx,
+ perspective: perspective,
+ queueControlFrame: queueControlFrame,
+ newFlowController: newFlowController,
+ maxIncomingBidiStreams: maxIncomingBidiStreams,
+ maxIncomingUniStreams: maxIncomingUniStreams,
+ sender: sender,
+ }
+ m.initMaps()
+ return m
+}
+
+func (m *streamsMap) initMaps() {
+ m.outgoingBidiStreams = newOutgoingStreamsMap(
+ protocol.StreamTypeBidi,
+ func(id protocol.StreamID) *Stream {
+ return newStream(m.ctx, id, m.sender, m.newFlowController(id), m.supportsResetStreamAt)
+ },
+ m.queueControlFrame,
+ m.perspective,
+ )
+ m.incomingBidiStreams = newIncomingStreamsMap(
+ protocol.StreamTypeBidi,
+ func(id protocol.StreamID) *Stream {
+ return newStream(m.ctx, id, m.sender, m.newFlowController(id), m.supportsResetStreamAt)
+ },
+ m.maxIncomingBidiStreams,
+ m.queueControlFrame,
+ m.perspective,
+ )
+ m.outgoingUniStreams = newOutgoingStreamsMap(
+ protocol.StreamTypeUni,
+ func(id protocol.StreamID) *SendStream {
+ return newSendStream(m.ctx, id, m.sender, m.newFlowController(id), m.supportsResetStreamAt)
+ },
+ m.queueControlFrame,
+ m.perspective,
+ )
+ m.incomingUniStreams = newIncomingStreamsMap(
+ protocol.StreamTypeUni,
+ func(id protocol.StreamID) *ReceiveStream {
+ return newReceiveStream(id, m.sender, m.newFlowController(id))
+ },
+ m.maxIncomingUniStreams,
+ m.queueControlFrame,
+ m.perspective,
+ )
+}
+
+func (m *streamsMap) OpenStream() (*Stream, error) {
+ m.mutex.Lock()
+ reset := m.reset
+ mm := m.outgoingBidiStreams
+ m.mutex.Unlock()
+ if reset {
+ return nil, Err0RTTRejected
+ }
+ return mm.OpenStream()
+}
+
+func (m *streamsMap) OpenStreamSync(ctx context.Context) (*Stream, error) {
+ m.mutex.Lock()
+ reset := m.reset
+ mm := m.outgoingBidiStreams
+ m.mutex.Unlock()
+ if reset {
+ return nil, Err0RTTRejected
+ }
+ return mm.OpenStreamSync(ctx)
+}
+
+func (m *streamsMap) OpenUniStream() (*SendStream, error) {
+ m.mutex.Lock()
+ reset := m.reset
+ mm := m.outgoingUniStreams
+ m.mutex.Unlock()
+ if reset {
+ return nil, Err0RTTRejected
+ }
+ return mm.OpenStream()
+}
+
+func (m *streamsMap) OpenUniStreamSync(ctx context.Context) (*SendStream, error) {
+ m.mutex.Lock()
+ reset := m.reset
+ mm := m.outgoingUniStreams
+ m.mutex.Unlock()
+ if reset {
+ return nil, Err0RTTRejected
+ }
+ return mm.OpenStreamSync(ctx)
+}
+
+func (m *streamsMap) AcceptStream(ctx context.Context) (*Stream, error) {
+ m.mutex.Lock()
+ reset := m.reset
+ mm := m.incomingBidiStreams
+ m.mutex.Unlock()
+ if reset {
+ return nil, Err0RTTRejected
+ }
+ return mm.AcceptStream(ctx)
+}
+
+func (m *streamsMap) AcceptUniStream(ctx context.Context) (*ReceiveStream, error) {
+ m.mutex.Lock()
+ reset := m.reset
+ mm := m.incomingUniStreams
+ m.mutex.Unlock()
+ if reset {
+ return nil, Err0RTTRejected
+ }
+ return mm.AcceptStream(ctx)
+}
+
+func (m *streamsMap) DeleteStream(id protocol.StreamID) error {
+ switch id.Type() {
+ case protocol.StreamTypeUni:
+ if id.InitiatedBy() == m.perspective {
+ return m.outgoingUniStreams.DeleteStream(id)
+ }
+ return m.incomingUniStreams.DeleteStream(id)
+ case protocol.StreamTypeBidi:
+ if id.InitiatedBy() == m.perspective {
+ return m.outgoingBidiStreams.DeleteStream(id)
+ }
+ return m.incomingBidiStreams.DeleteStream(id)
+ }
+ panic("")
+}
+
+func (m *streamsMap) HandleMaxStreamsFrame(f *wire.MaxStreamsFrame) {
+ switch f.Type {
+ case protocol.StreamTypeUni:
+ m.outgoingUniStreams.SetMaxStream(f.MaxStreamNum.StreamID(protocol.StreamTypeUni, m.perspective))
+ case protocol.StreamTypeBidi:
+ m.outgoingBidiStreams.SetMaxStream(f.MaxStreamNum.StreamID(protocol.StreamTypeBidi, m.perspective))
+ }
+}
+
+type sendStreamFrameHandler interface {
+ updateSendWindow(protocol.ByteCount)
+ handleStopSendingFrame(*wire.StopSendingFrame)
+}
+
+func (m *streamsMap) getSendStream(id protocol.StreamID) (sendStreamFrameHandler, error) {
+ switch id.Type() {
+ case protocol.StreamTypeUni:
+ if id.InitiatedBy() != m.perspective {
+ // an outgoing unidirectional stream is a send stream, not a receive stream
+ return nil, &qerr.TransportError{
+ ErrorCode: qerr.StreamStateError,
+ ErrorMessage: fmt.Sprintf("invalid frame for send stream %d", id),
+ }
+ }
+ str, err := m.outgoingUniStreams.GetStream(id)
+ if str == nil || err != nil {
+ return nil, err
+ }
+ return str, nil
+ case protocol.StreamTypeBidi:
+ if id.InitiatedBy() == m.perspective {
+ str, err := m.outgoingBidiStreams.GetStream(id)
+ if str == nil || err != nil {
+ return nil, err
+ }
+ return str, nil
+ }
+ str, err := m.incomingBidiStreams.GetOrOpenStream(id)
+ if str == nil || err != nil {
+ return nil, err
+ }
+ return str, nil
+ }
+ panic("unreachable")
+}
+
+func (m *streamsMap) HandleMaxStreamDataFrame(f *wire.MaxStreamDataFrame) error {
+ str, err := m.getSendStream(f.StreamID)
+ if err != nil {
+ return err
+ }
+ if str == nil { // stream already deleted
+ return nil
+ }
+ str.updateSendWindow(f.MaximumStreamData)
+ return nil
+}
+
+func (m *streamsMap) HandleStopSendingFrame(f *wire.StopSendingFrame) error {
+ str, err := m.getSendStream(f.StreamID)
+ if err != nil {
+ return err
+ }
+ if str == nil { // stream already deleted
+ return nil
+ }
+ str.handleStopSendingFrame(f)
+ return nil
+}
+
+type receiveStreamFrameHandler interface {
+ handleResetStreamFrame(*wire.ResetStreamFrame, monotime.Time) error
+ handleStreamFrame(*wire.StreamFrame, monotime.Time) error
+}
+
+func (m *streamsMap) getReceiveStream(id protocol.StreamID) (receiveStreamFrameHandler, error) {
+ switch id.Type() {
+ case protocol.StreamTypeUni:
+ // an outgoing unidirectional stream is a send stream, not a receive stream
+ if id.InitiatedBy() == m.perspective {
+ return nil, &qerr.TransportError{
+ ErrorCode: qerr.StreamStateError,
+ ErrorMessage: fmt.Sprintf("invalid frame for receive stream %d", id),
+ }
+ }
+ str, err := m.incomingUniStreams.GetOrOpenStream(id)
+ if err != nil || str == nil {
+ return nil, err
+ }
+ return str, nil
+ case protocol.StreamTypeBidi:
+ var str *Stream
+ var err error
+ if id.InitiatedBy() == m.perspective {
+ str, err = m.outgoingBidiStreams.GetStream(id)
+ } else {
+ str, err = m.incomingBidiStreams.GetOrOpenStream(id)
+ }
+ if str == nil || err != nil {
+ return nil, err
+ }
+ return str, nil
+ }
+ panic("unreachable")
+}
+
+func (m *streamsMap) HandleStreamDataBlockedFrame(f *wire.StreamDataBlockedFrame) error {
+ if _, err := m.getReceiveStream(f.StreamID); err != nil {
+ return err
+ }
+ // We don't need to do anything in response to a STREAM_DATA_BLOCKED frame,
+ // but we need to make sure that the stream ID is valid.
+ return nil // we don't need to do anything in response to a STREAM_DATA_BLOCKED frame
+}
+
+func (m *streamsMap) HandleResetStreamFrame(f *wire.ResetStreamFrame, rcvTime monotime.Time) error {
+ str, err := m.getReceiveStream(f.StreamID)
+ if err != nil {
+ return err
+ }
+ if str == nil { // stream already deleted
+ return nil
+ }
+ return str.handleResetStreamFrame(f, rcvTime)
+}
+
+func (m *streamsMap) HandleStreamFrame(f *wire.StreamFrame, rcvTime monotime.Time) error {
+ str, err := m.getReceiveStream(f.StreamID)
+ if err != nil {
+ return err
+ }
+ if str == nil { // stream already deleted
+ return nil
+ }
+ return str.handleStreamFrame(f, rcvTime)
+}
+
+func (m *streamsMap) HandleTransportParameters(p *wire.TransportParameters) {
+ m.supportsResetStreamAt = p.EnableResetStreamAt
+ m.outgoingBidiStreams.EnableResetStreamAt()
+ m.outgoingUniStreams.EnableResetStreamAt()
+ m.outgoingBidiStreams.UpdateSendWindow(p.InitialMaxStreamDataBidiRemote)
+ m.outgoingBidiStreams.SetMaxStream(p.MaxBidiStreamNum.StreamID(protocol.StreamTypeBidi, m.perspective))
+ m.outgoingUniStreams.UpdateSendWindow(p.InitialMaxStreamDataUni)
+ m.outgoingUniStreams.SetMaxStream(p.MaxUniStreamNum.StreamID(protocol.StreamTypeUni, m.perspective))
+}
+
+func (m *streamsMap) CloseWithError(err error) {
+ m.outgoingBidiStreams.CloseWithError(err)
+ m.outgoingUniStreams.CloseWithError(err)
+ m.incomingBidiStreams.CloseWithError(err)
+ m.incomingUniStreams.CloseWithError(err)
+}
+
+// ResetFor0RTT resets is used when 0-RTT is rejected. In that case, the streams maps are
+// 1. closed with an Err0RTTRejected, making calls to Open{Uni}Stream{Sync} / Accept{Uni}Stream return that error.
+// 2. reset to their initial state, such that we can immediately process new incoming stream data.
+// Afterwards, calls to Open{Uni}Stream{Sync} / Accept{Uni}Stream will continue to return the error,
+// until UseResetMaps() has been called.
+func (m *streamsMap) ResetFor0RTT() {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
+ m.reset = true
+ m.CloseWithError(Err0RTTRejected)
+ m.initMaps()
+}
+
+func (m *streamsMap) UseResetMaps() {
+ m.mutex.Lock()
+ m.reset = false
+ m.mutex.Unlock()
+}
diff --git a/vendor/github.com/quic-go/quic-go/streams_map_incoming.go b/vendor/github.com/quic-go/quic-go/streams_map_incoming.go
new file mode 100644
index 00000000..c714eaf1
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/streams_map_incoming.go
@@ -0,0 +1,209 @@
+package quic
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type incomingStream interface {
+ closeForShutdown(error)
+}
+
+// When a stream is deleted before it was accepted, we can't delete it from the map immediately.
+// We need to wait until the application accepts it, and delete it then.
+type incomingStreamEntry[T incomingStream] struct {
+ stream T
+ shouldDelete bool
+}
+
+type incomingStreamsMap[T incomingStream] struct {
+ mutex sync.RWMutex
+ newStreamChan chan struct{}
+
+ streamType protocol.StreamType
+ streams map[protocol.StreamID]incomingStreamEntry[T]
+
+ nextStreamToAccept protocol.StreamID // the next stream that will be returned by AcceptStream()
+ nextStreamToOpen protocol.StreamID // the highest stream that the peer opened
+ maxStream protocol.StreamID // the highest stream that the peer is allowed to open
+ maxNumStreams uint64 // maximum number of streams
+
+ newStream func(protocol.StreamID) T
+ queueMaxStreamID func(*wire.MaxStreamsFrame)
+
+ closeErr error
+}
+
+func newIncomingStreamsMap[T incomingStream](
+ streamType protocol.StreamType,
+ newStream func(protocol.StreamID) T,
+ maxStreams uint64,
+ queueControlFrame func(wire.Frame),
+ pers protocol.Perspective,
+) *incomingStreamsMap[T] {
+ var nextStreamToAccept protocol.StreamID
+ switch {
+ case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveServer:
+ nextStreamToAccept = protocol.FirstIncomingBidiStreamServer
+ case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveClient:
+ nextStreamToAccept = protocol.FirstIncomingBidiStreamClient
+ case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveServer:
+ nextStreamToAccept = protocol.FirstIncomingUniStreamServer
+ case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveClient:
+ nextStreamToAccept = protocol.FirstIncomingUniStreamClient
+ }
+ return &incomingStreamsMap[T]{
+ newStreamChan: make(chan struct{}, 1),
+ streamType: streamType,
+ streams: make(map[protocol.StreamID]incomingStreamEntry[T]),
+ maxStream: protocol.StreamNum(maxStreams).StreamID(streamType, pers.Opposite()),
+ maxNumStreams: maxStreams,
+ newStream: newStream,
+ nextStreamToOpen: nextStreamToAccept,
+ nextStreamToAccept: nextStreamToAccept,
+ queueMaxStreamID: func(f *wire.MaxStreamsFrame) { queueControlFrame(f) },
+ }
+}
+
+func (m *incomingStreamsMap[T]) AcceptStream(ctx context.Context) (T, error) {
+ // drain the newStreamChan, so we don't check the map twice if the stream doesn't exist
+ select {
+ case <-m.newStreamChan:
+ default:
+ }
+
+ m.mutex.Lock()
+
+ var id protocol.StreamID
+ var entry incomingStreamEntry[T]
+ for {
+ id = m.nextStreamToAccept
+ if m.closeErr != nil {
+ m.mutex.Unlock()
+ return *new(T), m.closeErr
+ }
+ var ok bool
+ entry, ok = m.streams[id]
+ if ok {
+ break
+ }
+ m.mutex.Unlock()
+ select {
+ case <-ctx.Done():
+ return *new(T), ctx.Err()
+ case <-m.newStreamChan:
+ }
+ m.mutex.Lock()
+ }
+ m.nextStreamToAccept += 4
+ // If this stream was completed before being accepted, we can delete it now.
+ if entry.shouldDelete {
+ if err := m.deleteStream(id); err != nil {
+ m.mutex.Unlock()
+ return *new(T), err
+ }
+ }
+ m.mutex.Unlock()
+ return entry.stream, nil
+}
+
+func (m *incomingStreamsMap[T]) GetOrOpenStream(id protocol.StreamID) (T, error) {
+ m.mutex.RLock()
+ if id > m.maxStream {
+ m.mutex.RUnlock()
+ return *new(T), &qerr.TransportError{
+ ErrorCode: qerr.StreamLimitError,
+ ErrorMessage: fmt.Sprintf("peer tried to open stream %d (current limit: %d)", id, m.maxStream),
+ }
+ }
+ // if the num is smaller than the highest we accepted
+ // * this stream exists in the map, and we can return it, or
+ // * this stream was already closed, then we can return the nil
+ if id < m.nextStreamToOpen {
+ var s T
+ // If the stream was already queued for deletion, and is just waiting to be accepted, don't return it.
+ if entry, ok := m.streams[id]; ok && !entry.shouldDelete {
+ s = entry.stream
+ }
+ m.mutex.RUnlock()
+ return s, nil
+ }
+ m.mutex.RUnlock()
+
+ m.mutex.Lock()
+ // no need to check the two error conditions from above again
+ // * maxStream can only increase, so if the id was valid before, it definitely is valid now
+ // * highestStream is only modified by this function
+ for newNum := m.nextStreamToOpen; newNum <= id; newNum += 4 {
+ m.streams[newNum] = incomingStreamEntry[T]{stream: m.newStream(newNum)}
+ select {
+ case m.newStreamChan <- struct{}{}:
+ default:
+ }
+ }
+ m.nextStreamToOpen = id + 4
+ entry := m.streams[id]
+ m.mutex.Unlock()
+ return entry.stream, nil
+}
+
+func (m *incomingStreamsMap[T]) DeleteStream(id protocol.StreamID) error {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
+
+ if err := m.deleteStream(id); err != nil {
+ return &qerr.TransportError{
+ ErrorCode: qerr.StreamStateError,
+ ErrorMessage: err.Error(),
+ }
+ }
+ return nil
+}
+
+func (m *incomingStreamsMap[T]) deleteStream(id protocol.StreamID) error {
+ if _, ok := m.streams[id]; !ok {
+ return fmt.Errorf("tried to delete unknown incoming stream %d", id)
+ }
+
+ // Don't delete this stream yet, if it was not yet accepted.
+ // Just save it to streamsToDelete map, to make sure it is deleted as soon as it gets accepted.
+ if id >= m.nextStreamToAccept {
+ entry, ok := m.streams[id]
+ if ok && entry.shouldDelete {
+ return fmt.Errorf("tried to delete incoming stream %d multiple times", id)
+ }
+ entry.shouldDelete = true
+ m.streams[id] = entry // can't assign to struct in map, so we need to reassign
+ return nil
+ }
+
+ delete(m.streams, id)
+ // queue a MAX_STREAM_ID frame, giving the peer the option to open a new stream
+ if m.maxNumStreams > uint64(len(m.streams)) {
+ maxStream := m.nextStreamToOpen + 4*protocol.StreamID(m.maxNumStreams-uint64(len(m.streams))-1)
+ // never send a value larger than the maximum value for a stream number
+ if maxStream <= protocol.MaxStreamID {
+ m.maxStream = maxStream
+ m.queueMaxStreamID(&wire.MaxStreamsFrame{
+ Type: m.streamType,
+ MaxStreamNum: m.maxStream.StreamNum(),
+ })
+ }
+ }
+ return nil
+}
+
+func (m *incomingStreamsMap[T]) CloseWithError(err error) {
+ m.mutex.Lock()
+ m.closeErr = err
+ for _, entry := range m.streams {
+ entry.stream.closeForShutdown(err)
+ }
+ m.mutex.Unlock()
+ close(m.newStreamChan)
+}
diff --git a/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go b/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go
new file mode 100644
index 00000000..14e087c6
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go
@@ -0,0 +1,253 @@
+package quic
+
+import (
+ "context"
+ "fmt"
+ "slices"
+ "sync"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/qerr"
+ "github.com/quic-go/quic-go/internal/wire"
+)
+
+type outgoingStream interface {
+ updateSendWindow(protocol.ByteCount)
+ enableResetStreamAt()
+ closeForShutdown(error)
+}
+
+type outgoingStreamsMap[T outgoingStream] struct {
+ mutex sync.RWMutex
+
+ streamType protocol.StreamType
+ streams map[protocol.StreamID]T
+
+ openQueue []chan struct{}
+
+ nextStream protocol.StreamID // stream ID of the stream returned by OpenStream(Sync)
+ maxStream protocol.StreamID // the maximum stream ID we're allowed to open
+ blockedSent bool // was a STREAMS_BLOCKED sent for the current maxStream
+
+ newStream func(protocol.StreamID) T
+ queueStreamIDBlocked func(*wire.StreamsBlockedFrame)
+
+ closeErr error
+}
+
+func newOutgoingStreamsMap[T outgoingStream](
+ streamType protocol.StreamType,
+ newStream func(protocol.StreamID) T,
+ queueControlFrame func(wire.Frame),
+ pers protocol.Perspective,
+) *outgoingStreamsMap[T] {
+ var nextStream protocol.StreamID
+ switch {
+ case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveServer:
+ nextStream = protocol.FirstOutgoingBidiStreamServer
+ case streamType == protocol.StreamTypeBidi && pers == protocol.PerspectiveClient:
+ nextStream = protocol.FirstOutgoingBidiStreamClient
+ case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveServer:
+ nextStream = protocol.FirstOutgoingUniStreamServer
+ case streamType == protocol.StreamTypeUni && pers == protocol.PerspectiveClient:
+ nextStream = protocol.FirstOutgoingUniStreamClient
+ }
+ return &outgoingStreamsMap[T]{
+ streamType: streamType,
+ streams: make(map[protocol.StreamID]T),
+ maxStream: protocol.InvalidStreamNum,
+ nextStream: nextStream,
+ newStream: newStream,
+ queueStreamIDBlocked: func(f *wire.StreamsBlockedFrame) { queueControlFrame(f) },
+ }
+}
+
+func (m *outgoingStreamsMap[T]) OpenStream() (T, error) {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
+
+ if m.closeErr != nil {
+ return *new(T), m.closeErr
+ }
+
+ // if there are OpenStreamSync calls waiting, return an error here
+ if len(m.openQueue) > 0 || m.nextStream > m.maxStream {
+ m.maybeSendBlockedFrame()
+ return *new(T), &StreamLimitReachedError{}
+ }
+ return m.openStream(), nil
+}
+
+func (m *outgoingStreamsMap[T]) OpenStreamSync(ctx context.Context) (T, error) {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
+
+ if m.closeErr != nil {
+ return *new(T), m.closeErr
+ }
+ if err := ctx.Err(); err != nil {
+ return *new(T), err
+ }
+ if len(m.openQueue) == 0 && m.nextStream <= m.maxStream {
+ return m.openStream(), nil
+ }
+
+ waitChan := make(chan struct{}, 1)
+ m.openQueue = append(m.openQueue, waitChan)
+ m.maybeSendBlockedFrame()
+
+ for {
+ m.mutex.Unlock()
+ select {
+ case <-ctx.Done():
+ m.mutex.Lock()
+ m.openQueue = slices.DeleteFunc(m.openQueue, func(c chan struct{}) bool {
+ return c == waitChan
+ })
+ // If we just received a MAX_STREAMS frame, this might have been the next stream
+ // that could be opened. Make sure we unblock the next OpenStreamSync call.
+ m.maybeUnblockOpenSync()
+ return *new(T), ctx.Err()
+ case <-waitChan:
+ }
+
+ m.mutex.Lock()
+ if m.closeErr != nil {
+ return *new(T), m.closeErr
+ }
+ if err := ctx.Err(); err != nil {
+ m.openQueue = slices.DeleteFunc(m.openQueue, func(c chan struct{}) bool {
+ return c == waitChan
+ })
+ m.maybeUnblockOpenSync()
+ return *new(T), err
+ }
+ if m.nextStream > m.maxStream {
+ // no stream available. Continue waiting
+ continue
+ }
+ str := m.openStream()
+ m.openQueue = m.openQueue[1:]
+ m.maybeUnblockOpenSync()
+ return str, nil
+ }
+}
+
+func (m *outgoingStreamsMap[T]) openStream() T {
+ s := m.newStream(m.nextStream)
+ m.streams[m.nextStream] = s
+ m.nextStream += 4
+ return s
+}
+
+// maybeSendBlockedFrame queues a STREAMS_BLOCKED frame for the current stream offset,
+// if we haven't sent one for this offset yet
+func (m *outgoingStreamsMap[T]) maybeSendBlockedFrame() {
+ if m.blockedSent {
+ return
+ }
+
+ var streamLimit protocol.StreamNum
+ if m.maxStream != protocol.InvalidStreamID {
+ streamLimit = m.maxStream.StreamNum()
+ }
+ m.queueStreamIDBlocked(&wire.StreamsBlockedFrame{
+ Type: m.streamType,
+ StreamLimit: streamLimit,
+ })
+ m.blockedSent = true
+}
+
+func (m *outgoingStreamsMap[T]) GetStream(id protocol.StreamID) (T, error) {
+ m.mutex.RLock()
+ if id >= m.nextStream {
+ m.mutex.RUnlock()
+ return *new(T), &qerr.TransportError{
+ ErrorCode: qerr.StreamStateError,
+ ErrorMessage: fmt.Sprintf("peer attempted to open stream %d", id),
+ }
+ }
+ s := m.streams[id]
+ m.mutex.RUnlock()
+ return s, nil
+}
+
+func (m *outgoingStreamsMap[T]) DeleteStream(id protocol.StreamID) error {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
+
+ if _, ok := m.streams[id]; !ok {
+ return &qerr.TransportError{
+ ErrorCode: qerr.StreamStateError,
+ ErrorMessage: fmt.Sprintf("tried to delete unknown outgoing stream %d", id),
+ }
+ }
+ delete(m.streams, id)
+ return nil
+}
+
+func (m *outgoingStreamsMap[T]) SetMaxStream(id protocol.StreamID) {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
+
+ if id <= m.maxStream {
+ return
+ }
+ m.maxStream = id
+ m.blockedSent = false
+ if m.maxStream < m.nextStream-4+4*protocol.StreamID(len(m.openQueue)) {
+ m.maybeSendBlockedFrame()
+ }
+ m.maybeUnblockOpenSync()
+}
+
+// UpdateSendWindow is called when the peer's transport parameters are received.
+// Only in the case of a 0-RTT handshake will we have open streams at this point.
+// We might need to update the send window, in case the server increased it.
+func (m *outgoingStreamsMap[T]) UpdateSendWindow(limit protocol.ByteCount) {
+ m.mutex.Lock()
+ for _, str := range m.streams {
+ str.updateSendWindow(limit)
+ }
+ m.mutex.Unlock()
+}
+
+func (m *outgoingStreamsMap[T]) EnableResetStreamAt() {
+ m.mutex.Lock()
+ for _, str := range m.streams {
+ str.enableResetStreamAt()
+ }
+ m.mutex.Unlock()
+}
+
+// unblockOpenSync unblocks the next OpenStreamSync go-routine to open a new stream
+func (m *outgoingStreamsMap[T]) maybeUnblockOpenSync() {
+ if len(m.openQueue) == 0 {
+ return
+ }
+ if m.nextStream > m.maxStream {
+ return
+ }
+ // unblockOpenSync is called both from OpenStreamSync and from SetMaxStream.
+ // It's sufficient to only unblock OpenStreamSync once.
+ select {
+ case m.openQueue[0] <- struct{}{}:
+ default:
+ }
+}
+
+func (m *outgoingStreamsMap[T]) CloseWithError(err error) {
+ m.mutex.Lock()
+ defer m.mutex.Unlock()
+
+ m.closeErr = err
+ for _, str := range m.streams {
+ str.closeForShutdown(err)
+ }
+ for _, c := range m.openQueue {
+ if c != nil {
+ close(c)
+ }
+ }
+ m.openQueue = nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn.go b/vendor/github.com/quic-go/quic-go/sys_conn.go
new file mode 100644
index 00000000..ce35de88
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn.go
@@ -0,0 +1,143 @@
+package quic
+
+import (
+ "io"
+ "log"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+type connCapabilities struct {
+ // This connection has the Don't Fragment (DF) bit set.
+ // This means it makes to run DPLPMTUD.
+ DF bool
+ // GSO (Generic Segmentation Offload) supported
+ GSO bool
+ // ECN (Explicit Congestion Notifications) supported
+ ECN bool
+}
+
+// rawConn is a connection that allow reading of a receivedPackeh.
+type rawConn interface {
+ ReadPacket() (receivedPacket, error)
+ // WritePacket writes a packet on the wire.
+ // gsoSize is the size of a single packet, or 0 to disable GSO.
+ // It is invalid to set gsoSize if capabilities.GSO is not set.
+ WritePacket(b []byte, addr net.Addr, packetInfoOOB []byte, gsoSize uint16, ecn protocol.ECN) (int, error)
+ LocalAddr() net.Addr
+ SetReadDeadline(time.Time) error
+ io.Closer
+
+ capabilities() connCapabilities
+}
+
+// OOBCapablePacketConn is a connection that allows the reading of ECN bits from the IP header.
+// If the PacketConn passed to the [Transport] satisfies this interface, quic-go will use it.
+// In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets.
+type OOBCapablePacketConn interface {
+ net.PacketConn
+ SyscallConn() (syscall.RawConn, error)
+ SetReadBuffer(int) error
+ ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
+ WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
+}
+
+var _ OOBCapablePacketConn = &net.UDPConn{}
+
+func wrapConn(pc net.PacketConn) (rawConn, error) {
+ if err := setReceiveBuffer(pc); err != nil {
+ if !strings.Contains(err.Error(), "use of closed network connection") {
+ setBufferWarningOnce.Do(func() {
+ if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
+ return
+ }
+ log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
+ })
+ }
+ }
+ if err := setSendBuffer(pc); err != nil {
+ if !strings.Contains(err.Error(), "use of closed network connection") {
+ setBufferWarningOnce.Do(func() {
+ if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
+ return
+ }
+ log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
+ })
+ }
+ }
+
+ conn, ok := pc.(interface {
+ SyscallConn() (syscall.RawConn, error)
+ })
+ var supportsDF bool
+ if ok {
+ rawConn, err := conn.SyscallConn()
+ if err != nil {
+ return nil, err
+ }
+
+ // only set DF on UDP sockets
+ if _, ok := pc.LocalAddr().(*net.UDPAddr); ok {
+ var err error
+ supportsDF, err = setDF(rawConn)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ c, ok := pc.(OOBCapablePacketConn)
+ if !ok {
+ utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.")
+ return &basicConn{PacketConn: pc, supportsDF: supportsDF}, nil
+ }
+ return newConn(c, supportsDF)
+}
+
+// The basicConn is the most trivial implementation of a rawConn.
+// It reads a single packet from the underlying net.PacketConn.
+// It is used when
+// * the net.PacketConn is not a OOBCapablePacketConn, and
+// * when the OS doesn't support OOB.
+type basicConn struct {
+ net.PacketConn
+ supportsDF bool
+}
+
+var _ rawConn = &basicConn{}
+
+func (c *basicConn) ReadPacket() (receivedPacket, error) {
+ buffer := getPacketBuffer()
+ // The packet size should not exceed protocol.MaxPacketBufferSize bytes
+ // If it does, we only read a truncated packet, which will then end up undecryptable
+ buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
+ n, addr, err := c.ReadFrom(buffer.Data)
+ if err != nil {
+ return receivedPacket{}, err
+ }
+ return receivedPacket{
+ remoteAddr: addr,
+ rcvTime: monotime.Now(),
+ data: buffer.Data[:n],
+ buffer: buffer,
+ }, nil
+}
+
+func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte, gsoSize uint16, ecn protocol.ECN) (n int, err error) {
+ if gsoSize != 0 {
+ panic("cannot use GSO with a basicConn")
+ }
+ if ecn != protocol.ECNUnsupported {
+ panic("cannot use ECN with a basicConn")
+ }
+ return c.WriteTo(b, addr)
+}
+
+func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} }
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_buffers.go b/vendor/github.com/quic-go/quic-go/sys_conn_buffers.go
new file mode 100644
index 00000000..8fe49162
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_buffers.go
@@ -0,0 +1,68 @@
+package quic
+
+import (
+ "errors"
+ "fmt"
+ "net"
+ "syscall"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+//go:generate sh -c "echo '// Code generated by go generate. DO NOT EDIT.\n// Source: sys_conn_buffers.go\n' > sys_conn_buffers_write.go && sed -e 's/SetReadBuffer/SetWriteBuffer/g' -e 's/setReceiveBuffer/setSendBuffer/g' -e 's/inspectReadBuffer/inspectWriteBuffer/g' -e 's/protocol\\.DesiredReceiveBufferSize/protocol\\.DesiredSendBufferSize/g' -e 's/forceSetReceiveBuffer/forceSetSendBuffer/g' -e 's/receive buffer/send buffer/g' sys_conn_buffers.go | sed '/^\\/\\/go:generate/d' >> sys_conn_buffers_write.go"
+func setReceiveBuffer(c net.PacketConn) error {
+ conn, ok := c.(interface{ SetReadBuffer(int) error })
+ if !ok {
+ return errors.New("connection doesn't allow setting of receive buffer size. Not a *net.UDPConn?")
+ }
+
+ var syscallConn syscall.RawConn
+ if sc, ok := c.(interface {
+ SyscallConn() (syscall.RawConn, error)
+ }); ok {
+ var err error
+ syscallConn, err = sc.SyscallConn()
+ if err != nil {
+ syscallConn = nil
+ }
+ }
+ // The connection has a SetReadBuffer method, but we couldn't obtain a syscall.RawConn.
+ // This shouldn't happen for a net.UDPConn, but is possible if the connection just implements the
+ // net.PacketConn interface and the SetReadBuffer method.
+ // We have no way of checking if increasing the buffer size actually worked.
+ if syscallConn == nil {
+ return conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
+ }
+
+ size, err := inspectReadBuffer(syscallConn)
+ if err != nil {
+ return fmt.Errorf("failed to determine receive buffer size: %w", err)
+ }
+ if size >= protocol.DesiredReceiveBufferSize {
+ utils.DefaultLogger.Debugf("Conn has receive buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024)
+ return nil
+ }
+ // Ignore the error. We check if we succeeded by querying the buffer size afterward.
+ _ = conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
+ newSize, err := inspectReadBuffer(syscallConn)
+ if newSize < protocol.DesiredReceiveBufferSize {
+ // Try again with RCVBUFFORCE on Linux
+ _ = forceSetReceiveBuffer(syscallConn, protocol.DesiredReceiveBufferSize)
+ newSize, err = inspectReadBuffer(syscallConn)
+ if err != nil {
+ return fmt.Errorf("failed to determine receive buffer size: %w", err)
+ }
+ }
+ if err != nil {
+ return fmt.Errorf("failed to determine receive buffer size: %w", err)
+ }
+ if newSize == size {
+ return fmt.Errorf("failed to increase receive buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredReceiveBufferSize/1024, newSize/1024)
+ }
+ if newSize < protocol.DesiredReceiveBufferSize {
+ return fmt.Errorf("failed to sufficiently increase receive buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024, newSize/1024)
+ }
+ utils.DefaultLogger.Debugf("Increased receive buffer size to %d kiB", newSize/1024)
+ return nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go b/vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go
new file mode 100644
index 00000000..c01a931b
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go
@@ -0,0 +1,70 @@
+// Code generated by go generate. DO NOT EDIT.
+// Source: sys_conn_buffers.go
+
+package quic
+
+import (
+ "errors"
+ "fmt"
+ "net"
+ "syscall"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+func setSendBuffer(c net.PacketConn) error {
+ conn, ok := c.(interface{ SetWriteBuffer(int) error })
+ if !ok {
+ return errors.New("connection doesn't allow setting of send buffer size. Not a *net.UDPConn?")
+ }
+
+ var syscallConn syscall.RawConn
+ if sc, ok := c.(interface {
+ SyscallConn() (syscall.RawConn, error)
+ }); ok {
+ var err error
+ syscallConn, err = sc.SyscallConn()
+ if err != nil {
+ syscallConn = nil
+ }
+ }
+ // The connection has a SetWriteBuffer method, but we couldn't obtain a syscall.RawConn.
+ // This shouldn't happen for a net.UDPConn, but is possible if the connection just implements the
+ // net.PacketConn interface and the SetWriteBuffer method.
+ // We have no way of checking if increasing the buffer size actually worked.
+ if syscallConn == nil {
+ return conn.SetWriteBuffer(protocol.DesiredSendBufferSize)
+ }
+
+ size, err := inspectWriteBuffer(syscallConn)
+ if err != nil {
+ return fmt.Errorf("failed to determine send buffer size: %w", err)
+ }
+ if size >= protocol.DesiredSendBufferSize {
+ utils.DefaultLogger.Debugf("Conn has send buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredSendBufferSize/1024)
+ return nil
+ }
+ // Ignore the error. We check if we succeeded by querying the buffer size afterward.
+ _ = conn.SetWriteBuffer(protocol.DesiredSendBufferSize)
+ newSize, err := inspectWriteBuffer(syscallConn)
+ if newSize < protocol.DesiredSendBufferSize {
+ // Try again with RCVBUFFORCE on Linux
+ _ = forceSetSendBuffer(syscallConn, protocol.DesiredSendBufferSize)
+ newSize, err = inspectWriteBuffer(syscallConn)
+ if err != nil {
+ return fmt.Errorf("failed to determine send buffer size: %w", err)
+ }
+ }
+ if err != nil {
+ return fmt.Errorf("failed to determine send buffer size: %w", err)
+ }
+ if newSize == size {
+ return fmt.Errorf("failed to increase send buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredSendBufferSize/1024, newSize/1024)
+ }
+ if newSize < protocol.DesiredSendBufferSize {
+ return fmt.Errorf("failed to sufficiently increase send buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredSendBufferSize/1024, newSize/1024)
+ }
+ utils.DefaultLogger.Debugf("Increased send buffer size to %d kiB", newSize/1024)
+ return nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_df.go b/vendor/github.com/quic-go/quic-go/sys_conn_df.go
new file mode 100644
index 00000000..0db61509
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_df.go
@@ -0,0 +1,22 @@
+//go:build !linux && !windows && !darwin
+
+package quic
+
+import (
+ "syscall"
+)
+
+func setDF(syscall.RawConn) (bool, error) {
+ // no-op on unsupported platforms
+ return false, nil
+}
+
+func isSendMsgSizeErr(err error) bool {
+ // to be implemented for more specific platforms
+ return false
+}
+
+func isRecvMsgSizeErr(err error) bool {
+ // to be implemented for more specific platforms
+ return false
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_df_darwin.go b/vendor/github.com/quic-go/quic-go/sys_conn_df_darwin.go
new file mode 100644
index 00000000..afaa6841
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_df_darwin.go
@@ -0,0 +1,90 @@
+//go:build darwin
+
+package quic
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+// for macOS versions, see https://en.wikipedia.org/wiki/Darwin_(operating_system)#Darwin_20_onwards
+const (
+ macOSVersion11 = 20
+ macOSVersion15 = 24
+)
+
+func setDF(rawConn syscall.RawConn) (bool, error) {
+ // Setting DF bit is only supported from macOS 11.
+ // https://github.com/chromium/chromium/blob/117.0.5881.2/net/socket/udp_socket_posix.cc#L555
+ version, err := getMacOSVersion()
+ if err != nil || version < macOSVersion11 {
+ return false, err
+ }
+
+ var controlErr error
+ var disableDF bool
+ if err := rawConn.Control(func(fd uintptr) {
+ addr, err := unix.Getsockname(int(fd))
+ if err != nil {
+ controlErr = fmt.Errorf("getsockname: %w", err)
+ return
+ }
+
+ // Dual-stack sockets are effectively IPv6 sockets (with IPV6_ONLY set to 0).
+ // On macOS, the DF bit on dual-stack sockets is controlled by the IPV6_DONTFRAG option.
+ // See https://datatracker.ietf.org/doc/draft-seemann-tsvwg-udp-fragmentation/ for details.
+ switch addr.(type) {
+ case *unix.SockaddrInet4:
+ controlErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_DONTFRAG, 1)
+ case *unix.SockaddrInet6:
+ controlErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_DONTFRAG, 1)
+
+ // Setting the DF bit on dual-stack sockets works since macOS Sequoia.
+ // Disable DF on dual-stack sockets before Sequoia.
+ if version < macOSVersion15 {
+ // check if this is a dual-stack socket by reading the IPV6_V6ONLY flag
+ v6only, err := unix.GetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_V6ONLY)
+ if err != nil {
+ controlErr = fmt.Errorf("getting IPV6_V6ONLY: %w", err)
+ return
+ }
+ disableDF = v6only == 0
+ }
+ default:
+ controlErr = fmt.Errorf("unknown address type: %T", addr)
+ }
+ }); err != nil {
+ return false, err
+ }
+ if controlErr != nil {
+ return false, controlErr
+ }
+ return !disableDF, nil
+}
+
+func isSendMsgSizeErr(err error) bool {
+ return errors.Is(err, unix.EMSGSIZE)
+}
+
+func isRecvMsgSizeErr(error) bool { return false }
+
+func getMacOSVersion() (int, error) {
+ uname := &unix.Utsname{}
+ if err := unix.Uname(uname); err != nil {
+ return 0, err
+ }
+ before, _, ok := strings.Cut(string(uname.Release[:]), ".")
+ if !ok {
+ return 0, nil
+ }
+ version, err := strconv.Atoi(before)
+ if err != nil {
+ return 0, err
+ }
+ return version, nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_df_linux.go b/vendor/github.com/quic-go/quic-go/sys_conn_df_linux.go
new file mode 100644
index 00000000..b09a2394
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_df_linux.go
@@ -0,0 +1,42 @@
+//go:build linux
+
+package quic
+
+import (
+ "errors"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+func setDF(rawConn syscall.RawConn) (bool, error) {
+ // Enabling IP_MTU_DISCOVER will force the kernel to return "sendto: message too long"
+ // and the datagram will not be fragmented
+ var errDFIPv4, errDFIPv6 error
+ if err := rawConn.Control(func(fd uintptr) {
+ errDFIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_MTU_DISCOVER, unix.IP_PMTUDISC_PROBE)
+ errDFIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_MTU_DISCOVER, unix.IPV6_PMTUDISC_PROBE)
+ }); err != nil {
+ return false, err
+ }
+ switch {
+ case errDFIPv4 == nil && errDFIPv6 == nil:
+ utils.DefaultLogger.Debugf("Setting DF for IPv4 and IPv6.")
+ case errDFIPv4 == nil && errDFIPv6 != nil:
+ utils.DefaultLogger.Debugf("Setting DF for IPv4.")
+ case errDFIPv4 != nil && errDFIPv6 == nil:
+ utils.DefaultLogger.Debugf("Setting DF for IPv6.")
+ case errDFIPv4 != nil && errDFIPv6 != nil:
+ return false, errors.New("setting DF failed for both IPv4 and IPv6")
+ }
+ return true, nil
+}
+
+func isSendMsgSizeErr(err error) bool {
+ // https://man7.org/linux/man-pages/man7/udp.7.html
+ return errors.Is(err, unix.EMSGSIZE)
+}
+
+func isRecvMsgSizeErr(error) bool { return false }
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_df_windows.go b/vendor/github.com/quic-go/quic-go/sys_conn_df_windows.go
new file mode 100644
index 00000000..4c140f00
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_df_windows.go
@@ -0,0 +1,52 @@
+//go:build windows
+
+package quic
+
+import (
+ "errors"
+ "syscall"
+
+ "golang.org/x/sys/windows"
+
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+const (
+ // https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinSock/constant.IP_DONTFRAGMENT.html
+ //nolint:stylecheck
+ IP_DONTFRAGMENT = 14
+ // https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Networking/WinSock/constant.IPV6_DONTFRAG.html
+ //nolint:stylecheck
+ IPV6_DONTFRAG = 14
+)
+
+func setDF(rawConn syscall.RawConn) (bool, error) {
+ var errDFIPv4, errDFIPv6 error
+ if err := rawConn.Control(func(fd uintptr) {
+ errDFIPv4 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, IP_DONTFRAGMENT, 1)
+ errDFIPv6 = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, IPV6_DONTFRAG, 1)
+ }); err != nil {
+ return false, err
+ }
+ switch {
+ case errDFIPv4 == nil && errDFIPv6 == nil:
+ utils.DefaultLogger.Debugf("Setting DF for IPv4 and IPv6.")
+ case errDFIPv4 == nil && errDFIPv6 != nil:
+ utils.DefaultLogger.Debugf("Setting DF for IPv4.")
+ case errDFIPv4 != nil && errDFIPv6 == nil:
+ utils.DefaultLogger.Debugf("Setting DF for IPv6.")
+ case errDFIPv4 != nil && errDFIPv6 != nil:
+ return false, errors.New("setting DF failed for both IPv4 and IPv6")
+ }
+ return true, nil
+}
+
+func isSendMsgSizeErr(err error) bool {
+ // https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
+ return errors.Is(err, windows.WSAEMSGSIZE)
+}
+
+func isRecvMsgSizeErr(err error) bool {
+ // https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
+ return errors.Is(err, windows.WSAEMSGSIZE)
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_helper_darwin.go b/vendor/github.com/quic-go/quic-go/sys_conn_helper_darwin.go
new file mode 100644
index 00000000..a04bfb3c
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_helper_darwin.go
@@ -0,0 +1,38 @@
+//go:build darwin
+
+package quic
+
+import (
+ "encoding/binary"
+ "net/netip"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ msgTypeIPTOS = unix.IP_RECVTOS
+ ipv4PKTINFO = unix.IP_RECVPKTINFO
+)
+
+const ecnIPv4DataLen = 4
+
+// ReadBatch only returns a single packet on OSX,
+// see https://godoc.org/golang.org/x/net/ipv4#PacketConn.ReadBatch.
+const batchSize = 1
+
+func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) {
+ // struct in_pktinfo {
+ // unsigned int ipi_ifindex; /* Interface index */
+ // struct in_addr ipi_spec_dst; /* Local address */
+ // struct in_addr ipi_addr; /* Header Destination address */
+ // };
+ if len(body) != 12 {
+ return netip.Addr{}, 0, false
+ }
+ return netip.AddrFrom4(*(*[4]byte)(body[8:12])), binary.NativeEndian.Uint32(body), true
+}
+
+func isGSOEnabled(syscall.RawConn) bool { return false }
+
+func isECNEnabled() bool { return !isECNDisabledUsingEnv() }
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_helper_freebsd.go b/vendor/github.com/quic-go/quic-go/sys_conn_helper_freebsd.go
new file mode 100644
index 00000000..521f80d4
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_helper_freebsd.go
@@ -0,0 +1,33 @@
+//go:build freebsd
+
+package quic
+
+import (
+ "net/netip"
+ "syscall"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ msgTypeIPTOS = unix.IP_RECVTOS
+ ipv4PKTINFO = 0x7
+)
+
+const ecnIPv4DataLen = 1
+
+const batchSize = 8
+
+func parseIPv4PktInfo(body []byte) (ip netip.Addr, _ uint32, ok bool) {
+ // struct in_pktinfo {
+ // struct in_addr ipi_addr; /* Header Destination address */
+ // };
+ if len(body) != 4 {
+ return netip.Addr{}, 0, false
+ }
+ return netip.AddrFrom4(*(*[4]byte)(body)), 0, true
+}
+
+func isGSOEnabled(syscall.RawConn) bool { return false }
+
+func isECNEnabled() bool { return !isECNDisabledUsingEnv() }
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go b/vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go
new file mode 100644
index 00000000..9a890cbe
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go
@@ -0,0 +1,156 @@
+//go:build linux
+
+package quic
+
+import (
+ "encoding/binary"
+ "errors"
+ "net/netip"
+ "os"
+ "strconv"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/unix"
+)
+
+const (
+ msgTypeIPTOS = unix.IP_TOS
+ ipv4PKTINFO = unix.IP_PKTINFO
+)
+
+const ecnIPv4DataLen = 1
+
+const batchSize = 8 // needs to smaller than MaxUint8 (otherwise the type of oobConn.readPos has to be changed)
+
+var kernelVersionMajor int
+
+func init() {
+ kernelVersionMajor, _ = kernelVersion()
+}
+
+func forceSetReceiveBuffer(c syscall.RawConn, bytes int) error {
+ var serr error
+ if err := c.Control(func(fd uintptr) {
+ serr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, bytes)
+ }); err != nil {
+ return err
+ }
+ return serr
+}
+
+func forceSetSendBuffer(c syscall.RawConn, bytes int) error {
+ var serr error
+ if err := c.Control(func(fd uintptr) {
+ serr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, bytes)
+ }); err != nil {
+ return err
+ }
+ return serr
+}
+
+func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) {
+ // struct in_pktinfo {
+ // unsigned int ipi_ifindex; /* Interface index */
+ // struct in_addr ipi_spec_dst; /* Local address */
+ // struct in_addr ipi_addr; /* Header Destination address */
+ // };
+ if len(body) != 12 {
+ return netip.Addr{}, 0, false
+ }
+ return netip.AddrFrom4(*(*[4]byte)(body[8:12])), binary.NativeEndian.Uint32(body), true
+}
+
+// isGSOEnabled tests if the kernel supports GSO.
+// Sending with GSO might still fail later on, if the interface doesn't support it (see isGSOError).
+func isGSOEnabled(conn syscall.RawConn) bool {
+ if kernelVersionMajor < 5 {
+ return false
+ }
+ disabled, err := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_GSO"))
+ if err == nil && disabled {
+ return false
+ }
+ var serr error
+ if err := conn.Control(func(fd uintptr) {
+ _, serr = unix.GetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_SEGMENT)
+ }); err != nil {
+ return false
+ }
+ return serr == nil
+}
+
+func appendUDPSegmentSizeMsg(b []byte, size uint16) []byte {
+ startLen := len(b)
+ const dataLen = 2 // payload is a uint16
+ b = append(b, make([]byte, unix.CmsgSpace(dataLen))...)
+ h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen]))
+ h.Level = syscall.IPPROTO_UDP
+ h.Type = unix.UDP_SEGMENT
+ h.SetLen(unix.CmsgLen(dataLen))
+
+ // UnixRights uses the private `data` method, but I *think* this achieves the same goal.
+ offset := startLen + unix.CmsgSpace(0)
+ *(*uint16)(unsafe.Pointer(&b[offset])) = size
+ return b
+}
+
+func isGSOError(err error) bool {
+ var serr *os.SyscallError
+ if errors.As(err, &serr) {
+ // EIO is returned by udp_send_skb() if the device driver does not have tx checksums enabled,
+ // which is a hard requirement of UDP_SEGMENT. See:
+ // https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man7/udp.7?id=806eabd74910447f21005160e90957bde4db0183#n228
+ // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv4/udp.c?h=v6.2&id=c9c3395d5e3dcc6daee66c6908354d47bf98cb0c#n942
+ return serr.Err == unix.EIO
+ }
+ return false
+}
+
+// The first sendmsg call on a new UDP socket sometimes errors on Linux.
+// It's not clear why this happens.
+// See https://github.com/golang/go/issues/63322.
+func isPermissionError(err error) bool {
+ var serr *os.SyscallError
+ if errors.As(err, &serr) {
+ return serr.Syscall == "sendmsg" && serr.Err == unix.EPERM
+ }
+ return false
+}
+
+func isECNEnabled() bool {
+ return kernelVersionMajor >= 5 && !isECNDisabledUsingEnv()
+}
+
+// kernelVersion returns major and minor kernel version numbers, parsed from
+// the syscall.Uname's Release field, or 0, 0 if the version can't be obtained
+// or parsed.
+//
+// copied from the standard library's internal/syscall/unix/kernel_version_linux.go
+func kernelVersion() (major, minor int) {
+ var uname syscall.Utsname
+ if err := syscall.Uname(&uname); err != nil {
+ return
+ }
+
+ var (
+ values [2]int
+ value, vi int
+ )
+ for _, c := range uname.Release {
+ if '0' <= c && c <= '9' {
+ value = (value * 10) + int(c-'0')
+ } else {
+ // Note that we're assuming N.N.N here.
+ // If we see anything else, we are likely to mis-parse it.
+ values[vi] = value
+ vi++
+ if vi >= len(values) {
+ break
+ }
+ value = 0
+ }
+ }
+
+ return values[0], values[1]
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go b/vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go
new file mode 100644
index 00000000..f8d69803
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go
@@ -0,0 +1,10 @@
+//go:build !linux
+
+package quic
+
+func forceSetReceiveBuffer(c any, bytes int) error { return nil }
+func forceSetSendBuffer(c any, bytes int) error { return nil }
+
+func appendUDPSegmentSizeMsg([]byte, uint16) []byte { return nil }
+func isGSOError(error) bool { return false }
+func isPermissionError(err error) bool { return false }
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go b/vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go
new file mode 100644
index 00000000..2a1f807e
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go
@@ -0,0 +1,21 @@
+//go:build !darwin && !linux && !freebsd && !windows
+
+package quic
+
+import (
+ "net"
+ "net/netip"
+)
+
+func newConn(c net.PacketConn, supportsDF bool) (*basicConn, error) {
+ return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
+}
+
+func inspectReadBuffer(any) (int, error) { return 0, nil }
+func inspectWriteBuffer(any) (int, error) { return 0, nil }
+
+type packetInfo struct {
+ addr netip.Addr
+}
+
+func (i *packetInfo) OOB() []byte { return nil }
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_oob.go b/vendor/github.com/quic-go/quic-go/sys_conn_oob.go
new file mode 100644
index 00000000..8a5f37bd
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_oob.go
@@ -0,0 +1,338 @@
+//go:build darwin || linux || freebsd
+
+package quic
+
+import (
+ "encoding/binary"
+ "errors"
+ "log"
+ "net"
+ "net/netip"
+ "os"
+ "strconv"
+ "sync"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/net/ipv4"
+ "golang.org/x/net/ipv6"
+ "golang.org/x/sys/unix"
+
+ "github.com/quic-go/quic-go/internal/monotime"
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+)
+
+const (
+ ecnMask = 0x3
+ oobBufferSize = 128
+)
+
+// Contrary to what the naming suggests, the ipv{4,6}.Message is not dependent on the IP version.
+// They're both just aliases for x/net/internal/socket.Message.
+// This means we can use this struct to read from a socket that receives both IPv4 and IPv6 messages.
+var _ ipv4.Message = ipv6.Message{}
+
+type batchConn interface {
+ ReadBatch(ms []ipv4.Message, flags int) (int, error)
+}
+
+func inspectReadBuffer(c syscall.RawConn) (int, error) {
+ var size int
+ var serr error
+ if err := c.Control(func(fd uintptr) {
+ size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF)
+ }); err != nil {
+ return 0, err
+ }
+ return size, serr
+}
+
+func inspectWriteBuffer(c syscall.RawConn) (int, error) {
+ var size int
+ var serr error
+ if err := c.Control(func(fd uintptr) {
+ size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF)
+ }); err != nil {
+ return 0, err
+ }
+ return size, serr
+}
+
+func isECNDisabledUsingEnv() bool {
+ disabled, err := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_ECN"))
+ return err == nil && disabled
+}
+
+type oobConn struct {
+ OOBCapablePacketConn
+ batchConn batchConn
+
+ readPos uint8
+ // Packets received from the kernel, but not yet returned by ReadPacket().
+ messages []ipv4.Message
+ buffers [batchSize]*packetBuffer
+
+ cap connCapabilities
+}
+
+var _ rawConn = &oobConn{}
+
+func newConn(c OOBCapablePacketConn, supportsDF bool) (*oobConn, error) {
+ rawConn, err := c.SyscallConn()
+ if err != nil {
+ return nil, err
+ }
+ var needsPacketInfo bool
+ if udpAddr, ok := c.LocalAddr().(*net.UDPAddr); ok && udpAddr.IP.IsUnspecified() {
+ needsPacketInfo = true
+ }
+ // We don't know if this a IPv4-only, IPv6-only or a IPv4-and-IPv6 connection.
+ // Try enabling receiving of ECN and packet info for both IP versions.
+ // We expect at least one of those syscalls to succeed.
+ var errECNIPv4, errECNIPv6, errPIIPv4, errPIIPv6 error
+ if err := rawConn.Control(func(fd uintptr) {
+ errECNIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_RECVTOS, 1)
+ errECNIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVTCLASS, 1)
+
+ if needsPacketInfo {
+ errPIIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, ipv4PKTINFO, 1)
+ errPIIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVPKTINFO, 1)
+ }
+ }); err != nil {
+ return nil, err
+ }
+ switch {
+ case errECNIPv4 == nil && errECNIPv6 == nil:
+ utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv4 and IPv6.")
+ case errECNIPv4 == nil && errECNIPv6 != nil:
+ utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv4.")
+ case errECNIPv4 != nil && errECNIPv6 == nil:
+ utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv6.")
+ case errECNIPv4 != nil && errECNIPv6 != nil:
+ return nil, errors.New("activating ECN failed for both IPv4 and IPv6")
+ }
+ if needsPacketInfo {
+ switch {
+ case errPIIPv4 == nil && errPIIPv6 == nil:
+ utils.DefaultLogger.Debugf("Activating reading of packet info for IPv4 and IPv6.")
+ case errPIIPv4 == nil && errPIIPv6 != nil:
+ utils.DefaultLogger.Debugf("Activating reading of packet info bits for IPv4.")
+ case errPIIPv4 != nil && errPIIPv6 == nil:
+ utils.DefaultLogger.Debugf("Activating reading of packet info bits for IPv6.")
+ case errPIIPv4 != nil && errPIIPv6 != nil:
+ return nil, errors.New("activating packet info failed for both IPv4 and IPv6")
+ }
+ }
+
+ // Allows callers to pass in a connection that already satisfies batchConn interface
+ // to make use of the optimisation. Otherwise, ipv4.NewPacketConn would unwrap the file descriptor
+ // via SyscallConn(), and read it that way, which might not be what the caller wants.
+ var bc batchConn
+ if ibc, ok := c.(batchConn); ok {
+ bc = ibc
+ } else {
+ bc = ipv4.NewPacketConn(c)
+ }
+
+ msgs := make([]ipv4.Message, batchSize)
+ for i := range msgs {
+ // preallocate the [][]byte
+ msgs[i].Buffers = make([][]byte, 1)
+ }
+ oobConn := &oobConn{
+ OOBCapablePacketConn: c,
+ batchConn: bc,
+ messages: msgs,
+ readPos: batchSize,
+ cap: connCapabilities{
+ DF: supportsDF,
+ GSO: isGSOEnabled(rawConn),
+ ECN: isECNEnabled(),
+ },
+ }
+ for i := range batchSize {
+ oobConn.messages[i].OOB = make([]byte, oobBufferSize)
+ }
+ return oobConn, nil
+}
+
+var invalidCmsgOnceV4, invalidCmsgOnceV6 sync.Once
+
+func (c *oobConn) ReadPacket() (receivedPacket, error) {
+ if len(c.messages) == int(c.readPos) { // all messages read. Read the next batch of messages.
+ c.messages = c.messages[:batchSize]
+ // replace buffers data buffers up to the packet that has been consumed during the last ReadBatch call
+ for i := uint8(0); i < c.readPos; i++ {
+ buffer := getPacketBuffer()
+ buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
+ c.buffers[i] = buffer
+ c.messages[i].Buffers[0] = c.buffers[i].Data
+ }
+ c.readPos = 0
+
+ n, err := c.batchConn.ReadBatch(c.messages, 0)
+ if n == 0 || err != nil {
+ return receivedPacket{}, err
+ }
+ c.messages = c.messages[:n]
+ }
+
+ msg := c.messages[c.readPos]
+ buffer := c.buffers[c.readPos]
+ c.readPos++
+
+ data := msg.OOB[:msg.NN]
+ p := receivedPacket{
+ remoteAddr: msg.Addr,
+ rcvTime: monotime.Now(),
+ data: msg.Buffers[0][:msg.N],
+ buffer: buffer,
+ }
+ for len(data) > 0 {
+ hdr, body, remainder, err := unix.ParseOneSocketControlMessage(data)
+ if err != nil {
+ return receivedPacket{}, err
+ }
+ if hdr.Level == unix.IPPROTO_IP {
+ switch hdr.Type {
+ case msgTypeIPTOS:
+ if len(body) != 1 {
+ return receivedPacket{}, errors.New("invalid IPTOS size")
+ }
+ p.ecn = protocol.ParseECNHeaderBits(body[0] & ecnMask)
+ case ipv4PKTINFO:
+ ip, ifIndex, ok := parseIPv4PktInfo(body)
+ if ok {
+ p.info.addr = ip
+ p.info.ifIndex = ifIndex
+ } else {
+ invalidCmsgOnceV4.Do(func() {
+ log.Printf("Received invalid IPv4 packet info control message: %+x. "+
+ "This should never occur, please open a new issue and include details about the architecture.", body)
+ })
+ }
+ }
+ }
+ if hdr.Level == unix.IPPROTO_IPV6 {
+ switch hdr.Type {
+ case unix.IPV6_TCLASS:
+ if len(body) != 4 {
+ return receivedPacket{}, errors.New("invalid IPV6_TCLASS size")
+ }
+ bits := uint8(binary.NativeEndian.Uint32(body)) & ecnMask
+ p.ecn = protocol.ParseECNHeaderBits(bits)
+ case unix.IPV6_PKTINFO:
+ // struct in6_pktinfo {
+ // struct in6_addr ipi6_addr; /* src/dst IPv6 address */
+ // unsigned int ipi6_ifindex; /* send/recv interface index */
+ // };
+ if len(body) == 20 {
+ p.info.addr = netip.AddrFrom16(*(*[16]byte)(body[:16])).Unmap()
+ p.info.ifIndex = binary.NativeEndian.Uint32(body[16:])
+ } else {
+ invalidCmsgOnceV6.Do(func() {
+ log.Printf("Received invalid IPv6 packet info control message: %+x. "+
+ "This should never occur, please open a new issue and include details about the architecture.", body)
+ })
+ }
+ }
+ }
+ data = remainder
+ }
+ return p, nil
+}
+
+// WritePacket writes a new packet.
+func (c *oobConn) WritePacket(b []byte, addr net.Addr, packetInfoOOB []byte, gsoSize uint16, ecn protocol.ECN) (int, error) {
+ oob := packetInfoOOB
+ if gsoSize > 0 {
+ if !c.capabilities().GSO {
+ panic("GSO disabled")
+ }
+ oob = appendUDPSegmentSizeMsg(oob, gsoSize)
+ }
+ if ecn != protocol.ECNUnsupported {
+ if !c.capabilities().ECN {
+ panic("tried to send an ECN-marked packet although ECN is disabled")
+ }
+ if remoteUDPAddr, ok := addr.(*net.UDPAddr); ok {
+ if remoteUDPAddr.IP.To4() != nil {
+ oob = appendIPv4ECNMsg(oob, ecn)
+ } else {
+ oob = appendIPv6ECNMsg(oob, ecn)
+ }
+ }
+ }
+ n, _, err := c.WriteMsgUDP(b, oob, addr.(*net.UDPAddr))
+ return n, err
+}
+
+func (c *oobConn) capabilities() connCapabilities {
+ return c.cap
+}
+
+type packetInfo struct {
+ addr netip.Addr
+ ifIndex uint32
+}
+
+func (info *packetInfo) OOB() []byte {
+ if info == nil {
+ return nil
+ }
+ if info.addr.Is4() {
+ ip := info.addr.As4()
+ // struct in_pktinfo {
+ // unsigned int ipi_ifindex; /* Interface index */
+ // struct in_addr ipi_spec_dst; /* Local address */
+ // struct in_addr ipi_addr; /* Header Destination address */
+ // };
+ cm := ipv4.ControlMessage{
+ Src: ip[:],
+ IfIndex: int(info.ifIndex),
+ }
+ return cm.Marshal()
+ } else if info.addr.Is6() {
+ ip := info.addr.As16()
+ // struct in6_pktinfo {
+ // struct in6_addr ipi6_addr; /* src/dst IPv6 address */
+ // unsigned int ipi6_ifindex; /* send/recv interface index */
+ // };
+ cm := ipv6.ControlMessage{
+ Src: ip[:],
+ IfIndex: int(info.ifIndex),
+ }
+ return cm.Marshal()
+ }
+ return nil
+}
+
+func appendIPv4ECNMsg(b []byte, val protocol.ECN) []byte {
+ startLen := len(b)
+ b = append(b, make([]byte, unix.CmsgSpace(ecnIPv4DataLen))...)
+ h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen]))
+ h.Level = syscall.IPPROTO_IP
+ h.Type = unix.IP_TOS
+ h.SetLen(unix.CmsgLen(ecnIPv4DataLen))
+
+ // UnixRights uses the private `data` method, but I *think* this achieves the same goal.
+ offset := startLen + unix.CmsgSpace(0)
+ b[offset] = val.ToHeaderBits()
+ return b
+}
+
+func appendIPv6ECNMsg(b []byte, val protocol.ECN) []byte {
+ startLen := len(b)
+ const dataLen = 4
+ b = append(b, make([]byte, unix.CmsgSpace(dataLen))...)
+ h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen]))
+ h.Level = syscall.IPPROTO_IPV6
+ h.Type = unix.IPV6_TCLASS
+ h.SetLen(unix.CmsgLen(dataLen))
+
+ // UnixRights uses the private `data` method, but I *think* this achieves the same goal.
+ offset := startLen + unix.CmsgSpace(0)
+ binary.NativeEndian.PutUint32(b[offset:offset+dataLen], uint32(val.ToHeaderBits()))
+ return b
+}
diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_windows.go b/vendor/github.com/quic-go/quic-go/sys_conn_windows.go
new file mode 100644
index 00000000..b9c1cbc8
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/sys_conn_windows.go
@@ -0,0 +1,42 @@
+//go:build windows
+
+package quic
+
+import (
+ "net/netip"
+ "syscall"
+
+ "golang.org/x/sys/windows"
+)
+
+func newConn(c OOBCapablePacketConn, supportsDF bool) (*basicConn, error) {
+ return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
+}
+
+func inspectReadBuffer(c syscall.RawConn) (int, error) {
+ var size int
+ var serr error
+ if err := c.Control(func(fd uintptr) {
+ size, serr = windows.GetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_RCVBUF)
+ }); err != nil {
+ return 0, err
+ }
+ return size, serr
+}
+
+func inspectWriteBuffer(c syscall.RawConn) (int, error) {
+ var size int
+ var serr error
+ if err := c.Control(func(fd uintptr) {
+ size, serr = windows.GetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_SNDBUF)
+ }); err != nil {
+ return 0, err
+ }
+ return size, serr
+}
+
+type packetInfo struct {
+ addr netip.Addr
+}
+
+func (i *packetInfo) OOB() []byte { return nil }
diff --git a/vendor/github.com/quic-go/quic-go/token_store.go b/vendor/github.com/quic-go/quic-go/token_store.go
new file mode 100644
index 00000000..a5c1c185
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/token_store.go
@@ -0,0 +1,116 @@
+package quic
+
+import (
+ "sync"
+
+ list "github.com/quic-go/quic-go/internal/utils/linkedlist"
+)
+
+type singleOriginTokenStore struct {
+ tokens []*ClientToken
+ len int
+ p int
+}
+
+func newSingleOriginTokenStore(size int) *singleOriginTokenStore {
+ return &singleOriginTokenStore{tokens: make([]*ClientToken, size)}
+}
+
+func (s *singleOriginTokenStore) Add(token *ClientToken) {
+ s.tokens[s.p] = token
+ s.p = s.index(s.p + 1)
+ s.len = min(s.len+1, len(s.tokens))
+}
+
+func (s *singleOriginTokenStore) Pop() *ClientToken {
+ s.p = s.index(s.p - 1)
+ token := s.tokens[s.p]
+ s.tokens[s.p] = nil
+ s.len = max(s.len-1, 0)
+ return token
+}
+
+func (s *singleOriginTokenStore) Len() int {
+ return s.len
+}
+
+func (s *singleOriginTokenStore) index(i int) int {
+ mod := len(s.tokens)
+ return (i + mod) % mod
+}
+
+type lruTokenStoreEntry struct {
+ key string
+ cache *singleOriginTokenStore
+}
+
+type lruTokenStore struct {
+ mutex sync.Mutex
+
+ m map[string]*list.Element[*lruTokenStoreEntry]
+ q *list.List[*lruTokenStoreEntry]
+ capacity int
+ singleOriginSize int
+}
+
+var _ TokenStore = &lruTokenStore{}
+
+// NewLRUTokenStore creates a new LRU cache for tokens received by the client.
+// maxOrigins specifies how many origins this cache is saving tokens for.
+// tokensPerOrigin specifies the maximum number of tokens per origin.
+func NewLRUTokenStore(maxOrigins, tokensPerOrigin int) TokenStore {
+ return &lruTokenStore{
+ m: make(map[string]*list.Element[*lruTokenStoreEntry]),
+ q: list.New[*lruTokenStoreEntry](),
+ capacity: maxOrigins,
+ singleOriginSize: tokensPerOrigin,
+ }
+}
+
+func (s *lruTokenStore) Put(key string, token *ClientToken) {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ if el, ok := s.m[key]; ok {
+ entry := el.Value
+ entry.cache.Add(token)
+ s.q.MoveToFront(el)
+ return
+ }
+
+ if s.q.Len() < s.capacity {
+ entry := &lruTokenStoreEntry{
+ key: key,
+ cache: newSingleOriginTokenStore(s.singleOriginSize),
+ }
+ entry.cache.Add(token)
+ s.m[key] = s.q.PushFront(entry)
+ return
+ }
+
+ elem := s.q.Back()
+ entry := elem.Value
+ delete(s.m, entry.key)
+ entry.key = key
+ entry.cache = newSingleOriginTokenStore(s.singleOriginSize)
+ entry.cache.Add(token)
+ s.q.MoveToFront(elem)
+ s.m[key] = elem
+}
+
+func (s *lruTokenStore) Pop(key string) *ClientToken {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ var token *ClientToken
+ if el, ok := s.m[key]; ok {
+ s.q.MoveToFront(el)
+ cache := el.Value.cache
+ token = cache.Pop()
+ if cache.Len() == 0 {
+ s.q.Remove(el)
+ delete(s.m, key)
+ }
+ }
+ return token
+}
diff --git a/vendor/github.com/quic-go/quic-go/transport.go b/vendor/github.com/quic-go/quic-go/transport.go
new file mode 100644
index 00000000..e597c3f4
--- /dev/null
+++ b/vendor/github.com/quic-go/quic-go/transport.go
@@ -0,0 +1,848 @@
+package quic
+
+import (
+ "context"
+ "crypto/rand"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "net"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/quic-go/quic-go/internal/protocol"
+ "github.com/quic-go/quic-go/internal/utils"
+ "github.com/quic-go/quic-go/internal/wire"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
+)
+
+// ErrTransportClosed is returned by the [Transport]'s Listen or Dial method after it was closed.
+var ErrTransportClosed = &errTransportClosed{}
+
+type errTransportClosed struct {
+ err error
+}
+
+func (e *errTransportClosed) Unwrap() []error { return []error{net.ErrClosed, e.err} }
+
+func (e *errTransportClosed) Error() string {
+ if e.err == nil {
+ return "quic: transport closed"
+ }
+ return fmt.Sprintf("quic: transport closed: %s", e.err)
+}
+
+func (e *errTransportClosed) Is(target error) bool {
+ _, ok := target.(*errTransportClosed)
+ return ok
+}
+
+var errListenerAlreadySet = errors.New("listener already set")
+
+type closePacket struct {
+ payload []byte
+ addr net.Addr
+ info packetInfo
+}
+
+// The Transport is the central point to manage incoming and outgoing QUIC connections.
+// QUIC demultiplexes connections based on their QUIC Connection IDs, not based on the 4-tuple.
+// This means that a single UDP socket can be used for listening for incoming connections, as well as
+// for dialing an arbitrary number of outgoing connections.
+// A Transport handles a single net.PacketConn, and offers a range of configuration options
+// compared to the simple helper functions like [Listen] and [Dial] that this package provides.
+type Transport struct {
+ // A single net.PacketConn can only be handled by one Transport.
+ // Bad things will happen if passed to multiple Transports.
+ //
+ // A number of optimizations will be enabled if the connections implements the OOBCapablePacketConn interface,
+ // as a *net.UDPConn does.
+ // 1. It enables the Don't Fragment (DF) bit on the IP header.
+ // This is required to run DPLPMTUD (Path MTU Discovery, RFC 8899).
+ // 2. It enables reading of the ECN bits from the IP header.
+ // This allows the remote node to speed up its loss detection and recovery.
+ // 3. It uses batched syscalls (recvmmsg) to more efficiently receive packets from the socket.
+ // 4. It uses Generic Segmentation Offload (GSO) to efficiently send batches of packets (on Linux).
+ //
+ // After passing the connection to the Transport, it's invalid to call ReadFrom or WriteTo on the connection.
+ Conn net.PacketConn
+
+ // The length of the connection ID in bytes.
+ // It can be any value between 1 and 20.
+ // Due to the increased risk of collisions, it is not recommended to use connection IDs shorter than 4 bytes.
+ // If unset, a 4 byte connection ID will be used.
+ ConnectionIDLength int
+
+ // Use for generating new connection IDs.
+ // This allows the application to control of the connection IDs used,
+ // which allows routing / load balancing based on connection IDs.
+ // All Connection IDs returned by the ConnectionIDGenerator MUST
+ // have the same length.
+ ConnectionIDGenerator ConnectionIDGenerator
+
+ // The StatelessResetKey is used to generate stateless reset tokens.
+ // If no key is configured, sending of stateless resets is disabled.
+ // It is highly recommended to configure a stateless reset key, as stateless resets
+ // allow the peer to quickly recover from crashes and reboots of this node.
+ // See section 10.3 of RFC 9000 for details.
+ StatelessResetKey *StatelessResetKey
+
+ // The TokenGeneratorKey is used to encrypt session resumption tokens.
+ // If no key is configured, a random key will be generated.
+ // If multiple servers are authoritative for the same domain, they should use the same key,
+ // see section 8.1.3 of RFC 9000 for details.
+ TokenGeneratorKey *TokenGeneratorKey
+
+ // MaxTokenAge is the maximum age of the resumption token presented during the handshake.
+ // These tokens allow skipping address resumption when resuming a QUIC connection,
+ // and are especially useful when using 0-RTT.
+ // If not set, it defaults to 24 hours.
+ // See section 8.1.3 of RFC 9000 for details.
+ MaxTokenAge time.Duration
+
+ // DisableVersionNegotiationPackets disables the sending of Version Negotiation packets.
+ // This can be useful if version information is exchanged out-of-band.
+ // It has no effect for clients.
+ DisableVersionNegotiationPackets bool
+
+ // VerifySourceAddress decides if a connection attempt originating from unvalidated source
+ // addresses first needs to go through source address validation using QUIC's Retry mechanism,
+ // as described in RFC 9000 section 8.1.2.
+ // Note that the address passed to this callback is unvalidated, and might be spoofed in case
+ // of an attack.
+ // Validating the source address adds one additional network roundtrip to the handshake,
+ // and should therefore only be used if a suspiciously high number of incoming connection is recorded.
+ // For most use cases, wrapping the Allow function of a rate.Limiter will be a reasonable
+ // implementation of this callback (negating its return value).
+ VerifySourceAddress func(net.Addr) bool
+
+ // ConnContext is called when the server accepts a new connection. To reject a connection return
+ // a non-nil error.
+ // The context is closed when the connection is closed, or when the handshake fails for any reason.
+ // The context returned from the callback is used to derive every other context used during the
+ // lifetime of the connection:
+ // * the context passed to crypto/tls (and used on the tls.ClientHelloInfo)
+ // * the context used in Config.QlogTrace
+ // * the context returned from Conn.Context
+ // * the context returned from SendStream.Context
+ // It is not used for dialed connections.
+ ConnContext func(context.Context, *ClientInfo) (context.Context, error)
+
+ // A Tracer traces events that don't belong to a single QUIC connection.
+ // Recorder.Close is called when the transport is closed.
+ Tracer qlogwriter.Recorder
+
+ mutex sync.Mutex
+ handlers map[protocol.ConnectionID]packetHandler
+ resetTokens map[protocol.StatelessResetToken]packetHandler
+
+ initOnce sync.Once
+ initErr error
+
+ // If no ConnectionIDGenerator is set, this is the ConnectionIDLength.
+ connIDLen int
+ // Set in init.
+ // If no ConnectionIDGenerator is set, this is set to a default.
+ connIDGenerator ConnectionIDGenerator
+ statelessResetter *statelessResetter
+
+ server *baseServer
+
+ conn rawConn
+
+ closeQueue chan closePacket
+ statelessResetQueue chan receivedPacket
+
+ listening chan struct{} // is closed when listen returns
+ closeErr error
+ createdConn bool
+ isSingleUse bool // was created for a single server or client, i.e. by calling quic.Listen or quic.Dial
+
+ readingNonQUICPackets atomic.Bool
+ nonQUICPackets chan receivedPacket
+
+ logger utils.Logger
+}
+
+// Listen starts listening for incoming QUIC connections.
+// There can only be a single listener on any net.PacketConn.
+// Listen may only be called again after the current listener was closed.
+func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) {
+ s, err := t.createServer(tlsConf, conf, false)
+ if err != nil {
+ return nil, err
+ }
+ return &Listener{baseServer: s}, nil
+}
+
+// ListenEarly starts listening for incoming QUIC connections.
+// There can only be a single listener on any net.PacketConn.
+// ListenEarly may only be called again after the current listener was closed.
+func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListener, error) {
+ s, err := t.createServer(tlsConf, conf, true)
+ if err != nil {
+ return nil, err
+ }
+ return &EarlyListener{baseServer: s}, nil
+}
+
+func (t *Transport) createServer(tlsConf *tls.Config, conf *Config, allow0RTT bool) (*baseServer, error) {
+ if tlsConf == nil {
+ return nil, errors.New("quic: tls.Config not set")
+ }
+ if err := validateConfig(conf); err != nil {
+ return nil, err
+ }
+
+ t.mutex.Lock()
+ defer t.mutex.Unlock()
+
+ if t.closeErr != nil {
+ return nil, t.closeErr
+ }
+ if t.server != nil {
+ return nil, errListenerAlreadySet
+ }
+ conf = populateConfig(conf)
+ if err := t.init(false); err != nil {
+ return nil, err
+ }
+ maxTokenAge := t.MaxTokenAge
+ if maxTokenAge == 0 {
+ maxTokenAge = 24 * time.Hour
+ }
+ s := newServer(
+ t.conn,
+ (*packetHandlerMap)(t),
+ t.connIDGenerator,
+ t.statelessResetter,
+ t.ConnContext,
+ tlsConf,
+ conf,
+ t.Tracer,
+ t.closeServer,
+ *t.TokenGeneratorKey,
+ maxTokenAge,
+ t.VerifySourceAddress,
+ t.DisableVersionNegotiationPackets,
+ allow0RTT,
+ )
+ t.server = s
+ return s, nil
+}
+
+// Dial dials a new connection to a remote host (not using 0-RTT).
+func (t *Transport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) {
+ return t.dial(ctx, addr, "", tlsConf, conf, false)
+}
+
+// DialEarly dials a new connection, attempting to use 0-RTT if possible.
+func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (*Conn, error) {
+ return t.dial(ctx, addr, "", tlsConf, conf, true)
+}
+
+func (t *Transport) dial(ctx context.Context, addr net.Addr, host string, tlsConf *tls.Config, conf *Config, use0RTT bool) (*Conn, error) {
+ if err := t.init(t.isSingleUse); err != nil {
+ return nil, err
+ }
+ if err := validateConfig(conf); err != nil {
+ return nil, err
+ }
+ conf = populateConfig(conf)
+ tlsConf = tlsConf.Clone()
+ setTLSConfigServerName(tlsConf, addr, host)
+ return t.doDial(ctx,
+ newSendConn(t.conn, addr, packetInfo{}, utils.DefaultLogger),
+ tlsConf,
+ conf,
+ 0,
+ false,
+ use0RTT,
+ conf.Versions[0],
+ )
+}
+
+func (t *Transport) doDial(
+ ctx context.Context,
+ sendConn sendConn,
+ tlsConf *tls.Config,
+ config *Config,
+ initialPacketNumber protocol.PacketNumber,
+ hasNegotiatedVersion bool,
+ use0RTT bool,
+ version protocol.Version,
+) (*Conn, error) {
+ srcConnID, err := t.connIDGenerator.GenerateConnectionID()
+ if err != nil {
+ return nil, err
+ }
+ destConnID, err := generateConnectionIDForInitial()
+ if err != nil {
+ return nil, err
+ }
+
+ t.mutex.Lock()
+ if t.closeErr != nil {
+ t.mutex.Unlock()
+ return nil, t.closeErr
+ }
+
+ var qlogTrace qlogwriter.Trace
+ if config.Tracer != nil {
+ qlogTrace = config.Tracer(ctx, true, destConnID)
+ }
+
+ logger := utils.DefaultLogger.WithPrefix("client")
+ logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", tlsConf.ServerName, sendConn.LocalAddr(), sendConn.RemoteAddr(), srcConnID, destConnID, version)
+
+ conn := newClientConnection(
+ context.WithoutCancel(ctx),
+ sendConn,
+ (*packetHandlerMap)(t),
+ destConnID,
+ srcConnID,
+ t.connIDGenerator,
+ t.statelessResetter,
+ config,
+ tlsConf,
+ initialPacketNumber,
+ use0RTT,
+ hasNegotiatedVersion,
+ qlogTrace,
+ logger,
+ version,
+ )
+ t.handlers[srcConnID] = conn
+ t.mutex.Unlock()
+
+ // The error channel needs to be buffered, as the run loop will continue running
+ // after doDial returns (if the handshake is successful).
+ // Similarly, the recreateChan needs to be buffered; in case a different case is selected.
+ errChan := make(chan error, 1)
+ recreateChan := make(chan errCloseForRecreating, 1)
+ go func() {
+ err := conn.run()
+ var recreateErr *errCloseForRecreating
+ if errors.As(err, &recreateErr) {
+ recreateChan <- *recreateErr
+ return
+ }
+ if t.isSingleUse {
+ t.Close()
+ }
+ errChan <- err
+ }()
+
+ // Only set when we're using 0-RTT.
+ // Otherwise, earlyConnChan will be nil. Receiving from a nil chan blocks forever.
+ var earlyConnChan <-chan struct{}
+ if use0RTT {
+ earlyConnChan = conn.earlyConnReady()
+ }
+
+ select {
+ case <-ctx.Done():
+ conn.destroy(nil)
+ // wait until the Go routine that called Conn.run() returns
+ select {
+ case <-errChan:
+ case <-recreateChan:
+ }
+ return nil, context.Cause(ctx)
+ case params := <-recreateChan:
+ return t.doDial(ctx,
+ sendConn,
+ tlsConf,
+ config,
+ params.nextPacketNumber,
+ true,
+ use0RTT,
+ params.nextVersion,
+ )
+ case err := <-errChan:
+ return nil, err
+ case <-earlyConnChan:
+ // ready to send 0-RTT data
+ return conn.Conn, nil
+ case <-conn.HandshakeComplete():
+ // handshake successfully completed
+ return conn.Conn, nil
+ }
+}
+
+func (t *Transport) init(allowZeroLengthConnIDs bool) error {
+ t.initOnce.Do(func() {
+ var conn rawConn
+ if c, ok := t.Conn.(rawConn); ok {
+ conn = c
+ } else {
+ var err error
+ conn, err = wrapConn(t.Conn)
+ if err != nil {
+ t.initErr = err
+ return
+ }
+ }
+
+ t.logger = utils.DefaultLogger // TODO: make this configurable
+ t.conn = conn
+ t.handlers = make(map[protocol.ConnectionID]packetHandler)
+ t.resetTokens = make(map[protocol.StatelessResetToken]packetHandler)
+ t.listening = make(chan struct{})
+
+ t.closeQueue = make(chan closePacket, 4)
+ t.statelessResetQueue = make(chan receivedPacket, 4)
+ if t.TokenGeneratorKey == nil {
+ var key TokenGeneratorKey
+ if _, err := rand.Read(key[:]); err != nil {
+ t.initErr = err
+ return
+ }
+ t.TokenGeneratorKey = &key
+ }
+
+ if t.ConnectionIDGenerator != nil {
+ t.connIDGenerator = t.ConnectionIDGenerator
+ t.connIDLen = t.ConnectionIDGenerator.ConnectionIDLen()
+ } else {
+ connIDLen := t.ConnectionIDLength
+ if t.ConnectionIDLength == 0 && !allowZeroLengthConnIDs {
+ connIDLen = protocol.DefaultConnectionIDLength
+ }
+ t.connIDLen = connIDLen
+ t.connIDGenerator = &protocol.DefaultConnectionIDGenerator{ConnLen: t.connIDLen}
+ }
+ t.statelessResetter = newStatelessResetter(t.StatelessResetKey)
+
+ go func() {
+ defer close(t.listening)
+ t.listen(conn)
+
+ if t.createdConn {
+ conn.Close()
+ }
+ }()
+ go t.runSendQueue()
+ })
+ return t.initErr
+}
+
+// WriteTo sends a packet on the underlying connection.
+func (t *Transport) WriteTo(b []byte, addr net.Addr) (int, error) {
+ if err := t.init(false); err != nil {
+ return 0, err
+ }
+ return t.conn.WritePacket(b, addr, nil, 0, protocol.ECNUnsupported)
+}
+
+func (t *Transport) runSendQueue() {
+ for {
+ select {
+ case <-t.listening:
+ return
+ case p := <-t.closeQueue:
+ t.conn.WritePacket(p.payload, p.addr, p.info.OOB(), 0, protocol.ECNUnsupported)
+ case p := <-t.statelessResetQueue:
+ t.sendStatelessReset(p)
+ }
+ }
+}
+
+// Close stops listening for UDP datagrams on the Transport.Conn.
+// It abruptly terminates all existing connections, without sending a CONNECTION_CLOSE
+// to the peers. It is the application's responsibility to cleanly terminate existing
+// connections prior to calling Close.
+//
+// If a server was started, it will be closed as well.
+// It is not possible to start any new server or dial new connections after that.
+func (t *Transport) Close() error {
+ // avoid race condition if the transport is currently being initialized
+ t.init(false)
+
+ t.close(nil)
+ if t.createdConn {
+ if err := t.Conn.Close(); err != nil {
+ return err
+ }
+ } else if t.conn != nil {
+ t.conn.SetReadDeadline(time.Now())
+ defer func() { t.conn.SetReadDeadline(time.Time{}) }()
+ }
+ if t.listening != nil {
+ <-t.listening // wait until listening returns
+ }
+ return nil
+}
+
+func (t *Transport) closeServer() {
+ t.mutex.Lock()
+ defer t.mutex.Unlock()
+
+ t.server = nil
+ if t.isSingleUse {
+ t.closeErr = ErrServerClosed
+ }
+
+ if len(t.handlers) == 0 {
+ t.maybeStopListening()
+ }
+}
+
+func (t *Transport) close(e error) {
+ t.mutex.Lock()
+
+ if t.closeErr != nil {
+ t.mutex.Unlock()
+ return
+ }
+
+ e = &errTransportClosed{err: e}
+ t.closeErr = e
+ server := t.server
+ t.server = nil
+ if server != nil {
+ t.mutex.Unlock()
+ server.close(e, true)
+ t.mutex.Lock()
+ }
+
+ // Close existing connections
+ var wg sync.WaitGroup
+ for _, handler := range t.handlers {
+ wg.Go(func() { handler.destroy(e) })
+ }
+ t.mutex.Unlock() // closing connections requires releasing transport mutex
+ wg.Wait()
+
+ if t.Tracer != nil {
+ t.Tracer.Close()
+ }
+}
+
+// only print warnings about the UDP receive buffer size once
+var setBufferWarningOnce sync.Once
+
+func (t *Transport) listen(conn rawConn) {
+ for {
+ p, err := conn.ReadPacket()
+ //nolint:staticcheck // SA1019 ignore this!
+ // TODO: This code is used to ignore wsa errors on Windows.
+ // Since net.Error.Temporary is deprecated as of Go 1.18, we should find a better solution.
+ // See https://github.com/quic-go/quic-go/issues/1737 for details.
+ if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
+ t.mutex.Lock()
+ closed := t.closeErr != nil
+ t.mutex.Unlock()
+ if closed {
+ return
+ }
+ t.logger.Debugf("Temporary error reading from conn: %w", err)
+ continue
+ }
+ if err != nil {
+ // Windows returns an error when receiving a UDP datagram that doesn't fit into the provided buffer.
+ if isRecvMsgSizeErr(err) {
+ continue
+ }
+ t.close(err)
+ return
+ }
+ t.handlePacket(p)
+ }
+}
+
+func (t *Transport) maybeStopListening() {
+ if t.isSingleUse && t.closeErr != nil {
+ t.conn.SetReadDeadline(time.Now())
+ }
+}
+
+func (t *Transport) handlePacket(p receivedPacket) {
+ if len(p.data) == 0 {
+ return
+ }
+ if !wire.IsPotentialQUICPacket(p.data[0]) && !wire.IsLongHeaderPacket(p.data[0]) {
+ t.handleNonQUICPacket(p)
+ return
+ }
+ connID, err := wire.ParseConnectionID(p.data, t.connIDLen)
+ if err != nil {
+ t.logger.Debugf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err)
+ if t.Tracer != nil {
+ t.Tracer.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
+ }
+ p.buffer.MaybeRelease()
+ return
+ }
+
+ // If there's a connection associated with the connection ID, pass the packet there.
+ if handler, ok := (*packetHandlerMap)(t).Get(connID); ok {
+ handler.handlePacket(p)
+ return
+ }
+ // RFC 9000 section 10.3.1 requires that the stateless reset detection logic is run for both
+ // packets that cannot be associated with any connections, and for packets that can't be decrypted.
+ // We deviate from the RFC and ignore the latter: If a packet's connection ID is associated with an
+ // existing connection, it is dropped there if if it can't be decrypted.
+ // Stateless resets use random connection IDs, and at reasonable connection ID lengths collisions are
+ // exceedingly rare. In the unlikely event that a stateless reset is misrouted to an existing connection,
+ // it is to be expected that the next stateless reset will be correctly detected.
+ if isStatelessReset := t.maybeHandleStatelessReset(p.data); isStatelessReset {
+ return
+ }
+ if !wire.IsLongHeaderPacket(p.data[0]) {
+ if statelessResetQueued := t.maybeSendStatelessReset(p); !statelessResetQueued {
+ if t.Tracer != nil {
+ t.Tracer.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketType1RTT},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnknownConnectionID,
+ })
+ }
+ p.buffer.Release()
+ }
+ return
+ }
+
+ t.mutex.Lock()
+ defer t.mutex.Unlock()
+ if t.server == nil { // no server set
+ t.logger.Debugf("received a packet with an unexpected connection ID %s", connID)
+ if t.Tracer != nil {
+ t.Tracer.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnknownConnectionID,
+ })
+ }
+ p.buffer.MaybeRelease()
+ return
+ }
+ t.server.handlePacket(p)
+}
+
+func (t *Transport) maybeSendStatelessReset(p receivedPacket) (statelessResetQueued bool) {
+ if t.StatelessResetKey == nil {
+ return false
+ }
+
+ // Don't send a stateless reset in response to very small packets.
+ // This includes packets that could be stateless resets.
+ if len(p.data) <= protocol.MinStatelessResetSize {
+ return false
+ }
+
+ select {
+ case t.statelessResetQueue <- p:
+ return true
+ default:
+ // it's fine to not send a stateless reset when we're busy
+ return false
+ }
+}
+
+func (t *Transport) sendStatelessReset(p receivedPacket) {
+ defer p.buffer.Release()
+
+ connID, err := wire.ParseConnectionID(p.data, t.connIDLen)
+ if err != nil {
+ t.logger.Errorf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err)
+ return
+ }
+ token := t.statelessResetter.GetStatelessResetToken(connID)
+ t.logger.Debugf("Sending stateless reset to %s (connection ID: %s). Token: %#x", p.remoteAddr, connID, token)
+ data := make([]byte, protocol.MinStatelessResetSize-16, protocol.MinStatelessResetSize)
+ rand.Read(data)
+ data[0] = (data[0] & 0x7f) | 0x40
+ data = append(data, token[:]...)
+ if _, err := t.conn.WritePacket(data, p.remoteAddr, p.info.OOB(), 0, protocol.ECNUnsupported); err != nil {
+ t.logger.Debugf("Error sending Stateless Reset to %s: %s", p.remoteAddr, err)
+ }
+}
+
+func (t *Transport) maybeHandleStatelessReset(data []byte) bool {
+ // stateless resets are always short header packets
+ if wire.IsLongHeaderPacket(data[0]) {
+ return false
+ }
+ if len(data) < 17 /* type byte + 16 bytes for the reset token */ {
+ return false
+ }
+
+ token := protocol.StatelessResetToken(data[len(data)-16:])
+ t.mutex.Lock()
+ conn, ok := t.resetTokens[token]
+ t.mutex.Unlock()
+
+ if ok {
+ t.logger.Debugf("Received a stateless reset with token %#x. Closing connection.", token)
+ go conn.destroy(&StatelessResetError{})
+ return true
+ }
+ return false
+}
+
+func (t *Transport) handleNonQUICPacket(p receivedPacket) {
+ // Strictly speaking, this is racy,
+ // but we only care about receiving packets at some point after ReadNonQUICPacket has been called.
+ if !t.readingNonQUICPackets.Load() {
+ return
+ }
+ select {
+ case t.nonQUICPackets <- p:
+ default:
+ if t.Tracer != nil {
+ t.Tracer.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
+ }
+ }
+}
+
+const maxQueuedNonQUICPackets = 32
+
+// ReadNonQUICPacket reads non-QUIC packets received on the underlying connection.
+// The detection logic is very simple: Any packet that has the first and second bit of the packet set to 0.
+// Note that this is stricter than the detection logic defined in RFC 9443.
+func (t *Transport) ReadNonQUICPacket(ctx context.Context, b []byte) (int, net.Addr, error) {
+ if err := t.init(false); err != nil {
+ return 0, nil, err
+ }
+ if !t.readingNonQUICPackets.Load() {
+ t.nonQUICPackets = make(chan receivedPacket, maxQueuedNonQUICPackets)
+ t.readingNonQUICPackets.Store(true)
+ }
+ select {
+ case <-ctx.Done():
+ return 0, nil, ctx.Err()
+ case p := <-t.nonQUICPackets:
+ n := copy(b, p.data)
+ return n, p.remoteAddr, nil
+ case <-t.listening:
+ return 0, nil, errors.New("closed")
+ }
+}
+
+func setTLSConfigServerName(tlsConf *tls.Config, addr net.Addr, host string) {
+ // If no ServerName is set, infer the ServerName from the host we're connecting to.
+ if tlsConf.ServerName != "" {
+ return
+ }
+ if host == "" {
+ if udpAddr, ok := addr.(*net.UDPAddr); ok {
+ tlsConf.ServerName = udpAddr.IP.String()
+ return
+ }
+ }
+ h, _, err := net.SplitHostPort(host)
+ if err != nil { // This happens if the host doesn't contain a port number.
+ tlsConf.ServerName = host
+ return
+ }
+ tlsConf.ServerName = h
+}
+
+type packetHandlerMap Transport
+
+var _ connRunner = &packetHandlerMap{}
+
+func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) bool /* was added */ {
+ h.mutex.Lock()
+ defer h.mutex.Unlock()
+
+ if _, ok := h.handlers[id]; ok {
+ h.logger.Debugf("Not adding connection ID %s, as it already exists.", id)
+ return false
+ }
+ h.handlers[id] = handler
+ h.logger.Debugf("Adding connection ID %s.", id)
+ return true
+}
+
+func (h *packetHandlerMap) Get(connID protocol.ConnectionID) (packetHandler, bool) {
+ h.mutex.Lock()
+ defer h.mutex.Unlock()
+ handler, ok := h.handlers[connID]
+ return handler, ok
+}
+
+func (h *packetHandlerMap) AddResetToken(token protocol.StatelessResetToken, handler packetHandler) {
+ h.mutex.Lock()
+ h.resetTokens[token] = handler
+ h.mutex.Unlock()
+}
+
+func (h *packetHandlerMap) RemoveResetToken(token protocol.StatelessResetToken) {
+ h.mutex.Lock()
+ delete(h.resetTokens, token)
+ h.mutex.Unlock()
+}
+
+func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.ConnectionID, handler packetHandler) bool {
+ h.mutex.Lock()
+ defer h.mutex.Unlock()
+
+ if _, ok := h.handlers[clientDestConnID]; ok {
+ h.logger.Debugf("Not adding connection ID %s for a new connection, as it already exists.", clientDestConnID)
+ return false
+ }
+ h.handlers[clientDestConnID] = handler
+ h.handlers[newConnID] = handler
+ h.logger.Debugf("Adding connection IDs %s and %s for a new connection.", clientDestConnID, newConnID)
+ return true
+}
+
+func (h *packetHandlerMap) Remove(id protocol.ConnectionID) {
+ h.mutex.Lock()
+ delete(h.handlers, id)
+ h.mutex.Unlock()
+ h.logger.Debugf("Removing connection ID %s.", id)
+}
+
+// ReplaceWithClosed is called when a connection is closed.
+// Depending on which side closed the connection, we need to:
+// * remote close: absorb delayed packets
+// * local close: retransmit the CONNECTION_CLOSE packet, in case it was lost
+func (h *packetHandlerMap) ReplaceWithClosed(ids []protocol.ConnectionID, connClosePacket []byte, expiry time.Duration) {
+ var handler packetHandler
+ if connClosePacket != nil {
+ handler = newClosedLocalConn(
+ func(addr net.Addr, info packetInfo) {
+ select {
+ case h.closeQueue <- closePacket{payload: connClosePacket, addr: addr, info: info}:
+ default:
+ // We're backlogged.
+ // Just drop the packet, sending CONNECTION_CLOSE copies is best effort anyway.
+ }
+ },
+ h.logger,
+ )
+ } else {
+ handler = newClosedRemoteConn()
+ }
+
+ h.mutex.Lock()
+ for _, id := range ids {
+ h.handlers[id] = handler
+ }
+ h.mutex.Unlock()
+ h.logger.Debugf("Replacing connection for connection IDs %s with a closed connection.", ids)
+
+ time.AfterFunc(expiry, func() {
+ h.mutex.Lock()
+ for _, id := range ids {
+ delete(h.handlers, id)
+ }
+ if len(h.handlers) == 0 {
+ t := (*Transport)(h)
+ t.maybeStopListening()
+ }
+ h.mutex.Unlock()
+ h.logger.Debugf("Removing connection IDs %s for a closed connection after it has been retired.", ids)
+ })
+}
diff --git a/vendor/github.com/refraction-networking/utls/.travis.yml b/vendor/github.com/refraction-networking/utls/.travis.yml
new file mode 100644
index 00000000..00697254
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/.travis.yml
@@ -0,0 +1,19 @@
+language: go
+
+go:
+ - "1.11.x"
+
+sudo: required
+dist: trusty
+
+install:
+ - go get -t ./...
+ - go get golang.org/x/lint/golint
+ # Install gometalinter
+ - go get github.com/alecthomas/gometalinter
+
+script:
+ - go test -race -v .
+ - gometalinter --install
+ - gometalinter --disable-all -E vet -E ineffassign --tests .
+ - gometalinter --disable-all -E gofmt -E misspell -E goimports --tests u_*
diff --git a/vendor/github.com/refraction-networking/utls/CONTRIBUTING.md b/vendor/github.com/refraction-networking/utls/CONTRIBUTING.md
new file mode 100644
index 00000000..6d364e1d
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution,
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
\ No newline at end of file
diff --git a/vendor/github.com/refraction-networking/utls/CONTRIBUTORS_GUIDE.md b/vendor/github.com/refraction-networking/utls/CONTRIBUTORS_GUIDE.md
new file mode 100644
index 00000000..7dcfb2d7
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/CONTRIBUTORS_GUIDE.md
@@ -0,0 +1,69 @@
+# How this package works
+### Chapter 1: [Making private things public](./u_public.go)
+There are numerous handshake-related structs in crypto/tls, most of which are either private or have private fields.
+One of them — `clientHandshakeState` — has private function `handshake()`,
+which is called in the beginning of default handshake.
+Unfortunately, user will not be able to directly access this struct outside of tls package.
+As a result, we decided to employ following workaround: declare public copies of private structs.
+Now user is free to manipulate fields of public `ClientHandshakeState`.
+Then, right before handshake, we can shallow-copy public state into private `clientHandshakeState`,
+call `handshake()` on it and carry on with default Golang handshake process.
+After handshake is done we shallow-copy private state back to public, allowing user to read results of handshake.
+
+### Chapter 2: [TLSExtension](./u_tls_extensions.go)
+The way we achieve reasonable flexibilty with extensions is inspired by
+[ztls'](https://github.com/zmap/zcrypto/blob/master/tls/handshake_extensions.go) design.
+However, our design has several differences, so we wrote it from scratch.
+This design allows us to have an array of `TLSExtension` objects and then marshal them in order:
+```Golang
+type TLSExtension interface {
+ writeToUConn(*UConn) error
+
+ Len() int // includes header
+
+ // Read reads up to len(p) bytes into p.
+ // It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
+ Read(p []byte) (n int, err error) // implements io.Reader
+}
+```
+`writeToUConn()` applies appropriate per-extension changes to `UConn`.
+
+`Len()` provides the size of marshaled extension, so we can allocate appropriate buffer beforehand,
+catch out-of-bound errors easily and guide size-dependent extensions such as padding.
+
+`Read(buffer []byte)` _writes(see: io.Reader interface)_ marshaled extensions into provided buffer.
+This avoids extra allocations.
+
+### Chapter 3: [UConn](./u_conn.go)
+`UConn` extends standard `tls.Conn`. Most notably, it stores slice with `TLSExtension`s and public
+`ClientHandshakeState`.
+Whenever `UConn.BuildHandshakeState()` gets called (happens automatically in `UConn.Handshake()`
+or could be called manually), config will be applied according to chosen `ClientHelloID`.
+From contributor's view there are 2 main behaviors:
+ * `HelloGolang` simply calls default Golang's [`makeClientHello()`](./handshake_client.go)
+ and directly stores it into `HandshakeState.Hello`. utls-specific stuff is ignored.
+ * Other ClientHelloIDs fill `UConn.Hello.{Random, CipherSuites, CompressionMethods}` and `UConn.Extensions` with
+per-parrot setup, which then gets applied to appropriate standard tls structs,
+and then marshaled by utls into `HandshakeState.Hello`.
+
+### Chapter 4: Tests
+
+Tests exist, but coverage is very limited. What's covered is a conjunction of
+ * TLS 1.2
+ * Working parrots without any unsupported extensions (only Android 5.1 at this time)
+ * Ciphersuites offered by parrot.
+ * Ciphersuites supported by Golang
+ * Simple conversation with reference implementation of OpenSSL.
+(e.g. no automatic checks for renegotiations, parroting quality and such)
+
+plus we test some other minor things.
+Basically, current tests aim to provide a sanity check.
+
+# Merging upstream
+```Bash
+git remote add -f golang git@github.com:golang/go.git
+git checkout -b golang-upstream golang/master
+git subtree split -P src/crypto/tls/ -b golang-tls-upstream
+git checkout master
+git merge --no-commit golang-tls-upstream
+```
diff --git a/vendor/github.com/refraction-networking/utls/LICENSE b/vendor/github.com/refraction-networking/utls/LICENSE
new file mode 100644
index 00000000..6a66aea5
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/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/github.com/refraction-networking/utls/README.md b/vendor/github.com/refraction-networking/utls/README.md
new file mode 100644
index 00000000..0309ef90
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/README.md
@@ -0,0 +1,315 @@
+#  uTLS
+[](https://github.com/refraction-networking/utls/actions/workflows/go.yml)
+[](https://godoc.org/github.com/refraction-networking/utls#UConn)
+---
+uTLS is a fork of "crypto/tls", which provides ClientHello fingerprinting resistance, low-level access to handshake, fake session tickets and some other features. Handshake is still performed by "crypto/tls", this library merely changes ClientHello part of it and provides low-level access.
+
+**Minimum Go Version**: Go 1.21
+
+If you have any questions, bug reports or contributions, you are welcome to publish those on GitHub. If you want to do so in private, ~~you can contact one of developers personally via sergey.frolov@colorado.edu~~.
+
+You can contact one of developers personally via gaukas.wang@colorado.edu.
+
+Documentation below may not keep up with all the changes and new features at all times,
+so you are encouraged to use [godoc](https://godoc.org/github.com/refraction-networking/utls#UConn).
+
+*Note: Information provided below in this README.md could be obsolete. We welcome
+any contributions to refresh the documentations in addition to code contributions.*
+
+# Features
+## Low-level access to handshake
+* Read/write access to all bits of client hello message.
+* Read access to fields of ClientHandshakeState, which, among other things, includes ServerHello and MasterSecret.
+* Read keystream. Can be used, for example, to "write" something in ciphertext.
+
+## ClientHello fingerprinting resistance
+Golang's ClientHello has a very unique fingerprint, which especially sticks out on mobile clients,
+where Golang is not too popular yet.
+Some members of anti-censorship community are concerned that their tools could be trivially blocked based on
+ClientHello with relatively small collateral damage. There are multiple solutions to this issue.
+
+**It is highly recommended to use multiple fingeprints, including randomized ones to avoid relying on a single fingerprint.**
+[utls.Roller](#roller) does this automatically.
+
+### Randomized Fingerprint
+Randomized Fingerprints are supposedly good at defeating blacklists, since
+those fingerprints have random ciphersuites and extensions in random order.
+Note that all used ciphersuites and extensions are fully supported by uTLS,
+which provides a solid moving target without any compatibility or parrot-is-dead attack risks.
+
+But note that there's a small chance that generated fingerprint won't work,
+so you may want to keep generating until a working one is found,
+and then keep reusing the working fingerprint to avoid suspicious behavior of constantly changing fingerprints.
+[utls.Roller](#roller) reuses working fingerprint automatically.
+
+#### Generating randomized fingerprints
+
+To generate a randomized fingerprint, simply do:
+```Golang
+uTlsConn := tls.UClient(tcpConn, &config, tls.HelloRandomized)
+```
+you can use `helloRandomizedALPN` or `helloRandomizedNoALPN` to ensure presence or absence of
+ALPN(Application-Layer Protocol Negotiation) extension.
+It is recommended, but certainly not required to include ALPN (or use helloRandomized which may or may not include ALPN).
+If you do use ALPN, you will want to correctly handle potential application layer protocols (likely h2 or http/1.1).
+
+#### Reusing randomized fingerprint
+```Golang
+// oldConn is an old connection that worked before, so we want to reuse it
+// newConn is a new connection we'd like to establish
+newConn := tls.UClient(tcpConn, &config, oldConn.ClientHelloID)
+```
+
+### Parroting
+This package can be used to parrot ClientHello of popular browsers.
+There are some caveats to this parroting:
+* We are forced to offer ciphersuites and tls extensions that are not supported by crypto/tls.
+This is not a problem, if you fully control the server and turn unsupported things off on server side.
+* Parroting could be imperfect, and there is no parroting beyond ClientHello.
+#### Compatibility risks of available parrots
+
+| Parrot | Ciphers* | Signature* | Unsupported extensions | TLS Fingerprint ID |
+| ------------- | -------- | ---------- | ---------------------- | --------------------------------------------- |
+| Chrome 62 | no | no | ChannelID | [0a4a74aeebd1bb66](https://tlsfingerprint.io/id/0a4a74aeebd1bb66) |
+| Chrome 70 | no | no | ChannelID, Encrypted Certs | [bc4c7e42f4961cd7](https://tlsfingerprint.io/id/bc4c7e42f4961cd7) |
+| Chrome 72 | no | no | ChannelID, Encrypted Certs | [bbf04e5f1881f506](https://tlsfingerprint.io/id/bbf04e5f1881f506) |
+| Chrome 83 | no | no | ChannelID, Encrypted Certs | [9c673fd64a32c8dc](https://tlsfingerprint.io/id/9c673fd64a32c8dc) |
+| Firefox 56 | very low | no | None | [c884bad7f40bee56](https://tlsfingerprint.io/id/c884bad7f40bee56) |
+| Firefox 65 | very low | no | MaxRecordSize | [6bfedc5d5c740d58](https://tlsfingerprint.io/id/6bfedc5d5c740d58) |
+| iOS 11.1 | low** | no | None | [71a81bafd58e1301](https://tlsfingerprint.io/id/71a81bafd58e1301) |
+| iOS 12.1 | low** | no | None | [ec55e5b4136c7949](https://tlsfingerprint.io/id/ec55e5b4136c7949) |
+
+\* Denotes very rough guesstimate of likelihood that unsupported things will get echoed back by the server in the wild,
+*visibly breaking the connection*.
+\*\* No risk, if `utls.EnableWeakCiphers()` is called prior to using it.
+
+#### Parrots FAQ
+> Does it really look like, say, Google Chrome with all the [GREASE](https://tools.ietf.org/html/draft-davidben-tls-grease-01) and stuff?
+
+It LGTM, but please open up Wireshark and check. If you see something — [say something](https://github.com/refraction-networking/utls/issues).
+
+> Aren't there side channels? Everybody knows that the ~~bird is a word~~[parrot is dead](https://people.cs.umass.edu/~amir/papers/parrot.pdf)
+
+There sure are. If you found one that approaches practicality at line speed — [please tell us](https://github.com/refraction-networking/utls/issues).
+
+However, there is a difference between this sort of parroting and techniques like SkypeMorth.
+Namely, TLS is highly standardized protocol, therefore simply not that many subtle things in TLS protocol
+could be different and/or suddenly change in one of mimicked implementation(potentially undermining the mimicry).
+It is possible that we have a distinguisher right now, but amount of those potential distinguishers is limited.
+
+### Custom Handshake
+It is possible to create custom handshake by
+1) Use `HelloCustom` as an argument for `UClient()` to get empty config
+2) Fill tls header fields: UConn.Hello.{Random, CipherSuites, CompressionMethods}, if needed, or stick to defaults.
+3) Configure and add various [TLS Extensions](u_tls_extensions.go) to UConn.Extensions: they will be marshaled in order.
+4) Set Session and SessionCache, as needed.
+
+If you need to manually control all the bytes on the wire(certainly not recommended!),
+you can set UConn.HandshakeStateBuilt = true, and marshal clientHello into UConn.HandshakeState.Hello.raw yourself.
+In this case you will be responsible for modifying other parts of Config and ClientHelloMsg to reflect your setup
+and not confuse "crypto/tls", which will be processing response from server.
+
+### Fingerprinting Captured Client Hello
+You can use a captured client hello to generate new ones that mimic/have the same properties as the original.
+The generated client hellos _should_ look like they were generated from the same client software as the original fingerprinted bytes.
+In order to do this:
+1) Create a `ClientHelloSpec` from the raw bytes of the original client hello
+2) Use `HelloCustom` as an argument for `UClient()` to get empty config
+3) Use `ApplyPreset` with the generated `ClientHelloSpec` to set the appropriate connection properties
+```
+uConn := UClient(&net.TCPConn{}, nil, HelloCustom)
+fingerprinter := &Fingerprinter{}
+generatedSpec, err := fingerprinter.FingerprintClientHello(rawCapturedClientHelloBytes)
+if err != nil {
+ panic("fingerprinting failed: %v", err)
+}
+if err := uConn.ApplyPreset(generatedSpec); err != nil {
+ panic("applying generated spec failed: %v", err)
+}
+```
+The `rawCapturedClientHelloBytes` should be the full tls record, including the record type/version/length header.
+
+## Roller
+
+A simple wrapper, that allows to easily use multiple latest(auto-updated) fingerprints.
+
+```Golang
+// NewRoller creates Roller object with default range of HelloIDs to cycle
+// through until a working/unblocked one is found.
+func NewRoller() (*Roller, error)
+```
+
+```Golang
+// Dial attempts to connect to given address using different HelloIDs.
+// If a working HelloID is found, it is used again for subsequent Dials.
+// If tcp connection fails or all HelloIDs are tried, returns with last error.
+//
+// Usage examples:
+//
+// Dial("tcp4", "google.com:443", "google.com")
+// Dial("tcp", "10.23.144.22:443", "mywebserver.org")
+func (c *Roller) Dial(network, addr, serverName string) (*UConn, error)
+```
+
+## Fake Session Tickets
+Fake session tickets is a very nifty trick that allows power users to hide parts of handshake, which may have some very fingerprintable features of handshake, and saves 1 RTT.
+Currently, there is a simple function to set session ticket to any desired state:
+
+```Golang
+// If you want you session tickets to be reused - use same cache on following connections
+func (uconn *UConn) SetSessionState(session *ClientSessionState)
+```
+
+Note that session tickets (fake ones or otherwise) are not reused.
+To reuse tickets, create a shared cache and set it on current and further configs:
+
+```Golang
+// If you want you session tickets to be reused - use same cache on following connections
+func (uconn *UConn) SetSessionCache(cache ClientSessionCache)
+```
+
+## Custom TLS extensions
+If you want to add your own fake (placeholder, without added functionality) extension for mimicry purposes, you can embed `*tls.GenericExtension` into your own struct and override `Len()` and `Read()` methods. For example, [DelegatedCredentials](https://datatracker.ietf.org/doc/draft-ietf-tls-subcerts/) extension can be implemented as follows:
+
+```Golang
+const FakeDelegatedCredentials uint16 = 0x0022
+
+type FakeDelegatedCredentialsExtension struct {
+ *tls.GenericExtension
+ SignatureAlgorithms []tls.SignatureScheme
+}
+
+func (e *FakeDelegatedCredentialsExtension) Len() int {
+ return 6 + 2*len(e.SignatureAlgorithms)
+}
+
+func (e *FakeDelegatedCredentialsExtension) Read(b []byte) (n int, err error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ offset := 0
+ appendUint16 := func(val uint16) {
+ b[offset] = byte(val >> 8)
+ b[offset+1] = byte(val & 0xff)
+ offset += 2
+ }
+
+ // Extension type
+ appendUint16(FakeDelegatedCredentials)
+
+ algosLength := 2 * len(e.SignatureAlgorithms)
+
+ // Extension data length
+ appendUint16(uint16(algosLength) + 2)
+
+ // Algorithms list length
+ appendUint16(uint16(algosLength))
+
+ // Algorithms list
+ for _, a := range e.SignatureAlgorithms {
+ appendUint16(uint16(a))
+ }
+ return e.Len(), io.EOF
+}
+```
+
+Then it can be used just like normal extension:
+
+```Golang
+&tls.ClientHelloSpec{
+ //...
+ Extensions: []tls.TLSExtension{
+ //...
+ &FakeDelegatedCredentialsExtension{
+ SignatureAlgorithms: []tls.SignatureScheme{
+ tls.ECDSAWithP256AndSHA256,
+ tls.ECDSAWithP384AndSHA384,
+ tls.ECDSAWithP521AndSHA512,
+ tls.ECDSAWithSHA1,
+ },
+ },
+ //...
+ }
+ //...
+}
+```
+
+# Client Hello IDs
+See full list of `clientHelloID` values [here](https://godoc.org/github.com/refraction-networking/utls#ClientHelloID).
+There are different behaviors you can get, depending on your `clientHelloID`:
+
+1. ```utls.HelloRandomized``` adds/reorders extensions, ciphersuites, etc. randomly.
+`HelloRandomized` adds ALPN in a percentage of cases, you may want to use `HelloRandomizedALPN` or
+`HelloRandomizedNoALPN` to choose specific behavior explicitly, as ALPN might affect application layer.
+2. ```utls.HelloGolang```
+ HelloGolang will use default "crypto/tls" handshake marshaling codepath, which WILL
+ overwrite your changes to Hello(Config, Session are fine).
+ You might want to call BuildHandshakeState() before applying any changes.
+ UConn.Extensions will be completely ignored.
+3. ```utls.HelloCustom```
+will prepare ClientHello with empty uconn.Extensions so you can fill it with TLSExtension's manually.
+4. The rest will will parrot given browser. Such parrots include, for example:
+ * `utls.HelloChrome_Auto`- parrots recommended(usually latest) Google Chrome version
+ * `utls.HelloChrome_58` - parrots Google Chrome 58
+ * `utls.HelloFirefox_Auto` - parrots recommended(usually latest) Firefox version
+ * `utls.HelloFirefox_55` - parrots Firefox 55
+
+# Usage
+## Examples
+Find basic examples [here](examples/examples.go).
+Here's a more [advanced example](https://github.com/sergeyfrolov/gotapdance/blob//9a777f35a04b0c4c5dacd30bca0e9224eb737b5e/tapdance/conn_raw.go#L275-L292) showing how to generate randomized ClientHello, modify generated ciphersuites a bit, and proceed with the handshake.
+### Migrating from "crypto/tls"
+Here's how default "crypto/tls" is typically used:
+```Golang
+ dialConn, err := net.Dial("tcp", "172.217.11.46:443")
+ if err != nil {
+ fmt.Printf("net.Dial() failed: %+v\n", err)
+ return
+ }
+
+ config := tls.Config{ServerName: "www.google.com"}
+ tlsConn := tls.Client(dialConn, &config)
+ n, err = tlsConn.Write("Hello, World!")
+ //...
+```
+To start using using uTLS:
+1. Import this library (e.g. `import tls "github.com/refraction-networking/utls"`)
+2. Pick the [Client Hello ID](#client-hello-ids)
+3. Simply substitute `tlsConn := tls.Client(dialConn, &config)`
+with `tlsConn := tls.UClient(dialConn, &config, tls.clientHelloID)`
+
+### Customizing handshake
+Some customizations(such as setting session ticket/clientHello) have easy-to-use functions for them. The idea is to make common manipulations easy:
+```Golang
+ cRandom := []byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131}
+ tlsConn.SetClientRandom(cRandom)
+ masterSecret := make([]byte, 48)
+ copy(masterSecret, []byte("masterSecret is NOT sent over the wire")) // you may use it for real security
+
+ // Create a session ticket that wasn't actually issued by the server.
+ sessionState := utls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12),
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ masterSecret,
+ nil, nil)
+ tlsConn.SetSessionState(sessionState)
+```
+
+For other customizations there are following functions
+```
+// you can use this to build the state manually and change it
+// for example use Randomized ClientHello, and add more extensions
+func (uconn *UConn) BuildHandshakeState() error
+```
+```
+// Then apply the changes and marshal final bytes, which will be sent
+func (uconn *UConn) MarshalClientHello() error
+```
+
+## Contributors' guide
+Please refer to [this document](./CONTRIBUTORS_GUIDE.md) if you're interested in internals
+
+## Credits
+The initial development of uTLS was completed during an internship at [Google Jigsaw](https://jigsaw.google.com/). This is not an official Google product.
diff --git a/vendor/github.com/refraction-networking/utls/SECURITY.md b/vendor/github.com/refraction-networking/utls/SECURITY.md
new file mode 100644
index 00000000..14a54815
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/SECURITY.md
@@ -0,0 +1,11 @@
+# Security Policy
+
+## Supported Versions
+
+We will only maintain one branch which is the master branch. Unless otherwise requested, no security patches will be applied to older Major/Minor versions.
+
+## Reporting a Vulnerability
+
+For a vulnerability of low to no severity, which causing no threats to security, you may report it openly to us by [opening an issue](https://github.com/refraction-networking/utls/issues/new)
+
+If the vulnerability you are reporting inflicts some security impact, please [do so privately](https://github.com/refraction-networking/utls/security/advisories/new).
diff --git a/vendor/github.com/refraction-networking/utls/alert.go b/vendor/github.com/refraction-networking/utls/alert.go
new file mode 100644
index 00000000..2301c067
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/alert.go
@@ -0,0 +1,111 @@
+// 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 tls
+
+import "strconv"
+
+// An AlertError is a TLS alert.
+//
+// When using a QUIC transport, QUICConn methods will return an error
+// which wraps AlertError rather than sending a TLS alert.
+type AlertError uint8
+
+func (e AlertError) Error() string {
+ return alert(e).String()
+}
+
+type alert uint8
+
+const (
+ // alert level
+ alertLevelWarning = 1
+ alertLevelError = 2
+)
+
+const (
+ alertCloseNotify alert = 0
+ alertUnexpectedMessage alert = 10
+ alertBadRecordMAC alert = 20
+ alertDecryptionFailed alert = 21
+ alertRecordOverflow alert = 22
+ alertDecompressionFailure alert = 30
+ alertHandshakeFailure alert = 40
+ alertBadCertificate alert = 42
+ alertUnsupportedCertificate alert = 43
+ alertCertificateRevoked alert = 44
+ alertCertificateExpired alert = 45
+ alertCertificateUnknown alert = 46
+ alertIllegalParameter alert = 47
+ alertUnknownCA alert = 48
+ alertAccessDenied alert = 49
+ alertDecodeError alert = 50
+ alertDecryptError alert = 51
+ alertExportRestriction alert = 60
+ alertProtocolVersion alert = 70
+ alertInsufficientSecurity alert = 71
+ alertInternalError alert = 80
+ alertInappropriateFallback alert = 86
+ alertUserCanceled alert = 90
+ alertNoRenegotiation alert = 100
+ alertMissingExtension alert = 109
+ alertUnsupportedExtension alert = 110
+ alertCertificateUnobtainable alert = 111
+ alertUnrecognizedName alert = 112
+ alertBadCertificateStatusResponse alert = 113
+ alertBadCertificateHashValue alert = 114
+ alertUnknownPSKIdentity alert = 115
+ alertCertificateRequired alert = 116
+ alertNoApplicationProtocol alert = 120
+ alertECHRequired alert = 121
+)
+
+var alertText = map[alert]string{
+ alertCloseNotify: "close notify",
+ alertUnexpectedMessage: "unexpected message",
+ alertBadRecordMAC: "bad record MAC",
+ alertDecryptionFailed: "decryption failed",
+ alertRecordOverflow: "record overflow",
+ alertDecompressionFailure: "decompression failure",
+ alertHandshakeFailure: "handshake failure",
+ alertBadCertificate: "bad certificate",
+ alertUnsupportedCertificate: "unsupported certificate",
+ alertCertificateRevoked: "revoked certificate",
+ alertCertificateExpired: "expired certificate",
+ alertCertificateUnknown: "unknown certificate",
+ alertIllegalParameter: "illegal parameter",
+ alertUnknownCA: "unknown certificate authority",
+ alertAccessDenied: "access denied",
+ alertDecodeError: "error decoding message",
+ alertDecryptError: "error decrypting message",
+ alertExportRestriction: "export restriction",
+ alertProtocolVersion: "protocol version not supported",
+ alertInsufficientSecurity: "insufficient security level",
+ alertInternalError: "internal error",
+ alertInappropriateFallback: "inappropriate fallback",
+ alertUserCanceled: "user canceled",
+ alertNoRenegotiation: "no renegotiation",
+ alertMissingExtension: "missing extension",
+ alertUnsupportedExtension: "unsupported extension",
+ alertCertificateUnobtainable: "certificate unobtainable",
+ alertUnrecognizedName: "unrecognized name",
+ alertBadCertificateStatusResponse: "bad certificate status response",
+ alertBadCertificateHashValue: "bad certificate hash value",
+ alertUnknownPSKIdentity: "unknown PSK identity",
+ alertCertificateRequired: "certificate required",
+ alertNoApplicationProtocol: "no application protocol",
+ alertECHRequired: "encrypted client hello required",
+}
+
+func (e alert) String() string {
+ s, ok := alertText[e]
+ if ok {
+ return "tls: " + s
+ }
+ return "tls: alert(" + strconv.Itoa(int(e)) + ")"
+}
+
+func (e alert) Error() string {
+ return e.String()
+}
diff --git a/vendor/github.com/refraction-networking/utls/auth.go b/vendor/github.com/refraction-networking/utls/auth.go
new file mode 100644
index 00000000..998deb9b
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/auth.go
@@ -0,0 +1,295 @@
+// 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.
+
+package tls
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+)
+
+// verifyHandshakeSignature verifies a signature against pre-hashed
+// (if required) handshake contents.
+func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error {
+ switch sigType {
+ case signatureECDSA:
+ pubKey, ok := pubkey.(*ecdsa.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an ECDSA public key, got %T", pubkey)
+ }
+ if !ecdsa.VerifyASN1(pubKey, signed, sig) {
+ return errors.New("ECDSA verification failure")
+ }
+ case signatureEd25519:
+ pubKey, ok := pubkey.(ed25519.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey)
+ }
+ if !ed25519.Verify(pubKey, signed, sig) {
+ return errors.New("Ed25519 verification failure")
+ }
+ case signaturePKCS1v15:
+ pubKey, ok := pubkey.(*rsa.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an RSA public key, got %T", pubkey)
+ }
+ if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil {
+ return err
+ }
+ case signatureRSAPSS:
+ pubKey, ok := pubkey.(*rsa.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an RSA public key, got %T", pubkey)
+ }
+ signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
+ if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil {
+ return err
+ }
+ default:
+ return errors.New("internal error: unknown signature type")
+ }
+ return nil
+}
+
+const (
+ serverSignatureContext = "TLS 1.3, server CertificateVerify\x00"
+ clientSignatureContext = "TLS 1.3, client CertificateVerify\x00"
+)
+
+var signaturePadding = []byte{
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+}
+
+// signedMessage returns the pre-hashed (if necessary) message to be signed by
+// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3.
+func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte {
+ if sigHash == directSigning {
+ b := &bytes.Buffer{}
+ b.Write(signaturePadding)
+ io.WriteString(b, context)
+ b.Write(transcript.Sum(nil))
+ return b.Bytes()
+ }
+ h := sigHash.New()
+ h.Write(signaturePadding)
+ io.WriteString(h, context)
+ h.Write(transcript.Sum(nil))
+ return h.Sum(nil)
+}
+
+// typeAndHashFromSignatureScheme returns the corresponding signature type and
+// crypto.Hash for a given TLS SignatureScheme.
+func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) {
+ switch signatureAlgorithm {
+ case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
+ sigType = signaturePKCS1v15
+ case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
+ sigType = signatureRSAPSS
+ case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
+ sigType = signatureECDSA
+ case Ed25519:
+ sigType = signatureEd25519
+ default:
+ return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+ }
+ switch signatureAlgorithm {
+ case PKCS1WithSHA1, ECDSAWithSHA1:
+ hash = crypto.SHA1
+ case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
+ hash = crypto.SHA256
+ case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
+ hash = crypto.SHA384
+ case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
+ hash = crypto.SHA512
+ case Ed25519:
+ hash = directSigning
+ default:
+ return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+ }
+ return sigType, hash, nil
+}
+
+// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for
+// a given public key used with TLS 1.0 and 1.1, before the introduction of
+// signature algorithm negotiation.
+func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) {
+ switch pub.(type) {
+ case *rsa.PublicKey:
+ return signaturePKCS1v15, crypto.MD5SHA1, nil
+ case *ecdsa.PublicKey:
+ return signatureECDSA, crypto.SHA1, nil
+ case ed25519.PublicKey:
+ // RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1,
+ // but it requires holding on to a handshake transcript to do a
+ // full signature, and not even OpenSSL bothers with the
+ // complexity, so we can't even test it properly.
+ return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2")
+ default:
+ return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub)
+ }
+}
+
+var rsaSignatureSchemes = []struct {
+ scheme SignatureScheme
+ minModulusBytes int
+ maxVersion uint16
+}{
+ // RSA-PSS is used with PSSSaltLengthEqualsHash, and requires
+ // emLen >= hLen + sLen + 2
+ {PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13},
+ {PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13},
+ {PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13},
+ // PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires
+ // emLen >= len(prefix) + hLen + 11
+ // TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS.
+ {PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12},
+ {PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12},
+ {PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12},
+ {PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12},
+}
+
+// signatureSchemesForCertificate returns the list of supported SignatureSchemes
+// for a given certificate, based on the public key and the protocol version,
+// and optionally filtered by its explicit SupportedSignatureAlgorithms.
+//
+// This function must be kept in sync with supportedSignatureAlgorithms.
+// FIPS filtering is applied in the caller, selectSignatureScheme.
+func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
+ priv, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return nil
+ }
+
+ var sigAlgs []SignatureScheme
+ switch pub := priv.Public().(type) {
+ case *ecdsa.PublicKey:
+ if version != VersionTLS13 {
+ // In TLS 1.2 and earlier, ECDSA algorithms are not
+ // constrained to a single curve.
+ sigAlgs = []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ ECDSAWithSHA1,
+ }
+ break
+ }
+ switch pub.Curve {
+ case elliptic.P256():
+ sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
+ case elliptic.P384():
+ sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
+ case elliptic.P521():
+ sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
+ default:
+ return nil
+ }
+ case *rsa.PublicKey:
+ size := pub.Size()
+ sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes))
+ for _, candidate := range rsaSignatureSchemes {
+ if size >= candidate.minModulusBytes && version <= candidate.maxVersion {
+ sigAlgs = append(sigAlgs, candidate.scheme)
+ }
+ }
+ case ed25519.PublicKey:
+ sigAlgs = []SignatureScheme{Ed25519}
+ default:
+ return nil
+ }
+
+ if cert.SupportedSignatureAlgorithms != nil {
+ var filteredSigAlgs []SignatureScheme
+ for _, sigAlg := range sigAlgs {
+ if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) {
+ filteredSigAlgs = append(filteredSigAlgs, sigAlg)
+ }
+ }
+ return filteredSigAlgs
+ }
+ return sigAlgs
+}
+
+// selectSignatureScheme picks a SignatureScheme from the peer's preference list
+// that works with the selected certificate. It's only called for protocol
+// versions that support signature algorithms, so TLS 1.2 and 1.3.
+func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
+ supportedAlgs := signatureSchemesForCertificate(vers, c)
+ if len(supportedAlgs) == 0 {
+ return 0, unsupportedCertificateError(c)
+ }
+ if len(peerAlgs) == 0 && vers == VersionTLS12 {
+ // For TLS 1.2, if the client didn't send signature_algorithms then we
+ // can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
+ peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1}
+ }
+ // Pick signature scheme in the peer's preference order, as our
+ // preference order is not configurable.
+ for _, preferredAlg := range peerAlgs {
+ // [uTLS] SECTION BEGIN
+ // if fips140tls.Required() && !isSupportedSignatureAlgorithm(preferredAlg, defaultSupportedSignatureAlgorithmsFIPS) {
+ // continue
+ // }
+ // [uTLS] SECTION END
+ if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
+ return preferredAlg, nil
+ }
+ }
+ return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms")
+}
+
+// unsupportedCertificateError returns a helpful error for certificates with
+// an unsupported private key.
+func unsupportedCertificateError(cert *Certificate) error {
+ switch cert.PrivateKey.(type) {
+ case rsa.PrivateKey, ecdsa.PrivateKey:
+ return fmt.Errorf("tls: unsupported certificate: private key is %T, expected *%T",
+ cert.PrivateKey, cert.PrivateKey)
+ case *ed25519.PrivateKey:
+ return fmt.Errorf("tls: unsupported certificate: private key is *ed25519.PrivateKey, expected ed25519.PrivateKey")
+ }
+
+ signer, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return fmt.Errorf("tls: certificate private key (%T) does not implement crypto.Signer",
+ cert.PrivateKey)
+ }
+
+ switch pub := signer.Public().(type) {
+ case *ecdsa.PublicKey:
+ switch pub.Curve {
+ case elliptic.P256():
+ case elliptic.P384():
+ case elliptic.P521():
+ default:
+ return fmt.Errorf("tls: unsupported certificate curve (%s)", pub.Curve.Params().Name)
+ }
+ case *rsa.PublicKey:
+ return fmt.Errorf("tls: certificate RSA key size too small for supported signature algorithms")
+ case ed25519.PublicKey:
+ default:
+ return fmt.Errorf("tls: unsupported certificate key (%T)", pub)
+ }
+
+ if cert.SupportedSignatureAlgorithms != nil {
+ return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms")
+ }
+
+ return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey)
+}
diff --git a/vendor/github.com/refraction-networking/utls/cache.go b/vendor/github.com/refraction-networking/utls/cache.go
new file mode 100644
index 00000000..a7677611
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/cache.go
@@ -0,0 +1,95 @@
+// 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.
+
+package tls
+
+import (
+ "crypto/x509"
+ "runtime"
+ "sync"
+ "sync/atomic"
+)
+
+type cacheEntry struct {
+ refs atomic.Int64
+ cert *x509.Certificate
+}
+
+// certCache implements an intern table for reference counted x509.Certificates,
+// implemented in a similar fashion to BoringSSL's CRYPTO_BUFFER_POOL. This
+// allows for a single x509.Certificate to be kept in memory and referenced from
+// multiple Conns. Returned references should not be mutated by callers. Certificates
+// are still safe to use after they are removed from the cache.
+//
+// Certificates are returned wrapped in an activeCert struct that should be held by
+// the caller. When references to the activeCert are freed, the number of references
+// to the certificate in the cache is decremented. Once the number of references
+// reaches zero, the entry is evicted from the cache.
+//
+// The main difference between this implementation and CRYPTO_BUFFER_POOL is that
+// CRYPTO_BUFFER_POOL is a more generic structure which supports blobs of data,
+// rather than specific structures. Since we only care about x509.Certificates,
+// certCache is implemented as a specific cache, rather than a generic one.
+//
+// See https://boringssl.googlesource.com/boringssl/+/master/include/openssl/pool.h
+// and https://boringssl.googlesource.com/boringssl/+/master/crypto/pool/pool.c
+// for the BoringSSL reference.
+type certCache struct {
+ sync.Map
+}
+
+var globalCertCache = new(certCache)
+
+// activeCert is a handle to a certificate held in the cache. Once there are
+// no alive activeCerts for a given certificate, the certificate is removed
+// from the cache by a finalizer.
+type activeCert struct {
+ cert *x509.Certificate
+}
+
+// active increments the number of references to the entry, wraps the
+// certificate in the entry in an activeCert, and sets the finalizer.
+//
+// Note that there is a race between active and the finalizer set on the
+// returned activeCert, triggered if active is called after the ref count is
+// decremented such that refs may be > 0 when evict is called. We consider this
+// safe, since the caller holding an activeCert for an entry that is no longer
+// in the cache is fine, with the only side effect being the memory overhead of
+// there being more than one distinct reference to a certificate alive at once.
+func (cc *certCache) active(e *cacheEntry) *activeCert {
+ e.refs.Add(1)
+ a := &activeCert{e.cert}
+ runtime.SetFinalizer(a, func(_ *activeCert) {
+ if e.refs.Add(-1) == 0 {
+ cc.evict(e)
+ }
+ })
+ return a
+}
+
+// evict removes a cacheEntry from the cache.
+func (cc *certCache) evict(e *cacheEntry) {
+ cc.Delete(string(e.cert.Raw))
+}
+
+// newCert returns a x509.Certificate parsed from der. If there is already a copy
+// of the certificate in the cache, a reference to the existing certificate will
+// be returned. Otherwise, a fresh certificate will be added to the cache, and
+// the reference returned. The returned reference should not be mutated.
+func (cc *certCache) newCert(der []byte) (*activeCert, error) {
+ if entry, ok := cc.Load(string(der)); ok {
+ return cc.active(entry.(*cacheEntry)), nil
+ }
+
+ cert, err := x509.ParseCertificate(der)
+ if err != nil {
+ return nil, err
+ }
+
+ entry := &cacheEntry{cert: cert}
+ if entry, loaded := cc.LoadOrStore(string(der), entry); loaded {
+ return cc.active(entry.(*cacheEntry)), nil
+ }
+ return cc.active(entry), nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/cipher_suites.go b/vendor/github.com/refraction-networking/utls/cipher_suites.go
new file mode 100644
index 00000000..5e01f7e8
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/cipher_suites.go
@@ -0,0 +1,725 @@
+// 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 tls
+
+import (
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/hmac"
+ "crypto/rc4"
+ "crypto/sha1"
+ "crypto/sha256"
+ "fmt"
+ "hash"
+ "runtime"
+ _ "unsafe" // for linkname
+
+ "github.com/refraction-networking/utls/internal/boring"
+ "golang.org/x/sys/cpu"
+
+ "golang.org/x/crypto/chacha20poly1305"
+)
+
+// CipherSuite is a TLS cipher suite. Note that most functions in this package
+// accept and expose cipher suite IDs instead of this type.
+type CipherSuite struct {
+ ID uint16
+ Name string
+
+ // Supported versions is the list of TLS protocol versions that can
+ // negotiate this cipher suite.
+ SupportedVersions []uint16
+
+ // Insecure is true if the cipher suite has known security issues
+ // due to its primitives, design, or implementation.
+ Insecure bool
+}
+
+var (
+ supportedUpToTLS12 = []uint16{VersionTLS10, VersionTLS11, VersionTLS12}
+ supportedOnlyTLS12 = []uint16{VersionTLS12}
+ supportedOnlyTLS13 = []uint16{VersionTLS13}
+)
+
+// CipherSuites returns a list of cipher suites currently implemented by this
+// package, excluding those with security issues, which are returned by
+// [InsecureCipherSuites].
+//
+// The list is sorted by ID. Note that the default cipher suites selected by
+// this package might depend on logic that can't be captured by a static list,
+// and might not match those returned by this function.
+func CipherSuites() []*CipherSuite {
+ return []*CipherSuite{
+ {TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", supportedOnlyTLS13, false},
+ {TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", supportedOnlyTLS13, false},
+ {TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", supportedOnlyTLS13, false},
+
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+ {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
+ }
+}
+
+// InsecureCipherSuites returns a list of cipher suites currently implemented by
+// this package and which have security issues.
+//
+// Most applications should not use the cipher suites in this list, and should
+// only use those returned by [CipherSuites].
+func InsecureCipherSuites() []*CipherSuite {
+ // This list includes RC4, CBC_SHA256, and 3DES cipher suites. See
+ // cipherSuitesPreferenceOrder for details.
+ return []*CipherSuite{
+ {TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true},
+ {TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, true},
+ {TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, true},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ {TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, true},
+ {TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, true},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ }
+}
+
+// CipherSuiteName returns the standard name for the passed cipher suite ID
+// (e.g. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), or a fallback representation
+// of the ID value if the cipher suite is not implemented by this package.
+func CipherSuiteName(id uint16) string {
+ for _, c := range CipherSuites() {
+ if c.ID == id {
+ return c.Name
+ }
+ }
+ for _, c := range InsecureCipherSuites() {
+ if c.ID == id {
+ return c.Name
+ }
+ }
+ return fmt.Sprintf("0x%04X", id)
+}
+
+const (
+ // suiteECDHE indicates that the cipher suite involves elliptic curve
+ // Diffie-Hellman. This means that it should only be selected when the
+ // client indicates that it supports ECC with a curve and point format
+ // that we're happy with.
+ suiteECDHE = 1 << iota
+ // suiteECSign indicates that the cipher suite involves an ECDSA or
+ // EdDSA signature and therefore may only be selected when the server's
+ // certificate is ECDSA or EdDSA. If this is not set then the cipher suite
+ // is RSA based.
+ suiteECSign
+ // suiteTLS12 indicates that the cipher suite should only be advertised
+ // and accepted when using TLS 1.2.
+ suiteTLS12
+ // suiteSHA384 indicates that the cipher suite uses SHA384 as the
+ // handshake hash.
+ suiteSHA384
+)
+
+// A cipherSuite is a TLS 1.0–1.2 cipher suite, and defines the key exchange
+// mechanism, as well as the cipher+MAC pair or the AEAD.
+type cipherSuite struct {
+ id uint16
+ // the lengths, in bytes, of the key material needed for each component.
+ keyLen int
+ macLen int
+ ivLen int
+ ka func(version uint16) keyAgreement
+ // flags is a bitmask of the suite* values, above.
+ flags int
+ cipher func(key, iv []byte, isRead bool) any
+ mac func(key []byte) hash.Hash
+ aead func(key, fixedNonce []byte) aead
+}
+
+var cipherSuites = []*cipherSuite{ // TODO: replace with a map, since the order doesn't matter.
+ {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
+ {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+ {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherRC4, macSHA1, nil},
+}
+
+// selectCipherSuite returns the first TLS 1.0–1.2 cipher suite from ids which
+// is also in supportedIDs and passes the ok filter.
+func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite {
+ for _, id := range ids {
+ candidate := cipherSuiteByID(id)
+ if candidate == nil || !ok(candidate) {
+ continue
+ }
+
+ for _, suppID := range supportedIDs {
+ if id == suppID {
+ return candidate
+ }
+ }
+ }
+ return nil
+}
+
+// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash
+// algorithm to be used with HKDF. See RFC 8446, Appendix B.4.
+type cipherSuiteTLS13 struct {
+ id uint16
+ keyLen int
+ aead func(key, fixedNonce []byte) aead
+ hash crypto.Hash
+}
+
+// cipherSuitesTLS13 should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/quic-go/quic-go
+// - github.com/sagernet/quic-go
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname cipherSuitesTLS13
+var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map.
+ {TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256},
+ {TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256},
+ {TLS_AES_256_GCM_SHA384, 32, aeadAESGCMTLS13, crypto.SHA384},
+}
+
+// cipherSuitesPreferenceOrder is the order in which we'll select (on the
+// server) or advertise (on the client) TLS 1.0–1.2 cipher suites.
+//
+// Cipher suites are filtered but not reordered based on the application and
+// peer's preferences, meaning we'll never select a suite lower in this list if
+// any higher one is available. This makes it more defensible to keep weaker
+// cipher suites enabled, especially on the server side where we get the last
+// word, since there are no known downgrade attacks on cipher suites selection.
+//
+// The list is sorted by applying the following priority rules, stopping at the
+// first (most important) applicable one:
+//
+// - Anything else comes before RC4
+//
+// RC4 has practically exploitable biases. See https://www.rc4nomore.com.
+//
+// - Anything else comes before CBC_SHA256
+//
+// SHA-256 variants of the CBC ciphersuites don't implement any Lucky13
+// countermeasures. See https://www.isg.rhul.ac.uk/tls/Lucky13.html and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+//
+// - Anything else comes before 3DES
+//
+// 3DES has 64-bit blocks, which makes it fundamentally susceptible to
+// birthday attacks. See https://sweet32.info.
+//
+// - ECDHE comes before anything else
+//
+// Once we got the broken stuff out of the way, the most important
+// property a cipher suite can have is forward secrecy. We don't
+// implement FFDHE, so that means ECDHE.
+//
+// - AEADs come before CBC ciphers
+//
+// Even with Lucky13 countermeasures, MAC-then-Encrypt CBC cipher suites
+// are fundamentally fragile, and suffered from an endless sequence of
+// padding oracle attacks. See https://eprint.iacr.org/2015/1129,
+// https://www.imperialviolet.org/2014/12/08/poodleagain.html, and
+// https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/.
+//
+// - AES comes before ChaCha20
+//
+// When AES hardware is available, AES-128-GCM and AES-256-GCM are faster
+// than ChaCha20Poly1305.
+//
+// When AES hardware is not available, AES-128-GCM is one or more of: much
+// slower, way more complex, and less safe (because not constant time)
+// than ChaCha20Poly1305.
+//
+// We use this list if we think both peers have AES hardware, and
+// cipherSuitesPreferenceOrderNoAES otherwise.
+//
+// - AES-128 comes before AES-256
+//
+// The only potential advantages of AES-256 are better multi-target
+// margins, and hypothetical post-quantum properties. Neither apply to
+// TLS, and AES-256 is slower due to its four extra rounds (which don't
+// contribute to the advantages above).
+//
+// - ECDSA comes before RSA
+//
+// The relative order of ECDSA and RSA cipher suites doesn't matter,
+// as they depend on the certificate. Pick one to get a stable order.
+var cipherSuitesPreferenceOrder = []uint16{
+ // AEADs w/ ECDHE
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+
+ // CBC w/ ECDHE
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+
+ // AEADs w/o ECDHE
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+
+ // CBC w/o ECDHE
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+
+ // 3DES
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ // CBC_SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+
+ // RC4
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_RC4_128_SHA,
+}
+
+var cipherSuitesPreferenceOrderNoAES = []uint16{
+ // ChaCha20Poly1305
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+
+ // AES-GCM w/ ECDHE
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+
+ // The rest of cipherSuitesPreferenceOrder.
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_RC4_128_SHA,
+}
+
+// disabledCipherSuites are not used unless explicitly listed in Config.CipherSuites.
+var disabledCipherSuites = map[uint16]bool{
+ // CBC_SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: true,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: true,
+ TLS_RSA_WITH_AES_128_CBC_SHA256: true,
+
+ // RC4
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: true,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA: true,
+ TLS_RSA_WITH_RC4_128_SHA: true,
+}
+
+// rsaKexCiphers contains the ciphers which use RSA based key exchange,
+// which we also disable by default unless a GODEBUG is set.
+var rsaKexCiphers = map[uint16]bool{
+ TLS_RSA_WITH_RC4_128_SHA: true,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA: true,
+ TLS_RSA_WITH_AES_128_CBC_SHA: true,
+ TLS_RSA_WITH_AES_256_CBC_SHA: true,
+ TLS_RSA_WITH_AES_128_CBC_SHA256: true,
+ TLS_RSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_RSA_WITH_AES_256_GCM_SHA384: true,
+}
+
+// tdesCiphers contains 3DES ciphers,
+// which we also disable by default unless a GODEBUG is set.
+var tdesCiphers = map[uint16]bool{
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: true,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA: true,
+}
+
+var (
+ // Keep in sync with crypto/internal/fips140/aes/gcm.supportsAESGCM.
+ hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3
+ hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
+ hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCTR && cpu.S390X.HasGHASH
+ hasGCMAsmPPC64 = runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le"
+
+ hasAESGCMHardwareSupport = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X || hasGCMAsmPPC64
+)
+
+var aesgcmCiphers = map[uint16]bool{
+ // TLS 1.2
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true,
+ // TLS 1.3
+ TLS_AES_128_GCM_SHA256: true,
+ TLS_AES_256_GCM_SHA384: true,
+}
+
+// aesgcmPreferred returns whether the first known cipher in the preference list
+// is an AES-GCM cipher, implying the peer has hardware support for it.
+func aesgcmPreferred(ciphers []uint16) bool {
+ for _, cID := range ciphers {
+ if c := cipherSuiteByID(cID); c != nil {
+ return aesgcmCiphers[cID]
+ }
+ if c := cipherSuiteTLS13ByID(cID); c != nil {
+ return aesgcmCiphers[cID]
+ }
+ }
+ return false
+}
+
+func cipherRC4(key, iv []byte, isRead bool) any {
+ cipher, _ := rc4.NewCipher(key)
+ return cipher
+}
+
+func cipher3DES(key, iv []byte, isRead bool) any {
+ block, _ := des.NewTripleDESCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+func cipherAES(key, iv []byte, isRead bool) any {
+ block, _ := aes.NewCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+// macSHA1 returns a SHA-1 based constant time MAC.
+func macSHA1(key []byte) hash.Hash {
+ h := sha1.New
+ // The BoringCrypto SHA1 does not have a constant-time
+ // checksum function, so don't try to use it.
+ if !boring.Enabled {
+ h = newConstantTimeHash(h)
+ }
+ return hmac.New(h, key)
+}
+
+// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
+// is currently only used in disabled-by-default cipher suites.
+func macSHA256(key []byte) hash.Hash {
+ return hmac.New(sha256.New, key)
+}
+
+type aead interface {
+ cipher.AEAD
+
+ // explicitNonceLen returns the number of bytes of explicit nonce
+ // included in each record. This is eight for older AEADs and
+ // zero for modern ones.
+ explicitNonceLen() int
+}
+
+const (
+ aeadNonceLength = 12
+ noncePrefixLength = 4
+)
+
+// prefixNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
+// each call.
+type prefixNonceAEAD struct {
+ // nonce contains the fixed part of the nonce in the first four bytes.
+ nonce [aeadNonceLength]byte
+ aead cipher.AEAD
+}
+
+func (f *prefixNonceAEAD) NonceSize() int { return aeadNonceLength - noncePrefixLength }
+func (f *prefixNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() }
+
+func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ copy(f.nonce[4:], nonce)
+ return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
+}
+
+func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ copy(f.nonce[4:], nonce)
+ return f.aead.Open(out, f.nonce[:], ciphertext, additionalData)
+}
+
+// xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
+// before each call.
+type xorNonceAEAD struct {
+ nonceMask [aeadNonceLength]byte
+ aead cipher.AEAD
+}
+
+func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
+func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
+
+func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result
+}
+
+func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result, err
+}
+
+func aeadAESGCM(key, noncePrefix []byte) aead {
+ if len(noncePrefix) != noncePrefixLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aes, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+ var aead cipher.AEAD
+ if boring.Enabled {
+ aead, err = boring.NewGCMTLS(aes)
+ } else {
+ boring.Unreachable()
+ // [uTLS] SECTION BEGIN
+ // aead, err = gcm.NewGCMForTLS12(aes.(*fipsaes.Block))
+ aead, err = cipher.NewGCM(aes)
+ // [uTLS] SECTION END
+ }
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &prefixNonceAEAD{aead: aead}
+ copy(ret.nonce[:], noncePrefix)
+ return ret
+}
+
+// aeadAESGCMTLS13 should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/xtls/xray-core
+// - github.com/v2fly/v2ray-core
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname aeadAESGCMTLS13
+func aeadAESGCMTLS13(key, nonceMask []byte) aead {
+ if len(nonceMask) != aeadNonceLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aes, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+ var aead cipher.AEAD
+ if boring.Enabled {
+ aead, err = boring.NewGCMTLS13(aes)
+ } else {
+ boring.Unreachable()
+ // [uTLS] SECTION BEGIN
+ // aead, err = gcm.NewGCMForTLS13(aes.(*fipsaes.Block))
+ aead, err = cipher.NewGCM(aes)
+ // [uTLS] SECTION END
+ }
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], nonceMask)
+ return ret
+}
+
+func aeadChaCha20Poly1305(key, nonceMask []byte) aead {
+ if len(nonceMask) != aeadNonceLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aead, err := chacha20poly1305.New(key)
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], nonceMask)
+ return ret
+}
+
+type constantTimeHash interface {
+ hash.Hash
+ ConstantTimeSum(b []byte) []byte
+}
+
+// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
+// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
+type cthWrapper struct {
+ h constantTimeHash
+}
+
+func (c *cthWrapper) Size() int { return c.h.Size() }
+func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() }
+func (c *cthWrapper) Reset() { c.h.Reset() }
+func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
+func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
+
+func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
+ boring.Unreachable()
+ return func() hash.Hash {
+ return &cthWrapper{h().(constantTimeHash)}
+ }
+}
+
+// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
+func tls10MAC(h hash.Hash, out, seq, header, data, extra []byte) []byte {
+ h.Reset()
+ h.Write(seq)
+ h.Write(header)
+ h.Write(data)
+ res := h.Sum(out)
+ if extra != nil {
+ h.Write(extra)
+ }
+ return res
+}
+
+func rsaKA(version uint16) keyAgreement {
+ return rsaKeyAgreement{}
+}
+
+func ecdheECDSAKA(version uint16) keyAgreement {
+ return &ecdheKeyAgreement{
+ isRSA: false,
+ version: version,
+ }
+}
+
+func ecdheRSAKA(version uint16) keyAgreement {
+ return &ecdheKeyAgreement{
+ isRSA: true,
+ version: version,
+ }
+}
+
+// mutualCipherSuite returns a cipherSuite given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
+ for _, id := range have {
+ if id == want {
+ return cipherSuiteByID(id)
+ }
+ }
+ return nil
+}
+
+func cipherSuiteByID(id uint16) *cipherSuite {
+ for _, cipherSuite := range utlsSupportedCipherSuites {
+ if cipherSuite.id == id {
+ return cipherSuite
+ }
+ }
+ return nil
+}
+
+func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 {
+ for _, id := range have {
+ if id == want {
+ return cipherSuiteTLS13ByID(id)
+ }
+ }
+ return nil
+}
+
+func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13 {
+ for _, cipherSuite := range cipherSuitesTLS13 {
+ if cipherSuite.id == id {
+ return cipherSuite
+ }
+ }
+ return nil
+}
+
+// A list of cipher suite IDs that are, or have been, implemented by this
+// package.
+//
+// See https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+ // TLS 1.0 - 1.2 cipher suites.
+ TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
+ TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
+ TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
+ TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
+ TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
+ TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca8
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca9
+
+ // TLS 1.3 cipher suites.
+ TLS_AES_128_GCM_SHA256 uint16 = 0x1301
+ TLS_AES_256_GCM_SHA384 uint16 = 0x1302
+ TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303
+
+ // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
+ // that the client is doing version fallback. See RFC 7507.
+ TLS_FALLBACK_SCSV uint16 = 0x5600
+
+ // Legacy names for the corresponding cipher suites with the correct _SHA256
+ // suffix, retained for backward compatibility.
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+)
diff --git a/vendor/github.com/refraction-networking/utls/common.go b/vendor/github.com/refraction-networking/utls/common.go
new file mode 100644
index 00000000..73b6dad5
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/common.go
@@ -0,0 +1,1819 @@
+// 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 tls
+
+import (
+ "bytes"
+ "container/list"
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha512"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "slices"
+ "strings"
+ "sync"
+ "time"
+ _ "unsafe" // for linkname
+
+ "github.com/refraction-networking/utls/internal/fips140tls"
+)
+
+const (
+ VersionTLS10 = 0x0301
+ VersionTLS11 = 0x0302
+ VersionTLS12 = 0x0303
+ VersionTLS13 = 0x0304
+
+ // Deprecated: SSLv3 is cryptographically broken, and is no longer
+ // supported by this package. See golang.org/issue/32716.
+ VersionSSL30 = 0x0300
+)
+
+// VersionName returns the name for the provided TLS version number
+// (e.g. "TLS 1.3"), or a fallback representation of the value if the
+// version is not implemented by this package.
+func VersionName(version uint16) string {
+ switch version {
+ case VersionSSL30:
+ return "SSLv3"
+ case VersionTLS10:
+ return "TLS 1.0"
+ case VersionTLS11:
+ return "TLS 1.1"
+ case VersionTLS12:
+ return "TLS 1.2"
+ case VersionTLS13:
+ return "TLS 1.3"
+ default:
+ return fmt.Sprintf("0x%04X", version)
+ }
+}
+
+const (
+ maxPlaintext = 16384 // maximum plaintext payload length
+ maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
+ maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3
+ recordHeaderLen = 5 // record header length
+ maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
+ maxHandshakeCertificateMsg = 262144 // maximum certificate message size (256 KiB)
+ maxUselessRecords = 32 // maximum number of consecutive non-advancing records
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+ recordTypeChangeCipherSpec recordType = 20
+ recordTypeAlert recordType = 21
+ recordTypeHandshake recordType = 22
+ recordTypeApplicationData recordType = 23
+)
+
+// TLS handshake message types.
+const (
+ typeHelloRequest uint8 = 0
+ typeClientHello uint8 = 1
+ typeServerHello uint8 = 2
+ typeNewSessionTicket uint8 = 4
+ typeEndOfEarlyData uint8 = 5
+ typeEncryptedExtensions uint8 = 8
+ typeCertificate uint8 = 11
+ typeServerKeyExchange uint8 = 12
+ typeCertificateRequest uint8 = 13
+ typeServerHelloDone uint8 = 14
+ typeCertificateVerify uint8 = 15
+ typeClientKeyExchange uint8 = 16
+ typeFinished uint8 = 20
+ typeCertificateStatus uint8 = 22
+ typeKeyUpdate uint8 = 24
+ typeMessageHash uint8 = 254 // synthetic message
+)
+
+// TLS compression types.
+const (
+ compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+const (
+ extensionServerName uint16 = 0
+ extensionStatusRequest uint16 = 5
+ extensionSupportedCurves uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7
+ extensionSupportedPoints uint16 = 11
+ extensionSignatureAlgorithms uint16 = 13
+ extensionALPN uint16 = 16
+ extensionStatusRequestV2 uint16 = 17
+ extensionSCT uint16 = 18
+ extensionExtendedMasterSecret uint16 = 23
+ extensionDelegatedCredentials uint16 = 34
+ extensionSessionTicket uint16 = 35
+ extensionPreSharedKey uint16 = 41
+ extensionEarlyData uint16 = 42
+ extensionSupportedVersions uint16 = 43
+ extensionCookie uint16 = 44
+ extensionPSKModes uint16 = 45
+ extensionCertificateAuthorities uint16 = 47
+ extensionSignatureAlgorithmsCert uint16 = 50
+ extensionKeyShare uint16 = 51
+ extensionQUICTransportParameters uint16 = 57
+ extensionRenegotiationInfo uint16 = 0xff01
+ extensionECHOuterExtensions uint16 = 0xfd00
+ extensionEncryptedClientHello uint16 = 0xfe0d
+)
+
+// TLS signaling cipher suite values
+const (
+ scsvRenegotiation uint16 = 0x00ff
+)
+
+// CurveID is the type of a TLS identifier for a key exchange mechanism. See
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
+//
+// In TLS 1.2, this registry used to support only elliptic curves. In TLS 1.3,
+// it was extended to other groups and renamed NamedGroup. See RFC 8446, Section
+// 4.2.7. It was then also extended to other mechanisms, such as hybrid
+// post-quantum KEMs.
+type CurveID uint16
+
+const (
+ CurveP256 CurveID = 23
+ CurveP384 CurveID = 24
+ CurveP521 CurveID = 25
+ X25519 CurveID = 29
+ X25519MLKEM768 CurveID = 4588
+)
+
+func isTLS13OnlyKeyExchange(curve CurveID) bool {
+ return curve == X25519MLKEM768
+}
+
+func isPQKeyExchange(curve CurveID) bool {
+ return curve == X25519MLKEM768
+}
+
+// TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
+type keyShare struct {
+ group CurveID
+ data []byte
+}
+
+// TLS 1.3 PSK Key Exchange Modes. See RFC 8446, Section 4.2.9.
+const (
+ pskModePlain uint8 = 0
+ pskModeDHE uint8 = 1
+)
+
+// TLS 1.3 PSK Identity. Can be a Session Ticket, or a reference to a saved
+// session. See RFC 8446, Section 4.2.11.
+type pskIdentity struct {
+ label []byte
+ obfuscatedTicketAge uint32
+}
+
+// TLS Elliptic Curve Point Formats
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+const (
+ pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+ statusTypeOCSP uint8 = 1
+ statusV2TypeOCSP uint8 = 2
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+ certTypeRSASign = 1
+ certTypeECDSASign = 64 // ECDSA or EdDSA keys, see RFC 8422, Section 3.
+)
+
+// Signature algorithms (for internal signaling use). Starting at 225 to avoid overlap with
+// TLS 1.2 codepoints (RFC 5246, Appendix A.4.1), with which these have nothing to do.
+const (
+ signaturePKCS1v15 uint8 = iota + 225
+ signatureRSAPSS
+ signatureECDSA
+ signatureEd25519
+ signatureEdDilithium3
+)
+
+// directSigning is a standard Hash value that signals that no pre-hashing
+// should be performed, and that the input should be signed directly. It is the
+// hash function associated with the Ed25519 signature scheme.
+var directSigning crypto.Hash = 0
+
+// helloRetryRequestRandom is set as the Random value of a ServerHello
+// to signal that the message is actually a HelloRetryRequest.
+var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3.
+ 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
+ 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
+ 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
+ 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
+}
+
+const (
+ // downgradeCanaryTLS12 or downgradeCanaryTLS11 is embedded in the server
+ // random as a downgrade protection if the server would be capable of
+ // negotiating a higher version. See RFC 8446, Section 4.1.3.
+ downgradeCanaryTLS12 = "DOWNGRD\x01"
+ downgradeCanaryTLS11 = "DOWNGRD\x00"
+)
+
+// testingOnlyForceDowngradeCanary is set in tests to force the server side to
+// include downgrade canaries even if it's using its highers supported version.
+var testingOnlyForceDowngradeCanary bool
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+ // Version is the TLS version used by the connection (e.g. VersionTLS12).
+ Version uint16
+
+ // HandshakeComplete is true if the handshake has concluded.
+ HandshakeComplete bool
+
+ // DidResume is true if this connection was successfully resumed from a
+ // previous session with a session ticket or similar mechanism.
+ DidResume bool
+
+ // CipherSuite is the cipher suite negotiated for the connection (e.g.
+ // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256).
+ CipherSuite uint16
+
+ // NegotiatedProtocol is the application protocol negotiated with ALPN.
+ NegotiatedProtocol string
+
+ // NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation.
+ //
+ // Deprecated: this value is always true.
+ NegotiatedProtocolIsMutual bool
+
+ // PeerApplicationSettings is the Application-Layer Protocol Settings (ALPS)
+ // provided by peer.
+ PeerApplicationSettings []byte // [uTLS]
+
+ // ServerName is the value of the Server Name Indication extension sent by
+ // the client. It's available both on the server and on the client side.
+ ServerName string
+
+ // PeerCertificates are the parsed certificates sent by the peer, in the
+ // order in which they were sent. The first element is the leaf certificate
+ // that the connection is verified against.
+ //
+ // On the client side, it can't be empty. On the server side, it can be
+ // empty if Config.ClientAuth is not RequireAnyClientCert or
+ // RequireAndVerifyClientCert.
+ //
+ // PeerCertificates and its contents should not be modified.
+ PeerCertificates []*x509.Certificate
+
+ // VerifiedChains is a list of one or more chains where the first element is
+ // PeerCertificates[0] and the last element is from Config.RootCAs (on the
+ // client side) or Config.ClientCAs (on the server side).
+ //
+ // On the client side, it's set if Config.InsecureSkipVerify is false. On
+ // the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven
+ // (and the peer provided a certificate) or RequireAndVerifyClientCert.
+ //
+ // VerifiedChains and its contents should not be modified.
+ VerifiedChains [][]*x509.Certificate
+
+ // SignedCertificateTimestamps is a list of SCTs provided by the peer
+ // through the TLS handshake for the leaf certificate, if any.
+ SignedCertificateTimestamps [][]byte
+
+ // OCSPResponse is a stapled Online Certificate Status Protocol (OCSP)
+ // response provided by the peer for the leaf certificate, if any.
+ OCSPResponse []byte
+
+ // TLSUnique contains the "tls-unique" channel binding value (see RFC 5929,
+ // Section 3). This value will be nil for TLS 1.3 connections and for
+ // resumed connections that don't support Extended Master Secret (RFC 7627).
+ TLSUnique []byte
+
+ // ECHAccepted indicates if Encrypted Client Hello was offered by the client
+ // and accepted by the server. Currently, ECH is supported only on the
+ // client side.
+ ECHAccepted bool
+
+ // ekm is a closure exposed via ExportKeyingMaterial.
+ ekm func(label string, context []byte, length int) ([]byte, error)
+
+ // testingOnlyDidHRR is true if a HelloRetryRequest was sent/received.
+ testingOnlyDidHRR bool
+
+ // testingOnlyCurveID is the selected CurveID, or zero if an RSA exchanges
+ // is performed.
+ testingOnlyCurveID CurveID
+}
+
+// ExportKeyingMaterial returns length bytes of exported key material in a new
+// slice as defined in RFC 5705. If context is nil, it is not used as part of
+// the seed. If the connection was set to allow renegotiation via
+// Config.Renegotiation, or if the connections supports neither TLS 1.3 nor
+// Extended Master Secret, this function will return an error.
+//
+// Exporting key material without Extended Master Secret or TLS 1.3 was disabled
+// in Go 1.22 due to security issues (see the Security Considerations sections
+// of RFC 5705 and RFC 7627), but can be re-enabled with the GODEBUG setting
+// tlsunsafeekm=1.
+func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+ return cs.ekm(label, context, length)
+}
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+ // NoClientCert indicates that no client certificate should be requested
+ // during the handshake, and if any certificates are sent they will not
+ // be verified.
+ NoClientCert ClientAuthType = iota
+ // RequestClientCert indicates that a client certificate should be requested
+ // during the handshake, but does not require that the client send any
+ // certificates.
+ RequestClientCert
+ // RequireAnyClientCert indicates that a client certificate should be requested
+ // during the handshake, and that at least one certificate is required to be
+ // sent by the client, but that certificate is not required to be valid.
+ RequireAnyClientCert
+ // VerifyClientCertIfGiven indicates that a client certificate should be requested
+ // during the handshake, but does not require that the client sends a
+ // certificate. If the client does send a certificate it is required to be
+ // valid.
+ VerifyClientCertIfGiven
+ // RequireAndVerifyClientCert indicates that a client certificate should be requested
+ // during the handshake, and that at least one valid certificate is required
+ // to be sent by the client.
+ RequireAndVerifyClientCert
+)
+
+// requiresClientCert reports whether the ClientAuthType requires a client
+// certificate to be provided.
+func requiresClientCert(c ClientAuthType) bool {
+ switch c {
+ case RequireAnyClientCert, RequireAndVerifyClientCert:
+ return true
+ default:
+ return false
+ }
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
+// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
+// are supported via this interface.
+type ClientSessionCache interface {
+ // Get searches for a ClientSessionState associated with the given key.
+ // On return, ok is true if one was found.
+ Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+ // Put adds the ClientSessionState to the cache with the given key. It might
+ // get called multiple times in a connection if a TLS 1.3 server provides
+ // more than one session ticket. If called with a nil *ClientSessionState,
+ // it should remove the cache entry.
+ Put(sessionKey string, cs *ClientSessionState)
+}
+
+//go:generate stringer -linecomment -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
+
+// SignatureScheme identifies a signature algorithm supported by TLS. See
+// RFC 8446, Section 4.2.3.
+type SignatureScheme uint16
+
+const (
+ // RSASSA-PKCS1-v1_5 algorithms.
+ PKCS1WithSHA256 SignatureScheme = 0x0401
+ PKCS1WithSHA384 SignatureScheme = 0x0501
+ PKCS1WithSHA512 SignatureScheme = 0x0601
+
+ // RSASSA-PSS algorithms with public key OID rsaEncryption.
+ PSSWithSHA256 SignatureScheme = 0x0804
+ PSSWithSHA384 SignatureScheme = 0x0805
+ PSSWithSHA512 SignatureScheme = 0x0806
+
+ // ECDSA algorithms. Only constrained to a specific curve in TLS 1.3.
+ ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
+ ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
+ ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
+
+ // EdDSA algorithms.
+ Ed25519 SignatureScheme = 0x0807
+
+ // Legacy signature and hash algorithms for TLS 1.2.
+ PKCS1WithSHA1 SignatureScheme = 0x0201
+ ECDSAWithSHA1 SignatureScheme = 0x0203
+)
+
+// ClientHelloInfo contains information from a ClientHello message in order to
+// guide application logic in the GetCertificate and GetConfigForClient callbacks.
+type ClientHelloInfo struct {
+ // CipherSuites lists the CipherSuites supported by the client (e.g.
+ // TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
+ CipherSuites []uint16
+
+ // ServerName indicates the name of the server requested by the client
+ // in order to support virtual hosting. ServerName is only set if the
+ // client is using SNI (see RFC 4366, Section 3.1).
+ ServerName string
+
+ // SupportedCurves lists the key exchange mechanisms supported by the
+ // client. It was renamed to "supported groups" in TLS 1.3, see RFC 8446,
+ // Section 4.2.7 and [CurveID].
+ //
+ // SupportedCurves may be nil in TLS 1.2 and lower if the Supported Elliptic
+ // Curves Extension is not being used (see RFC 4492, Section 5.1.1).
+ SupportedCurves []CurveID
+
+ // SupportedPoints lists the point formats supported by the client.
+ // SupportedPoints is set only if the Supported Point Formats Extension
+ // is being used (see RFC 4492, Section 5.1.2).
+ SupportedPoints []uint8
+
+ // SignatureSchemes lists the signature and hash schemes that the client
+ // is willing to verify. SignatureSchemes is set only if the Signature
+ // Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
+ SignatureSchemes []SignatureScheme
+
+ // SupportedProtos lists the application protocols supported by the client.
+ // SupportedProtos is set only if the Application-Layer Protocol
+ // Negotiation Extension is being used (see RFC 7301, Section 3.1).
+ //
+ // Servers can select a protocol by setting Config.NextProtos in a
+ // GetConfigForClient return value.
+ SupportedProtos []string
+
+ // SupportedVersions lists the TLS versions supported by the client.
+ // For TLS versions less than 1.3, this is extrapolated from the max
+ // version advertised by the client, so values other than the greatest
+ // might be rejected if used.
+ SupportedVersions []uint16
+
+ // Extensions lists the IDs of the extensions presented by the client
+ // in the ClientHello.
+ Extensions []uint16
+
+ // Conn is the underlying net.Conn for the connection. Do not read
+ // from, or write to, this connection; that will cause the TLS
+ // connection to fail.
+ Conn net.Conn
+
+ // config is embedded by the GetCertificate or GetConfigForClient caller,
+ // for use with SupportsCertificate.
+ config *Config
+
+ // ctx is the context of the handshake that is in progress.
+ ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *ClientHelloInfo) Context() context.Context {
+ return c.ctx
+}
+
+// CertificateRequestInfo contains information from a server's
+// CertificateRequest message, which is used to demand a certificate and proof
+// of control from a client.
+type CertificateRequestInfo struct {
+ // AcceptableCAs contains zero or more, DER-encoded, X.501
+ // Distinguished Names. These are the names of root or intermediate CAs
+ // that the server wishes the returned certificate to be signed by. An
+ // empty slice indicates that the server has no preference.
+ AcceptableCAs [][]byte
+
+ // SignatureSchemes lists the signature schemes that the server is
+ // willing to verify.
+ SignatureSchemes []SignatureScheme
+
+ // Version is the TLS version that was negotiated for this connection.
+ Version uint16
+
+ // ctx is the context of the handshake that is in progress.
+ ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *CertificateRequestInfo) Context() context.Context {
+ return c.ctx
+}
+
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// the state machine and has been the source of numerous, subtle security
+// issues. Initiating a renegotiation is not supported, but support for
+// accepting renegotiation requests may be enabled.
+//
+// Even when enabled, the server may not change its identity between handshakes
+// (i.e. the leaf certificate must be the same). Additionally, concurrent
+// handshake and application data flow is not permitted so renegotiation can
+// only be used with protocols that synchronise with the renegotiation, such as
+// HTTPS.
+//
+// Renegotiation is not defined in TLS 1.3.
+type RenegotiationSupport int
+
+const (
+ // RenegotiateNever disables renegotiation.
+ RenegotiateNever RenegotiationSupport = iota
+
+ // RenegotiateOnceAsClient allows a remote server to request
+ // renegotiation once per connection.
+ RenegotiateOnceAsClient
+
+ // RenegotiateFreelyAsClient allows a remote server to repeatedly
+ // request renegotiation.
+ RenegotiateFreelyAsClient
+)
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
+type Config struct {
+ // Rand provides the source of entropy for nonces and RSA blinding.
+ // If Rand is nil, TLS uses the cryptographic random reader in package
+ // crypto/rand.
+ // The Reader must be safe for use by multiple goroutines.
+ Rand io.Reader
+
+ // Time returns the current time as the number of seconds since the epoch.
+ // If Time is nil, TLS uses time.Now.
+ Time func() time.Time
+
+ // Certificates contains one or more certificate chains to present to the
+ // other side of the connection. The first certificate compatible with the
+ // peer's requirements is selected automatically.
+ //
+ // Server configurations must set one of Certificates, GetCertificate or
+ // GetConfigForClient. Clients doing client-authentication may set either
+ // Certificates or GetClientCertificate.
+ //
+ // Note: if there are multiple Certificates, and they don't have the
+ // optional field Leaf set, certificate selection will incur a significant
+ // per-handshake performance cost.
+ Certificates []Certificate
+
+ // NameToCertificate maps from a certificate name to an element of
+ // Certificates. Note that a certificate name can be of the form
+ // '*.example.com' and so doesn't have to be a domain name as such.
+ //
+ // Deprecated: NameToCertificate only allows associating a single
+ // certificate with a given name. Leave this field nil to let the library
+ // select the first compatible chain from Certificates.
+ NameToCertificate map[string]*Certificate
+
+ // GetCertificate returns a Certificate based on the given
+ // ClientHelloInfo. It will only be called if the client supplies SNI
+ // information or if Certificates is empty.
+ //
+ // If GetCertificate is nil or returns nil, then the certificate is
+ // retrieved from NameToCertificate. If NameToCertificate is nil, the
+ // best element of Certificates will be used.
+ //
+ // Once a Certificate is returned it should not be modified.
+ GetCertificate func(*ClientHelloInfo) (*Certificate, error)
+
+ // GetClientCertificate, if not nil, is called when a server requests a
+ // certificate from a client. If set, the contents of Certificates will
+ // be ignored.
+ //
+ // If GetClientCertificate returns an error, the handshake will be
+ // aborted and that error will be returned. Otherwise
+ // GetClientCertificate must return a non-nil Certificate. If
+ // Certificate.Certificate is empty then no certificate will be sent to
+ // the server. If this is unacceptable to the server then it may abort
+ // the handshake.
+ //
+ // GetClientCertificate may be called multiple times for the same
+ // connection if renegotiation occurs or if TLS 1.3 is in use.
+ //
+ // Once a Certificate is returned it should not be modified.
+ GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+
+ // GetConfigForClient, if not nil, is called after a ClientHello is
+ // received from a client. It may return a non-nil Config in order to
+ // change the Config that will be used to handle this connection. If
+ // the returned Config is nil, the original Config will be used. The
+ // Config returned by this callback may not be subsequently modified.
+ //
+ // If GetConfigForClient is nil, the Config passed to Server() will be
+ // used for all connections.
+ //
+ // If SessionTicketKey was explicitly set on the returned Config, or if
+ // SetSessionTicketKeys was called on the returned Config, those keys will
+ // be used. Otherwise, the original Config keys will be used (and possibly
+ // rotated if they are automatically managed).
+ GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+
+ // VerifyPeerCertificate, if not nil, is called after normal
+ // certificate verification by either a TLS client or server. It
+ // receives the raw ASN.1 certificates provided by the peer and also
+ // any verified chains that normal processing found. If it returns a
+ // non-nil error, the handshake is aborted and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. If normal verification is disabled (on the
+ // client when InsecureSkipVerify is set, or on a server when ClientAuth is
+ // RequestClientCert or RequireAnyClientCert), then this callback will be
+ // considered but the verifiedChains argument will always be nil. When
+ // ClientAuth is NoClientCert, this callback is not called on the server.
+ // rawCerts may be empty on the server if ClientAuth is RequestClientCert or
+ // VerifyClientCertIfGiven.
+ //
+ // This callback is not invoked on resumed connections, as certificates are
+ // not re-verified on resumption.
+ //
+ // verifiedChains and its contents should not be modified.
+ VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+
+ // VerifyConnection, if not nil, is called after normal certificate
+ // verification and after VerifyPeerCertificate by either a TLS client
+ // or server. If it returns a non-nil error, the handshake is aborted
+ // and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. This callback will run for all connections,
+ // including resumptions, regardless of InsecureSkipVerify or ClientAuth
+ // settings.
+ VerifyConnection func(ConnectionState) error
+
+ // RootCAs defines the set of root certificate authorities
+ // that clients use when verifying server certificates.
+ // If RootCAs is nil, TLS uses the host's root CA set.
+ RootCAs *x509.CertPool
+
+ // NextProtos is a list of supported application level protocols, in
+ // order of preference. If both peers support ALPN, the selected
+ // protocol will be one from this list, and the connection will fail
+ // if there is no mutually supported protocol. If NextProtos is empty
+ // or the peer doesn't support ALPN, the connection will succeed and
+ // ConnectionState.NegotiatedProtocol will be empty.
+ NextProtos []string
+
+ // ApplicationSettings is a set of application settings (ALPS) to use
+ // with each application protocol (ALPN).
+ ApplicationSettings map[string][]byte // [uTLS]
+
+ // ServerName is used to verify the hostname on the returned
+ // certificates unless InsecureSkipVerify is given. It is also included
+ // in the client's handshake to support virtual hosting unless it is
+ // an IP address.
+ ServerName string
+
+ // ClientAuth determines the server's policy for
+ // TLS Client Authentication. The default is NoClientCert.
+ ClientAuth ClientAuthType
+
+ // ClientCAs defines the set of root certificate authorities
+ // that servers use if required to verify a client certificate
+ // by the policy in ClientAuth.
+ ClientCAs *x509.CertPool
+
+ // InsecureSkipVerify controls whether a client verifies the server's
+ // certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
+ // accepts any certificate presented by the server and any host name in that
+ // certificate. In this mode, TLS is susceptible to machine-in-the-middle
+ // attacks unless custom verification is used. This should be used only for
+ // testing or in combination with VerifyConnection or VerifyPeerCertificate.
+ InsecureSkipVerify bool
+
+ // InsecureSkipTimeVerify controls whether a client verifies the server's
+ // certificate chain against time. If InsecureSkipTimeVerify is true,
+ // crypto/tls accepts the certificate even when it is expired.
+ //
+ // This field is ignored when InsecureSkipVerify is true.
+ InsecureSkipTimeVerify bool // [uTLS]
+
+ // OmitEmptyPsk determines whether utls will automatically conceal
+ // the psk extension when it is empty. When the psk extension is empty, the
+ // browser omits it from the client hello. Utls can mimic this behavior,
+ // but it deviates from the provided client hello specification, rendering
+ // it unsuitable as the default behavior. Users have the option to enable
+ // this behavior at their own discretion.
+ OmitEmptyPsk bool // [uTLS]
+
+ // InsecureServerNameToVerify is used to verify the hostname on the returned
+ // certificates. It is intended to use with spoofed ServerName.
+ // If InsecureServerNameToVerify is "*", crypto/tls will do normal
+ // certificate validation but ignore certifacate's DNSName.
+ //
+ // This field is ignored when InsecureSkipVerify is true.
+ InsecureServerNameToVerify string // [uTLS]
+
+ // PreferSkipResumptionOnNilExtension controls the behavior when session resumption is enabled but the corresponding session extensions are nil.
+ //
+ // To successfully use session resumption, ensure that the following requirements are met:
+ // - SessionTicketsDisabled is set to false
+ // - ClientSessionCache is non-nil
+ // - For TLS 1.2, SessionTicketExtension is non-nil
+ // - For TLS 1.3, PreSharedKeyExtension is non-nil
+ //
+ // There may be cases where users enable session resumption (SessionTicketsDisabled: false && ClientSessionCache: non-nil), but they do not provide SessionTicketExtension or PreSharedKeyExtension in the ClientHelloSpec. This could be intentional or accidental.
+ //
+ // By default, utls throws an exception in such scenarios. Set this to true to skip the resumption and suppress the exception.
+ PreferSkipResumptionOnNilExtension bool // [uTLS]
+
+ // CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of
+ // the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
+ //
+ // If CipherSuites is nil, a safe default list is used. The default cipher
+ // suites might change over time. In Go 1.22 RSA key exchange based cipher
+ // suites were removed from the default list, but can be re-added with the
+ // GODEBUG setting tlsrsakex=1. In Go 1.23 3DES cipher suites were removed
+ // from the default list, but can be re-added with the GODEBUG setting
+ // tls3des=1.
+ CipherSuites []uint16
+
+ // PreferServerCipherSuites is a legacy field and has no effect.
+ //
+ // It used to control whether the server would follow the client's or the
+ // server's preference. Servers now select the best mutually supported
+ // cipher suite based on logic that takes into account inferred client
+ // hardware, server hardware, and security.
+ //
+ // Deprecated: PreferServerCipherSuites is ignored.
+ PreferServerCipherSuites bool
+
+ // SessionTicketsDisabled may be set to true to disable session ticket and
+ // PSK (resumption) support. Note that on clients, session ticket support is
+ // also disabled if ClientSessionCache is nil.
+ SessionTicketsDisabled bool
+
+ // SessionTicketKey is used by TLS servers to provide session resumption.
+ // See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
+ // with random data before the first server handshake.
+ //
+ // Deprecated: if this field is left at zero, session ticket keys will be
+ // automatically rotated every day and dropped after seven days. For
+ // customizing the rotation schedule or synchronizing servers that are
+ // terminating connections for the same host, use SetSessionTicketKeys.
+ SessionTicketKey [32]byte
+
+ // ClientSessionCache is a cache of ClientSessionState entries for TLS
+ // session resumption. It is only used by clients.
+ ClientSessionCache ClientSessionCache
+
+ // UnwrapSession is called on the server to turn a ticket/identity
+ // previously produced by [WrapSession] into a usable session.
+ //
+ // UnwrapSession will usually either decrypt a session state in the ticket
+ // (for example with [Config.EncryptTicket]), or use the ticket as a handle
+ // to recover a previously stored state. It must use [ParseSessionState] to
+ // deserialize the session state.
+ //
+ // If UnwrapSession returns an error, the connection is terminated. If it
+ // returns (nil, nil), the session is ignored. crypto/tls may still choose
+ // not to resume the returned session.
+ UnwrapSession func(identity []byte, cs ConnectionState) (*SessionState, error)
+
+ // WrapSession is called on the server to produce a session ticket/identity.
+ //
+ // WrapSession must serialize the session state with [SessionState.Bytes].
+ // It may then encrypt the serialized state (for example with
+ // [Config.DecryptTicket]) and use it as the ticket, or store the state and
+ // return a handle for it.
+ //
+ // If WrapSession returns an error, the connection is terminated.
+ //
+ // Warning: the return value will be exposed on the wire and to clients in
+ // plaintext. The application is in charge of encrypting and authenticating
+ // it (and rotating keys) or returning high-entropy identifiers. Failing to
+ // do so correctly can compromise current, previous, and future connections
+ // depending on the protocol version.
+ WrapSession func(ConnectionState, *SessionState) ([]byte, error)
+
+ // MinVersion contains the minimum TLS version that is acceptable.
+ //
+ // By default, TLS 1.2 is currently used as the minimum. TLS 1.0 is the
+ // minimum supported by this package.
+ //
+ // The server-side default can be reverted to TLS 1.0 by including the value
+ // "tls10server=1" in the GODEBUG environment variable.
+ MinVersion uint16
+
+ // MaxVersion contains the maximum TLS version that is acceptable.
+ //
+ // By default, the maximum version supported by this package is used,
+ // which is currently TLS 1.3.
+ MaxVersion uint16
+
+ // CurvePreferences contains a set of supported key exchange mechanisms.
+ // The name refers to elliptic curves for legacy reasons, see [CurveID].
+ // The order of the list is ignored, and key exchange mechanisms are chosen
+ // from this list using an internal preference order. If empty, the default
+ // will be used.
+ //
+ // From Go 1.24, the default includes the [X25519MLKEM768] hybrid
+ // post-quantum key exchange. To disable it, set CurvePreferences explicitly
+ // or use the GODEBUG=tlsmlkem=0 environment variable.
+ CurvePreferences []CurveID
+
+ // PQSignatureSchemesEnabled controls whether additional post-quantum
+ // signature schemes are supported for peer certificates. For available
+ // signature schemes, see tls_cf.go.
+ PQSignatureSchemesEnabled bool // [UTLS] ported from cloudflare/go
+
+ // DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
+ // When true, the largest possible TLS record size is always used. When
+ // false, the size of TLS records may be adjusted in an attempt to
+ // improve latency.
+ DynamicRecordSizingDisabled bool
+
+ // Renegotiation controls what types of renegotiation are supported.
+ // The default, none, is correct for the vast majority of applications.
+ Renegotiation RenegotiationSupport
+
+ // KeyLogWriter optionally specifies a destination for TLS master secrets
+ // in NSS key log format that can be used to allow external programs
+ // such as Wireshark to decrypt TLS connections.
+ // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+ // Use of KeyLogWriter compromises security and should only be
+ // used for debugging.
+ KeyLogWriter io.Writer
+
+ // EncryptedClientHelloConfigList is a serialized ECHConfigList. If
+ // provided, clients will attempt to connect to servers using Encrypted
+ // Client Hello (ECH) using one of the provided ECHConfigs.
+ //
+ // Servers do not use this field. In order to configure ECH for servers, see
+ // the EncryptedClientHelloKeys field.
+ //
+ // If the list contains no valid ECH configs, the handshake will fail
+ // and return an error.
+ //
+ // If EncryptedClientHelloConfigList is set, MinVersion, if set, must
+ // be VersionTLS13.
+ //
+ // When EncryptedClientHelloConfigList is set, the handshake will only
+ // succeed if ECH is successfully negotiated. If the server rejects ECH,
+ // an ECHRejectionError error will be returned, which may contain a new
+ // ECHConfigList that the server suggests using.
+ //
+ // How this field is parsed may change in future Go versions, if the
+ // encoding described in the final Encrypted Client Hello RFC changes.
+ EncryptedClientHelloConfigList []byte
+
+ // EncryptedClientHelloRejectionVerify, if not nil, is called when ECH is
+ // rejected by the remote server, in order to verify the ECH provider
+ // certificate in the outer ClientHello. If it returns a non-nil error, the
+ // handshake is aborted and that error results.
+ //
+ // On the server side this field is not used.
+ //
+ // Unlike VerifyPeerCertificate and VerifyConnection, normal certificate
+ // verification will not be performed before calling
+ // EncryptedClientHelloRejectionVerify.
+ //
+ // If EncryptedClientHelloRejectionVerify is nil and ECH is rejected, the
+ // roots in RootCAs will be used to verify the ECH providers public
+ // certificate. VerifyPeerCertificate and VerifyConnection are not called
+ // when ECH is rejected, even if set, and InsecureSkipVerify is ignored.
+ EncryptedClientHelloRejectionVerify func(ConnectionState) error
+
+ // EncryptedClientHelloKeys are the ECH keys to use when a client
+ // attempts ECH.
+ //
+ // If EncryptedClientHelloKeys is set, MinVersion, if set, must be
+ // VersionTLS13.
+ //
+ // If a client attempts ECH, but it is rejected by the server, the server
+ // will send a list of configs to retry based on the set of
+ // EncryptedClientHelloKeys which have the SendAsRetry field set.
+ //
+ // On the client side, this field is ignored. In order to configure ECH for
+ // clients, see the EncryptedClientHelloConfigList field.
+ EncryptedClientHelloKeys []EncryptedClientHelloKey
+
+ // mutex protects sessionTicketKeys and autoSessionTicketKeys.
+ mutex sync.RWMutex
+ // sessionTicketKeys contains zero or more ticket keys. If set, it means
+ // the keys were set with SessionTicketKey or SetSessionTicketKeys. The
+ // first key is used for new tickets and any subsequent keys can be used to
+ // decrypt old tickets. The slice contents are not protected by the mutex
+ // and are immutable.
+ sessionTicketKeys []ticketKey
+ // autoSessionTicketKeys is like sessionTicketKeys but is owned by the
+ // auto-rotation logic. See Config.ticketKeys.
+ autoSessionTicketKeys []ticketKey
+}
+
+// EncryptedClientHelloKey holds a private key that is associated
+// with a specific ECH config known to a client.
+type EncryptedClientHelloKey struct {
+ // Config should be a marshalled ECHConfig associated with PrivateKey. This
+ // must match the config provided to clients byte-for-byte. The config
+ // should only specify the DHKEM(X25519, HKDF-SHA256) KEM ID (0x0020), the
+ // HKDF-SHA256 KDF ID (0x0001), and a subset of the following AEAD IDs:
+ // AES-128-GCM (0x0000), AES-256-GCM (0x0001), ChaCha20Poly1305 (0x0002).
+ Config []byte
+ // PrivateKey should be a marshalled private key. Currently, we expect
+ // this to be the output of [ecdh.PrivateKey.Bytes].
+ PrivateKey []byte
+ // SendAsRetry indicates if Config should be sent as part of the list of
+ // retry configs when ECH is requested by the client but rejected by the
+ // server.
+ SendAsRetry bool
+}
+
+const (
+ // ticketKeyLifetime is how long a ticket key remains valid and can be used to
+ // resume a client connection.
+ ticketKeyLifetime = 7 * 24 * time.Hour // 7 days
+
+ // ticketKeyRotation is how often the server should rotate the session ticket key
+ // that is used for new tickets.
+ ticketKeyRotation = 24 * time.Hour
+)
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+ aesKey [16]byte
+ hmacKey [16]byte
+ // created is the time at which this ticket key was created. See Config.ticketKeys.
+ created time.Time
+}
+
+// ticketKeyFromBytes converts from the external representation of a session
+// ticket key to a ticketKey. Externally, session ticket keys are 32 random
+// bytes and this function expands that into sufficient name and key material.
+func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+ hashed := sha512.Sum512(b[:])
+ // The first 16 bytes of the hash used to be exposed on the wire as a ticket
+ // prefix. They MUST NOT be used as a secret. In the future, it would make
+ // sense to use a proper KDF here, like HKDF with a fixed salt.
+ const legacyTicketKeyNameLen = 16
+ copy(key.aesKey[:], hashed[legacyTicketKeyNameLen:])
+ copy(key.hmacKey[:], hashed[legacyTicketKeyNameLen+len(key.aesKey):])
+ key.created = c.time()
+ return key
+}
+
+// maxSessionTicketLifetime is the maximum allowed lifetime of a TLS 1.3 session
+// ticket, and the lifetime we set for all tickets we send.
+const maxSessionTicketLifetime = 7 * 24 * time.Hour
+
+// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a [Config] that is
+// being used concurrently by a TLS client or server.
+func (c *Config) Clone() *Config {
+ if c == nil {
+ return nil
+ }
+ c.mutex.RLock()
+ defer c.mutex.RUnlock()
+ return &Config{
+ Rand: c.Rand,
+ Time: c.Time,
+ Certificates: c.Certificates,
+ NameToCertificate: c.NameToCertificate,
+ GetCertificate: c.GetCertificate,
+ GetClientCertificate: c.GetClientCertificate,
+ GetConfigForClient: c.GetConfigForClient,
+ VerifyPeerCertificate: c.VerifyPeerCertificate,
+ VerifyConnection: c.VerifyConnection,
+ RootCAs: c.RootCAs,
+ NextProtos: c.NextProtos,
+ ApplicationSettings: c.ApplicationSettings,
+ ServerName: c.ServerName,
+ ClientAuth: c.ClientAuth,
+ ClientCAs: c.ClientCAs,
+ InsecureSkipVerify: c.InsecureSkipVerify,
+ InsecureSkipTimeVerify: c.InsecureSkipTimeVerify,
+ InsecureServerNameToVerify: c.InsecureServerNameToVerify,
+ OmitEmptyPsk: c.OmitEmptyPsk,
+ CipherSuites: c.CipherSuites,
+ PreferServerCipherSuites: c.PreferServerCipherSuites,
+ SessionTicketsDisabled: c.SessionTicketsDisabled,
+ SessionTicketKey: c.SessionTicketKey,
+ ClientSessionCache: c.ClientSessionCache,
+ UnwrapSession: c.UnwrapSession,
+ WrapSession: c.WrapSession,
+ MinVersion: c.MinVersion,
+ MaxVersion: c.MaxVersion,
+ CurvePreferences: c.CurvePreferences,
+ PQSignatureSchemesEnabled: c.PQSignatureSchemesEnabled, // [UTLS]
+ DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+ Renegotiation: c.Renegotiation,
+ KeyLogWriter: c.KeyLogWriter,
+ EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList,
+ EncryptedClientHelloRejectionVerify: c.EncryptedClientHelloRejectionVerify,
+ EncryptedClientHelloKeys: c.EncryptedClientHelloKeys,
+ sessionTicketKeys: c.sessionTicketKeys,
+ autoSessionTicketKeys: c.autoSessionTicketKeys,
+
+ PreferSkipResumptionOnNilExtension: c.PreferSkipResumptionOnNilExtension, // [UTLS]
+ }
+}
+
+// deprecatedSessionTicketKey is set as the prefix of SessionTicketKey if it was
+// randomized for backwards compatibility but is not in use.
+var deprecatedSessionTicketKey = []byte("DEPRECATED")
+
+// initLegacySessionTicketKeyRLocked ensures the legacy SessionTicketKey field is
+// randomized if empty, and that sessionTicketKeys is populated from it otherwise.
+func (c *Config) initLegacySessionTicketKeyRLocked() {
+ // Don't write if SessionTicketKey is already defined as our deprecated string,
+ // or if it is defined by the user but sessionTicketKeys is already set.
+ if c.SessionTicketKey != [32]byte{} &&
+ (bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) {
+ return
+ }
+
+ // We need to write some data, so get an exclusive lock and re-check any conditions.
+ c.mutex.RUnlock()
+ defer c.mutex.RLock()
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ if c.SessionTicketKey == [32]byte{} {
+ if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err))
+ }
+ // Write the deprecated prefix at the beginning so we know we created
+ // it. This key with the DEPRECATED prefix isn't used as an actual
+ // session ticket key, and is only randomized in case the application
+ // reuses it for some reason.
+ copy(c.SessionTicketKey[:], deprecatedSessionTicketKey)
+ } else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 {
+ c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)}
+ }
+
+}
+
+// ticketKeys returns the ticketKeys for this connection.
+// If configForClient has explicitly set keys, those will
+// be returned. Otherwise, the keys on c will be used and
+// may be rotated if auto-managed.
+// During rotation, any expired session ticket keys are deleted from
+// c.sessionTicketKeys. If the session ticket key that is currently
+// encrypting tickets (ie. the first ticketKey in c.sessionTicketKeys)
+// is not fresh, then a new session ticket key will be
+// created and prepended to c.sessionTicketKeys.
+func (c *Config) ticketKeys(configForClient *Config) []ticketKey {
+ // If the ConfigForClient callback returned a Config with explicitly set
+ // keys, use those, otherwise just use the original Config.
+ if configForClient != nil {
+ configForClient.mutex.RLock()
+ if configForClient.SessionTicketsDisabled {
+ return nil
+ }
+ configForClient.initLegacySessionTicketKeyRLocked()
+ if len(configForClient.sessionTicketKeys) != 0 {
+ ret := configForClient.sessionTicketKeys
+ configForClient.mutex.RUnlock()
+ return ret
+ }
+ configForClient.mutex.RUnlock()
+ }
+
+ c.mutex.RLock()
+ defer c.mutex.RUnlock()
+ if c.SessionTicketsDisabled {
+ return nil
+ }
+ c.initLegacySessionTicketKeyRLocked()
+ if len(c.sessionTicketKeys) != 0 {
+ return c.sessionTicketKeys
+ }
+ // Fast path for the common case where the key is fresh enough.
+ if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation {
+ return c.autoSessionTicketKeys
+ }
+
+ // autoSessionTicketKeys are managed by auto-rotation.
+ c.mutex.RUnlock()
+ defer c.mutex.RLock()
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ // Re-check the condition in case it changed since obtaining the new lock.
+ if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation {
+ var newKey [32]byte
+ if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil {
+ panic(fmt.Sprintf("unable to generate random session ticket key: %v", err))
+ }
+ valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1)
+ valid = append(valid, c.ticketKeyFromBytes(newKey))
+ for _, k := range c.autoSessionTicketKeys {
+ // While rotating the current key, also remove any expired ones.
+ if c.time().Sub(k.created) < ticketKeyLifetime {
+ valid = append(valid, k)
+ }
+ }
+ c.autoSessionTicketKeys = valid
+ }
+ return c.autoSessionTicketKeys
+}
+
+// SetSessionTicketKeys updates the session ticket keys for a server.
+//
+// The first key will be used when creating new tickets, while all keys can be
+// used for decrypting tickets. It is safe to call this function while the
+// server is running in order to rotate the session ticket keys. The function
+// will panic if keys is empty.
+//
+// Calling this function will turn off automatic session ticket key rotation.
+//
+// If multiple servers are terminating connections for the same host they should
+// all have the same session ticket keys. If the session ticket keys leaks,
+// previously recorded and future TLS connections using those keys might be
+// compromised.
+func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+ if len(keys) == 0 {
+ panic("tls: keys must have at least one key")
+ }
+
+ newKeys := make([]ticketKey, len(keys))
+ for i, bytes := range keys {
+ newKeys[i] = c.ticketKeyFromBytes(bytes)
+ }
+
+ c.mutex.Lock()
+ c.sessionTicketKeys = newKeys
+ c.mutex.Unlock()
+}
+
+func (c *Config) rand() io.Reader {
+ r := c.Rand
+ if r == nil {
+ return rand.Reader
+ }
+ return r
+}
+
+func (c *Config) time() time.Time {
+ t := c.Time
+ if t == nil {
+ t = time.Now
+ }
+ return t()
+}
+
+func (c *Config) cipherSuites() []uint16 {
+ if c.CipherSuites == nil {
+ // [uTLS] SECTION BEGIN
+ // if fips140tls.Required() {
+ // return defaultCipherSuitesFIPS
+ // }
+ // [uTLS] SECTION END
+ return defaultCipherSuites()
+ }
+ // [uTLS] SECTION BEGIN
+ // if fips140tls.Required() {
+ // cipherSuites := slices.Clone(c.CipherSuites)
+ // return slices.DeleteFunc(cipherSuites, func(id uint16) bool {
+ // return !slices.Contains(defaultCipherSuitesFIPS, id)
+ // })
+ // }
+ // [uTLS] SECTION END
+ return c.CipherSuites
+}
+
+var supportedVersions = []uint16{
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+}
+
+// roleClient and roleServer are meant to call supportedVersions and parents
+// with more readability at the callsite.
+const roleClient = true
+const roleServer = false
+
+// var tls10server = godebug.New("tls10server") // [UTLS] unsupported
+
+func (c *Config) supportedVersions(isClient bool) []uint16 {
+ versions := make([]uint16, 0, len(supportedVersions))
+ for _, v := range supportedVersions {
+ // [uTLS] SECTION BEGIN
+ // if fips140tls.Required() && !slices.Contains(defaultSupportedVersionsFIPS, v) {
+ // continue
+ // }
+ // [uTLS] SECTION END
+ if (c == nil || c.MinVersion == 0) && v < VersionTLS12 {
+ // [uTLS SECTION BEGIN]
+ // Disable unsupported godebug package
+ // if isClient || tls10server.Value() != "1" {
+ // continue
+ // }
+ if isClient {
+ continue
+ }
+ // [uTLS SECTION END]
+ }
+ if isClient && c.EncryptedClientHelloConfigList != nil && v < VersionTLS13 {
+ continue
+ }
+ if c != nil && c.MinVersion != 0 && v < c.MinVersion {
+ continue
+ }
+ if c != nil && c.MaxVersion != 0 && v > c.MaxVersion {
+ continue
+ }
+ versions = append(versions, v)
+ }
+ return versions
+}
+
+func (c *Config) maxSupportedVersion(isClient bool) uint16 {
+ supportedVersions := c.supportedVersions(isClient)
+ if len(supportedVersions) == 0 {
+ return 0
+ }
+ return supportedVersions[0]
+}
+
+// supportedVersionsFromMax returns a list of supported versions derived from a
+// legacy maximum version value. Note that only versions supported by this
+// library are returned. Any newer peer will use supportedVersions anyway.
+func supportedVersionsFromMax(maxVersion uint16) []uint16 {
+ versions := make([]uint16, 0, len(supportedVersions))
+ for _, v := range supportedVersions {
+ if v > maxVersion {
+ continue
+ }
+ versions = append(versions, v)
+ }
+ return versions
+}
+
+func (c *Config) curvePreferences(version uint16) []CurveID {
+ var curvePreferences []CurveID
+ // [uTLS] SECTION BEGIN
+ // if fips140tls.Required() {
+ // curvePreferences = slices.Clone(defaultCurvePreferencesFIPS)
+ // } else {
+ curvePreferences = defaultCurvePreferences()
+ // }
+ // [uTLS] SECTION END
+ if c != nil && len(c.CurvePreferences) != 0 {
+ curvePreferences = slices.DeleteFunc(curvePreferences, func(x CurveID) bool {
+ return !slices.Contains(c.CurvePreferences, x)
+ })
+ }
+ if version < VersionTLS13 {
+ curvePreferences = slices.DeleteFunc(curvePreferences, isTLS13OnlyKeyExchange)
+ }
+ return curvePreferences
+}
+
+func (c *Config) supportsCurve(version uint16, curve CurveID) bool {
+ for _, cc := range c.curvePreferences(version) {
+ if cc == curve {
+ return true
+ }
+ }
+ return false
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// versions of the peer. Priority is given to the peer preference order.
+func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) {
+ supportedVersions := c.supportedVersions(isClient)
+ for _, peerVersion := range peerVersions {
+ for _, v := range supportedVersions {
+ if v == peerVersion {
+ return v, true
+ }
+ }
+ }
+ return 0, false
+}
+
+// errNoCertificates should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/xtls/xray-core
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname errNoCertificates
+var errNoCertificates = errors.New("tls: no certificates configured")
+
+// getCertificate returns the best certificate for the given ClientHelloInfo,
+// defaulting to the first element of c.Certificates.
+func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
+ if c.GetCertificate != nil &&
+ (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
+ cert, err := c.GetCertificate(clientHello)
+ if cert != nil || err != nil {
+ return cert, err
+ }
+ }
+
+ if len(c.Certificates) == 0 {
+ return nil, errNoCertificates
+ }
+
+ if len(c.Certificates) == 1 {
+ // There's only one choice, so no point doing any work.
+ return &c.Certificates[0], nil
+ }
+
+ if c.NameToCertificate != nil {
+ name := strings.ToLower(clientHello.ServerName)
+ if cert, ok := c.NameToCertificate[name]; ok {
+ return cert, nil
+ }
+ if len(name) > 0 {
+ labels := strings.Split(name, ".")
+ labels[0] = "*"
+ wildcardName := strings.Join(labels, ".")
+ if cert, ok := c.NameToCertificate[wildcardName]; ok {
+ return cert, nil
+ }
+ }
+ }
+
+ for _, cert := range c.Certificates {
+ if err := clientHello.SupportsCertificate(&cert); err == nil {
+ return &cert, nil
+ }
+ }
+
+ // If nothing matches, return the first certificate.
+ return &c.Certificates[0], nil
+}
+
+// SupportsCertificate returns nil if the provided certificate is supported by
+// the client that sent the ClientHello. Otherwise, it returns an error
+// describing the reason for the incompatibility.
+//
+// If this [ClientHelloInfo] was passed to a GetConfigForClient or GetCertificate
+// callback, this method will take into account the associated [Config]. Note that
+// if GetConfigForClient returns a different [Config], the change can't be
+// accounted for by this method.
+//
+// This function will call x509.ParseCertificate unless c.Leaf is set, which can
+// incur a significant performance cost.
+func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
+ // Note we don't currently support certificate_authorities nor
+ // signature_algorithms_cert, and don't check the algorithms of the
+ // signatures on the chain (which anyway are a SHOULD, see RFC 8446,
+ // Section 4.4.2.2).
+
+ config := chi.config
+ if config == nil {
+ config = &Config{}
+ }
+ vers, ok := config.mutualVersion(roleServer, chi.SupportedVersions)
+ if !ok {
+ return errors.New("no mutually supported protocol versions")
+ }
+
+ // If the client specified the name they are trying to connect to, the
+ // certificate needs to be valid for it.
+ if chi.ServerName != "" {
+ x509Cert, err := c.leaf()
+ if err != nil {
+ return fmt.Errorf("failed to parse certificate: %w", err)
+ }
+ if err := x509Cert.VerifyHostname(chi.ServerName); err != nil {
+ return fmt.Errorf("certificate is not valid for requested server name: %w", err)
+ }
+ }
+
+ // supportsRSAFallback returns nil if the certificate and connection support
+ // the static RSA key exchange, and unsupported otherwise. The logic for
+ // supporting static RSA is completely disjoint from the logic for
+ // supporting signed key exchanges, so we just check it as a fallback.
+ supportsRSAFallback := func(unsupported error) error {
+ // TLS 1.3 dropped support for the static RSA key exchange.
+ if vers == VersionTLS13 {
+ return unsupported
+ }
+ // The static RSA key exchange works by decrypting a challenge with the
+ // RSA private key, not by signing, so check the PrivateKey implements
+ // crypto.Decrypter, like *rsa.PrivateKey does.
+ if priv, ok := c.PrivateKey.(crypto.Decrypter); ok {
+ if _, ok := priv.Public().(*rsa.PublicKey); !ok {
+ return unsupported
+ }
+ } else {
+ return unsupported
+ }
+ // Finally, there needs to be a mutual cipher suite that uses the static
+ // RSA key exchange instead of ECDHE.
+ rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+ if c.flags&suiteECDHE != 0 {
+ return false
+ }
+ if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+ return false
+ }
+ return true
+ })
+ if rsaCipherSuite == nil {
+ return unsupported
+ }
+ return nil
+ }
+
+ // If the client sent the signature_algorithms extension, ensure it supports
+ // schemes we can use with this certificate and TLS version.
+ if len(chi.SignatureSchemes) > 0 {
+ if _, err := selectSignatureScheme(vers, c, chi.SignatureSchemes); err != nil {
+ return supportsRSAFallback(err)
+ }
+ }
+
+ // In TLS 1.3 we are done because supported_groups is only relevant to the
+ // ECDHE computation, point format negotiation is removed, cipher suites are
+ // only relevant to the AEAD choice, and static RSA does not exist.
+ if vers == VersionTLS13 {
+ return nil
+ }
+
+ // The only signed key exchange we support is ECDHE.
+ if !supportsECDHE(config, vers, chi.SupportedCurves, chi.SupportedPoints) {
+ return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange"))
+ }
+
+ var ecdsaCipherSuite bool
+ if priv, ok := c.PrivateKey.(crypto.Signer); ok {
+ switch pub := priv.Public().(type) {
+ case *ecdsa.PublicKey:
+ var curve CurveID
+ switch pub.Curve {
+ case elliptic.P256():
+ curve = CurveP256
+ case elliptic.P384():
+ curve = CurveP384
+ case elliptic.P521():
+ curve = CurveP521
+ default:
+ return supportsRSAFallback(unsupportedCertificateError(c))
+ }
+ var curveOk bool
+ for _, c := range chi.SupportedCurves {
+ if c == curve && config.supportsCurve(vers, c) {
+ curveOk = true
+ break
+ }
+ }
+ if !curveOk {
+ return errors.New("client doesn't support certificate curve")
+ }
+ ecdsaCipherSuite = true
+ case ed25519.PublicKey:
+ if vers < VersionTLS12 || len(chi.SignatureSchemes) == 0 {
+ return errors.New("connection doesn't support Ed25519")
+ }
+ ecdsaCipherSuite = true
+ case *rsa.PublicKey:
+ default:
+ return supportsRSAFallback(unsupportedCertificateError(c))
+ }
+ } else {
+ return supportsRSAFallback(unsupportedCertificateError(c))
+ }
+
+ // Make sure that there is a mutually supported cipher suite that works with
+ // this certificate. Cipher suite selection will then apply the logic in
+ // reverse to pick it. See also serverHandshakeState.cipherSuiteOk.
+ cipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+ if c.flags&suiteECDHE == 0 {
+ return false
+ }
+ if c.flags&suiteECSign != 0 {
+ if !ecdsaCipherSuite {
+ return false
+ }
+ } else {
+ if ecdsaCipherSuite {
+ return false
+ }
+ }
+ if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+ return false
+ }
+ return true
+ })
+ if cipherSuite == nil {
+ return supportsRSAFallback(errors.New("client doesn't support any cipher suites compatible with the certificate"))
+ }
+
+ return nil
+}
+
+// SupportsCertificate returns nil if the provided certificate is supported by
+// the server that sent the CertificateRequest. Otherwise, it returns an error
+// describing the reason for the incompatibility.
+func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate) error {
+ if _, err := selectSignatureScheme(cri.Version, c, cri.SignatureSchemes); err != nil {
+ return err
+ }
+
+ if len(cri.AcceptableCAs) == 0 {
+ return nil
+ }
+
+ for j, cert := range c.Certificate {
+ x509Cert := c.Leaf
+ // Parse the certificate if this isn't the leaf node, or if
+ // chain.Leaf was nil.
+ if j != 0 || x509Cert == nil {
+ var err error
+ if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+ return fmt.Errorf("failed to parse certificate #%d in the chain: %w", j, err)
+ }
+ }
+
+ for _, ca := range cri.AcceptableCAs {
+ if bytes.Equal(x509Cert.RawIssuer, ca) {
+ return nil
+ }
+ }
+ }
+ return errors.New("chain is not signed by an acceptable CA")
+}
+
+// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
+// from the CommonName and SubjectAlternateName fields of each of the leaf
+// certificates.
+//
+// Deprecated: NameToCertificate only allows associating a single certificate
+// with a given name. Leave that field nil to let the library select the first
+// compatible chain from Certificates.
+func (c *Config) BuildNameToCertificate() {
+ c.NameToCertificate = make(map[string]*Certificate)
+ for i := range c.Certificates {
+ cert := &c.Certificates[i]
+ x509Cert, err := cert.leaf()
+ if err != nil {
+ continue
+ }
+ // If SANs are *not* present, some clients will consider the certificate
+ // valid for the name in the Common Name.
+ if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 {
+ c.NameToCertificate[x509Cert.Subject.CommonName] = cert
+ }
+ for _, san := range x509Cert.DNSNames {
+ c.NameToCertificate[san] = cert
+ }
+ }
+}
+
+const (
+ keyLogLabelTLS12 = "CLIENT_RANDOM"
+ keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
+ keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
+ keyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0"
+ keyLogLabelServerTraffic = "SERVER_TRAFFIC_SECRET_0"
+)
+
+func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
+ if c.KeyLogWriter == nil {
+ return nil
+ }
+
+ logLine := fmt.Appendf(nil, "%s %x %x\n", label, clientRandom, secret)
+
+ writerMutex.Lock()
+ _, err := c.KeyLogWriter.Write(logLine)
+ writerMutex.Unlock()
+
+ return err
+}
+
+// writerMutex protects all KeyLogWriters globally. It is rarely enabled,
+// and is only for debugging, so a global mutex saves space.
+var writerMutex sync.Mutex
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+ Certificate [][]byte
+ // PrivateKey contains the private key corresponding to the public key in
+ // Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
+ // For a server up to TLS 1.2, it can also implement crypto.Decrypter with
+ // an RSA PublicKey.
+ PrivateKey crypto.PrivateKey
+ // SupportedSignatureAlgorithms is an optional list restricting what
+ // signature algorithms the PrivateKey can be used for.
+ SupportedSignatureAlgorithms []SignatureScheme
+ // OCSPStaple contains an optional OCSP response which will be served
+ // to clients that request it.
+ OCSPStaple []byte
+ // SignedCertificateTimestamps contains an optional list of Signed
+ // Certificate Timestamps which will be served to clients that request it.
+ SignedCertificateTimestamps [][]byte
+ // Leaf is the parsed form of the leaf certificate, which may be initialized
+ // using x509.ParseCertificate to reduce per-handshake processing. If nil,
+ // the leaf certificate will be parsed as needed.
+ Leaf *x509.Certificate
+}
+
+// leaf returns the parsed leaf certificate, either from c.Leaf or by parsing
+// the corresponding c.Certificate[0].
+func (c *Certificate) leaf() (*x509.Certificate, error) {
+ if c.Leaf != nil {
+ return c.Leaf, nil
+ }
+ return x509.ParseCertificate(c.Certificate[0])
+}
+
+type handshakeMessage interface {
+ marshal() ([]byte, error)
+ unmarshal([]byte) bool
+}
+
+type handshakeMessageWithOriginalBytes interface {
+ handshakeMessage
+
+ // originalBytes should return the original bytes that were passed to
+ // unmarshal to create the message. If the message was not produced by
+ // unmarshal, it should return nil.
+ originalBytes() []byte
+}
+
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+ sync.Mutex
+
+ m map[string]*list.Element
+ q *list.List
+ capacity int
+}
+
+type lruSessionCacheEntry struct {
+ sessionKey string
+ state *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a [ClientSessionCache] with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+ const defaultSessionCacheCapacity = 64
+
+ if capacity < 1 {
+ capacity = defaultSessionCacheCapacity
+ }
+ return &lruSessionCache{
+ m: make(map[string]*list.Element),
+ q: list.New(),
+ capacity: capacity,
+ }
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache. If cs is nil, the entry
+// corresponding to sessionKey is removed from the cache instead.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ if cs == nil {
+ c.q.Remove(elem)
+ delete(c.m, sessionKey)
+ } else {
+ entry := elem.Value.(*lruSessionCacheEntry)
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ }
+ return
+ }
+
+ if c.q.Len() < c.capacity {
+ entry := &lruSessionCacheEntry{sessionKey, cs}
+ c.m[sessionKey] = c.q.PushFront(entry)
+ return
+ }
+
+ elem := c.q.Back()
+ entry := elem.Value.(*lruSessionCacheEntry)
+ delete(c.m, entry.sessionKey)
+ entry.sessionKey = sessionKey
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ c.m[sessionKey] = elem
+}
+
+// Get returns the [ClientSessionState] value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ c.q.MoveToFront(elem)
+ return elem.Value.(*lruSessionCacheEntry).state, true
+ }
+ return nil, false
+}
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+ return &emptyConfig
+}
+
+func unexpectedMessageError(wanted, got any) error {
+ return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
+
+// supportedSignatureAlgorithms returns the supported signature algorithms.
+func supportedSignatureAlgorithms() []SignatureScheme {
+ // [uTLS] SECTION BEGIN
+ // if !fips140tls.Required() {
+ return defaultSupportedSignatureAlgorithms
+ // }
+ // return defaultSupportedSignatureAlgorithmsFIPS
+ // [uTLS] SECTION END
+}
+
+func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool {
+ for _, s := range supportedSignatureAlgorithms {
+ if s == sigAlg {
+ return true
+ }
+ }
+ return false
+}
+
+// CertificateVerificationError is returned when certificate verification fails during the handshake.
+type CertificateVerificationError struct {
+ // UnverifiedCertificates and its contents should not be modified.
+ UnverifiedCertificates []*x509.Certificate
+ Err error
+}
+
+func (e *CertificateVerificationError) Error() string {
+ return fmt.Sprintf("tls: failed to verify certificate: %s", e.Err)
+}
+
+func (e *CertificateVerificationError) Unwrap() error {
+ return e.Err
+}
+
+// fipsAllowedChains returns chains that are allowed to be used in a TLS connection
+// based on the current fips140tls enforcement setting.
+//
+// If fips140tls is not required, the chains are returned as-is with no processing.
+// Otherwise, the returned chains are filtered to only those allowed by FIPS 140-3.
+// If this results in no chains it returns an error.
+func fipsAllowedChains(chains [][]*x509.Certificate) ([][]*x509.Certificate, error) {
+ if !fips140tls.Required() {
+ return chains, nil
+ }
+
+ permittedChains := make([][]*x509.Certificate, 0, len(chains))
+ for _, chain := range chains {
+ if fipsAllowChain(chain) {
+ permittedChains = append(permittedChains, chain)
+ }
+ }
+
+ if len(permittedChains) == 0 {
+ return nil, errors.New("tls: no FIPS compatible certificate chains found")
+ }
+
+ return permittedChains, nil
+}
+
+func fipsAllowChain(chain []*x509.Certificate) bool {
+ if len(chain) == 0 {
+ return false
+ }
+
+ for _, cert := range chain {
+ if !fipsAllowCert(cert) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func fipsAllowCert(c *x509.Certificate) bool {
+ // The key must be RSA 2048, RSA 3072, RSA 4096,
+ // or ECDSA P-256, P-384, P-521.
+ switch k := c.PublicKey.(type) {
+ case *rsa.PublicKey:
+ size := k.N.BitLen()
+ return size == 2048 || size == 3072 || size == 4096
+ case *ecdsa.PublicKey:
+ return k.Curve == elliptic.P256() || k.Curve == elliptic.P384() || k.Curve == elliptic.P521()
+ }
+
+ return false
+}
diff --git a/vendor/github.com/refraction-networking/utls/common_string.go b/vendor/github.com/refraction-networking/utls/common_string.go
new file mode 100644
index 00000000..e15dd488
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/common_string.go
@@ -0,0 +1,120 @@
+// Code generated by "stringer -linecomment -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT.
+
+package tls
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[PKCS1WithSHA256-1025]
+ _ = x[PKCS1WithSHA384-1281]
+ _ = x[PKCS1WithSHA512-1537]
+ _ = x[PSSWithSHA256-2052]
+ _ = x[PSSWithSHA384-2053]
+ _ = x[PSSWithSHA512-2054]
+ _ = x[ECDSAWithP256AndSHA256-1027]
+ _ = x[ECDSAWithP384AndSHA384-1283]
+ _ = x[ECDSAWithP521AndSHA512-1539]
+ _ = x[Ed25519-2055]
+ _ = x[PKCS1WithSHA1-513]
+ _ = x[ECDSAWithSHA1-515]
+}
+
+const (
+ _SignatureScheme_name_0 = "PKCS1WithSHA1"
+ _SignatureScheme_name_1 = "ECDSAWithSHA1"
+ _SignatureScheme_name_2 = "PKCS1WithSHA256"
+ _SignatureScheme_name_3 = "ECDSAWithP256AndSHA256"
+ _SignatureScheme_name_4 = "PKCS1WithSHA384"
+ _SignatureScheme_name_5 = "ECDSAWithP384AndSHA384"
+ _SignatureScheme_name_6 = "PKCS1WithSHA512"
+ _SignatureScheme_name_7 = "ECDSAWithP521AndSHA512"
+ _SignatureScheme_name_8 = "PSSWithSHA256PSSWithSHA384PSSWithSHA512Ed25519"
+)
+
+var (
+ _SignatureScheme_index_8 = [...]uint8{0, 13, 26, 39, 46}
+)
+
+func (i SignatureScheme) String() string {
+ switch {
+ case i == 513:
+ return _SignatureScheme_name_0
+ case i == 515:
+ return _SignatureScheme_name_1
+ case i == 1025:
+ return _SignatureScheme_name_2
+ case i == 1027:
+ return _SignatureScheme_name_3
+ case i == 1281:
+ return _SignatureScheme_name_4
+ case i == 1283:
+ return _SignatureScheme_name_5
+ case i == 1537:
+ return _SignatureScheme_name_6
+ case i == 1539:
+ return _SignatureScheme_name_7
+ case 2052 <= i && i <= 2055:
+ i -= 2052
+ return _SignatureScheme_name_8[_SignatureScheme_index_8[i]:_SignatureScheme_index_8[i+1]]
+ default:
+ return "SignatureScheme(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[CurveP256-23]
+ _ = x[CurveP384-24]
+ _ = x[CurveP521-25]
+ _ = x[X25519-29]
+ _ = x[X25519MLKEM768-4588]
+}
+
+const (
+ _CurveID_name_0 = "CurveP256CurveP384CurveP521"
+ _CurveID_name_1 = "X25519"
+ _CurveID_name_2 = "X25519MLKEM768"
+)
+
+var (
+ _CurveID_index_0 = [...]uint8{0, 9, 18, 27}
+)
+
+func (i CurveID) String() string {
+ switch {
+ case 23 <= i && i <= 25:
+ i -= 23
+ return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]]
+ case i == 29:
+ return _CurveID_name_1
+ case i == 4588:
+ return _CurveID_name_2
+ default:
+ return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[NoClientCert-0]
+ _ = x[RequestClientCert-1]
+ _ = x[RequireAnyClientCert-2]
+ _ = x[VerifyClientCertIfGiven-3]
+ _ = x[RequireAndVerifyClientCert-4]
+}
+
+const _ClientAuthType_name = "NoClientCertRequestClientCertRequireAnyClientCertVerifyClientCertIfGivenRequireAndVerifyClientCert"
+
+var _ClientAuthType_index = [...]uint8{0, 12, 29, 49, 72, 98}
+
+func (i ClientAuthType) String() string {
+ if i < 0 || i >= ClientAuthType(len(_ClientAuthType_index)-1) {
+ return "ClientAuthType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _ClientAuthType_name[_ClientAuthType_index[i]:_ClientAuthType_index[i+1]]
+}
diff --git a/vendor/github.com/refraction-networking/utls/conn.go b/vendor/github.com/refraction-networking/utls/conn.go
new file mode 100644
index 00000000..f761ccae
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/conn.go
@@ -0,0 +1,1701 @@
+// 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.
+
+// TLS low level connection and record layer
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto/cipher"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "net"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+ // constant
+ conn net.Conn
+ isClient bool
+ handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
+ quic *quicState // nil for non-QUIC connections
+
+ // isHandshakeComplete is true if the connection is currently transferring
+ // application data (i.e. is not currently processing a handshake).
+ // isHandshakeComplete is true implies handshakeErr == nil.
+ isHandshakeComplete atomic.Bool
+ // constant after handshake; protected by handshakeMutex
+ handshakeMutex sync.Mutex
+ handshakeErr error // error resulting from handshake
+ vers uint16 // TLS version
+ haveVers bool // version has been negotiated
+ config *Config // configuration passed to constructor
+ // handshakes counts the number of handshakes performed on the
+ // connection so far. If renegotiation is disabled then this is either
+ // zero or one.
+ handshakes int
+ extMasterSecret bool
+ didResume bool // whether this connection was a session resumption
+ didHRR bool // whether a HelloRetryRequest was sent/received
+ cipherSuite uint16
+ curveID CurveID
+ ocspResponse []byte // stapled OCSP response
+ scts [][]byte // signed certificate timestamps from server
+ peerCertificates []*x509.Certificate
+ // activeCertHandles contains the cache handles to certificates in
+ // peerCertificates that are used to track active references.
+ activeCertHandles []*activeCert
+ // verifiedChains contains the certificate chains that we built, as
+ // opposed to the ones presented by the server.
+ verifiedChains [][]*x509.Certificate
+ // serverName contains the server name indicated by the client, if any.
+ serverName string
+ // secureRenegotiation is true if the server echoed the secure
+ // renegotiation extension. (This is meaningless as a server because
+ // renegotiation is not supported in that case.)
+ secureRenegotiation bool
+ // ekm is a closure for exporting keying material.
+ ekm func(label string, context []byte, length int) ([]byte, error)
+ // resumptionSecret is the resumption_master_secret for handling
+ // or sending NewSessionTicket messages.
+ resumptionSecret []byte
+ echAccepted bool
+
+ // ticketKeys is the set of active session ticket keys for this
+ // connection. The first one is used to encrypt new tickets and
+ // all are tried to decrypt tickets.
+ ticketKeys []ticketKey
+
+ // clientFinishedIsFirst is true if the client sent the first Finished
+ // message during the most recent handshake. This is recorded because
+ // the first transmitted Finished message is the tls-unique
+ // channel-binding value.
+ clientFinishedIsFirst bool
+
+ // closeNotifyErr is any error from sending the alertCloseNotify record.
+ closeNotifyErr error
+ // closeNotifySent is true if the Conn attempted to send an
+ // alertCloseNotify record.
+ closeNotifySent bool
+
+ // clientFinished and serverFinished contain the Finished message sent
+ // by the client or server in the most recent handshake. This is
+ // retained to support the renegotiation extension and tls-unique
+ // channel-binding.
+ clientFinished [12]byte
+ serverFinished [12]byte
+
+ // clientProtocol is the negotiated ALPN protocol.
+ clientProtocol string
+
+ utls utlsConnExtraFields // [UTLS] used for extensive things such as ALPS, PSK, etc
+
+ // input/output
+ in, out halfConn
+ rawInput bytes.Buffer // raw input, starting with a record header
+ input bytes.Reader // application data waiting to be read, from rawInput.Next
+ hand bytes.Buffer // handshake data waiting to be read
+ buffering bool // whether records are buffered in sendBuf
+ sendBuf []byte // a buffer of records waiting to be sent
+
+ // bytesSent counts the bytes of application data sent.
+ // packetsSent counts packets.
+ bytesSent int64
+ packetsSent int64
+
+ // retryCount counts the number of consecutive non-advancing records
+ // received by Conn.readRecord. That is, records that neither advance the
+ // handshake, nor deliver application data. Protected by in.Mutex.
+ retryCount int
+
+ // activeCall indicates whether Close has been call in the low bit.
+ // the rest of the bits are the number of goroutines in Conn.Write.
+ activeCall atomic.Int32
+
+ tmp [16]byte
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+// SetDeadline sets the read and write deadlines associated with the connection.
+// A zero value for t means [Conn.Read] and [Conn.Write] will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetDeadline(t time.Time) error {
+ return c.conn.SetDeadline(t)
+}
+
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means [Conn.Read] will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ return c.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the write deadline on the underlying connection.
+// A zero value for t means [Conn.Write] will not time out.
+// After a [Conn.Write] has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ return c.conn.SetWriteDeadline(t)
+}
+
+// NetConn returns the underlying connection that is wrapped by c.
+// Note that writing to or reading from this connection directly will corrupt the
+// TLS session.
+func (c *Conn) NetConn() net.Conn {
+ return c.conn
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+ sync.Mutex
+
+ err error // first permanent error
+ version uint16 // protocol version
+ cipher any // cipher algorithm
+ mac hash.Hash
+ seq [8]byte // 64-bit sequence number
+
+ scratchBuf [13]byte // to avoid allocs; interface method args escape
+
+ nextCipher any // next encryption state
+ nextMac hash.Hash // next MAC algorithm
+
+ level QUICEncryptionLevel // current QUIC encryption level
+ trafficSecret []byte // current TLS 1.3 traffic secret
+}
+
+type permanentError struct {
+ err net.Error
+}
+
+func (e *permanentError) Error() string { return e.err.Error() }
+func (e *permanentError) Unwrap() error { return e.err }
+func (e *permanentError) Timeout() bool { return e.err.Timeout() }
+func (e *permanentError) Temporary() bool { return false }
+
+func (hc *halfConn) setErrorLocked(err error) error {
+ if e, ok := err.(net.Error); ok {
+ hc.err = &permanentError{err: e}
+ } else {
+ hc.err = err
+ }
+ return hc.err
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher any, mac hash.Hash) {
+ hc.version = version
+ hc.nextCipher = cipher
+ hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() error {
+ if hc.nextCipher == nil || hc.version == VersionTLS13 {
+ return alertInternalError
+ }
+ hc.cipher = hc.nextCipher
+ hc.mac = hc.nextMac
+ hc.nextCipher = nil
+ hc.nextMac = nil
+ for i := range hc.seq {
+ hc.seq[i] = 0
+ }
+ return nil
+}
+
+func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) {
+ hc.trafficSecret = secret
+ hc.level = level
+ key, iv := suite.trafficKey(secret)
+ hc.cipher = suite.aead(key, iv)
+ for i := range hc.seq {
+ hc.seq[i] = 0
+ }
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+ for i := 7; i >= 0; i-- {
+ hc.seq[i]++
+ if hc.seq[i] != 0 {
+ return
+ }
+ }
+
+ // Not allowed to let sequence number wrap.
+ // Instead, must renegotiate before it does.
+ // Not likely enough to bother.
+ panic("TLS: sequence number wraparound")
+}
+
+// explicitNonceLen returns the number of bytes of explicit nonce or IV included
+// in each record. Explicit nonces are present only in CBC modes after TLS 1.0
+// and in certain AEAD modes in TLS 1.2.
+func (hc *halfConn) explicitNonceLen() int {
+ if hc.cipher == nil {
+ return 0
+ }
+
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ return 0
+ case aead:
+ return c.explicitNonceLen()
+ case cbcMode:
+ // TLS 1.1 introduced a per-record explicit IV to fix the BEAST attack.
+ if hc.version >= VersionTLS11 {
+ return c.BlockSize()
+ }
+ return 0
+ default:
+ panic("unknown cipher type")
+ }
+}
+
+// extractPadding returns, in constant time, the length of the padding to remove
+// from the end of payload. It also returns a byte which is equal to 255 if the
+// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2.
+func extractPadding(payload []byte) (toRemove int, good byte) {
+ if len(payload) < 1 {
+ return 0, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good = byte(int32(^t) >> 31)
+
+ // The maximum possible padding length plus the actual length field
+ toCheck := 256
+ // The length of the padded data is public, so we can use an if here
+ if toCheck > len(payload) {
+ toCheck = len(payload)
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ // Zero the padding length on error. This ensures any unchecked bytes
+ // are included in the MAC. Otherwise, an attacker that could
+ // distinguish MAC failures from padding failures could mount an attack
+ // similar to POODLE in SSL 3.0: given a good ciphertext that uses a
+ // full block's worth of padding, replace the final block with another
+ // block. If the MAC check passed but the padding check failed, the
+ // last byte of that block decrypted to the block size.
+ //
+ // See also macAndPaddingGood logic below.
+ paddingLen &= good
+
+ toRemove = int(paddingLen) + 1
+ return
+}
+
+func roundUp(a, b int) int {
+ return a + (b-a%b)%b
+}
+
+// cbcMode is an interface for block ciphers using cipher block chaining.
+type cbcMode interface {
+ cipher.BlockMode
+ SetIV([]byte)
+}
+
+// decrypt authenticates and decrypts the record if protection is active at
+// this stage. The returned plaintext might overlap with the input.
+func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
+ var plaintext []byte
+ typ := recordType(record[0])
+ payload := record[recordHeaderLen:]
+
+ // In TLS 1.3, change_cipher_spec messages are to be ignored without being
+ // decrypted. See RFC 8446, Appendix D.4.
+ if hc.version == VersionTLS13 && typ == recordTypeChangeCipherSpec {
+ return payload, typ, nil
+ }
+
+ paddingGood := byte(255)
+ paddingLen := 0
+
+ explicitNonceLen := hc.explicitNonceLen()
+
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case aead:
+ if len(payload) < explicitNonceLen {
+ return nil, 0, alertBadRecordMAC
+ }
+ nonce := payload[:explicitNonceLen]
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
+ payload = payload[explicitNonceLen:]
+
+ var additionalData []byte
+ if hc.version == VersionTLS13 {
+ additionalData = record[:recordHeaderLen]
+ } else {
+ additionalData = append(hc.scratchBuf[:0], hc.seq[:]...)
+ additionalData = append(additionalData, record[:3]...)
+ n := len(payload) - c.Overhead()
+ additionalData = append(additionalData, byte(n>>8), byte(n))
+ }
+
+ var err error
+ plaintext, err = c.Open(payload[:0], nonce, payload, additionalData)
+ if err != nil {
+ return nil, 0, alertBadRecordMAC
+ }
+ case cbcMode:
+ blockSize := c.BlockSize()
+ minPayload := explicitNonceLen + roundUp(hc.mac.Size()+1, blockSize)
+ if len(payload)%blockSize != 0 || len(payload) < minPayload {
+ return nil, 0, alertBadRecordMAC
+ }
+
+ if explicitNonceLen > 0 {
+ c.SetIV(payload[:explicitNonceLen])
+ payload = payload[explicitNonceLen:]
+ }
+ c.CryptBlocks(payload, payload)
+
+ // In a limited attempt to protect against CBC padding oracles like
+ // Lucky13, the data past paddingLen (which is secret) is passed to
+ // the MAC function as extra data, to be fed into the HMAC after
+ // computing the digest. This makes the MAC roughly constant time as
+ // long as the digest computation is constant time and does not
+ // affect the subsequent write, modulo cache effects.
+ paddingLen, paddingGood = extractPadding(payload)
+ default:
+ panic("unknown cipher type")
+ }
+
+ if hc.version == VersionTLS13 {
+ if typ != recordTypeApplicationData {
+ return nil, 0, alertUnexpectedMessage
+ }
+ if len(plaintext) > maxPlaintext+1 {
+ return nil, 0, alertRecordOverflow
+ }
+ // Remove padding and find the ContentType scanning from the end.
+ for i := len(plaintext) - 1; i >= 0; i-- {
+ if plaintext[i] != 0 {
+ typ = recordType(plaintext[i])
+ plaintext = plaintext[:i]
+ break
+ }
+ if i == 0 {
+ return nil, 0, alertUnexpectedMessage
+ }
+ }
+ }
+ } else {
+ plaintext = payload
+ }
+
+ if hc.mac != nil {
+ macSize := hc.mac.Size()
+ if len(payload) < macSize {
+ return nil, 0, alertBadRecordMAC
+ }
+
+ n := len(payload) - macSize - paddingLen
+ n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 }
+ record[3] = byte(n >> 8)
+ record[4] = byte(n)
+ remoteMAC := payload[n : n+macSize]
+ localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
+
+ // This is equivalent to checking the MACs and paddingGood
+ // separately, but in constant-time to prevent distinguishing
+ // padding failures from MAC failures. Depending on what value
+ // of paddingLen was returned on bad padding, distinguishing
+ // bad MAC from bad padding can lead to an attack.
+ //
+ // See also the logic at the end of extractPadding.
+ macAndPaddingGood := subtle.ConstantTimeCompare(localMAC, remoteMAC) & int(paddingGood)
+ if macAndPaddingGood != 1 {
+ return nil, 0, alertBadRecordMAC
+ }
+
+ plaintext = payload[:n]
+ }
+
+ hc.incSeq()
+ return plaintext, typ, nil
+}
+
+// sliceForAppend extends the input slice by n bytes. head is the full extended
+// slice, while tail is the appended part. If the original slice has sufficient
+// capacity no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// encrypt encrypts payload, adding the appropriate nonce and/or MAC, and
+// appends it to record, which must already contain the record header.
+func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) {
+ if hc.cipher == nil {
+ return append(record, payload...), nil
+ }
+
+ var explicitNonce []byte
+ if explicitNonceLen := hc.explicitNonceLen(); explicitNonceLen > 0 {
+ record, explicitNonce = sliceForAppend(record, explicitNonceLen)
+ if _, isCBC := hc.cipher.(cbcMode); !isCBC && explicitNonceLen < 16 {
+ // The AES-GCM construction in TLS has an explicit nonce so that the
+ // nonce can be random. However, the nonce is only 8 bytes which is
+ // too small for a secure, random nonce. Therefore we use the
+ // sequence number as the nonce. The 3DES-CBC construction also has
+ // an 8 bytes nonce but its nonces must be unpredictable (see RFC
+ // 5246, Appendix F.3), forcing us to use randomness. That's not
+ // 3DES' biggest problem anyway because the birthday bound on block
+ // collision is reached first due to its similarly small block size
+ // (see the Sweet32 attack).
+ copy(explicitNonce, hc.seq[:])
+ } else {
+ if _, err := io.ReadFull(rand, explicitNonce); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ var dst []byte
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
+ record, dst = sliceForAppend(record, len(payload)+len(mac))
+ c.XORKeyStream(dst[:len(payload)], payload)
+ c.XORKeyStream(dst[len(payload):], mac)
+ case aead:
+ nonce := explicitNonce
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
+
+ if hc.version == VersionTLS13 {
+ record = append(record, payload...)
+
+ // Encrypt the actual ContentType and replace the plaintext one.
+ record = append(record, record[0])
+ record[0] = byte(recordTypeApplicationData)
+
+ n := len(payload) + 1 + c.Overhead()
+ record[3] = byte(n >> 8)
+ record[4] = byte(n)
+
+ record = c.Seal(record[:recordHeaderLen],
+ nonce, record[recordHeaderLen:], record[:recordHeaderLen])
+ } else {
+ additionalData := append(hc.scratchBuf[:0], hc.seq[:]...)
+ additionalData = append(additionalData, record[:recordHeaderLen]...)
+ record = c.Seal(record, nonce, payload, additionalData)
+ }
+ case cbcMode:
+ mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
+ blockSize := c.BlockSize()
+ plaintextLen := len(payload) + len(mac)
+ paddingLen := blockSize - plaintextLen%blockSize
+ record, dst = sliceForAppend(record, plaintextLen+paddingLen)
+ copy(dst, payload)
+ copy(dst[len(payload):], mac)
+ for i := plaintextLen; i < len(dst); i++ {
+ dst[i] = byte(paddingLen - 1)
+ }
+ if len(explicitNonce) > 0 {
+ c.SetIV(explicitNonce)
+ }
+ c.CryptBlocks(dst, dst)
+ default:
+ panic("unknown cipher type")
+ }
+
+ // Update length to include nonce, MAC and any block padding needed.
+ n := len(record) - recordHeaderLen
+ record[3] = byte(n >> 8)
+ record[4] = byte(n)
+ hc.incSeq()
+
+ return record, nil
+}
+
+// RecordHeaderError is returned when a TLS record header is invalid.
+type RecordHeaderError struct {
+ // Msg contains a human readable string that describes the error.
+ Msg string
+ // RecordHeader contains the five bytes of TLS record header that
+ // triggered the error.
+ RecordHeader [5]byte
+ // Conn provides the underlying net.Conn in the case that a client
+ // sent an initial handshake that didn't look like TLS.
+ // It is nil if there's already been a handshake or a TLS alert has
+ // been written to the connection.
+ Conn net.Conn
+}
+
+func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
+
+func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err RecordHeaderError) {
+ err.Msg = msg
+ err.Conn = conn
+ copy(err.RecordHeader[:], c.rawInput.Bytes())
+ return err
+}
+
+func (c *Conn) readRecord() error {
+ return c.readRecordOrCCS(false)
+}
+
+func (c *Conn) readChangeCipherSpec() error {
+ return c.readRecordOrCCS(true)
+}
+
+// readRecordOrCCS reads one or more TLS records from the connection and
+// updates the record layer state. Some invariants:
+// - c.in must be locked
+// - c.input must be empty
+//
+// During the handshake one and only one of the following will happen:
+// - c.hand grows
+// - c.in.changeCipherSpec is called
+// - an error is returned
+//
+// After the handshake one and only one of the following will happen:
+// - c.hand grows
+// - c.input is set
+// - an error is returned
+func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
+ if c.in.err != nil {
+ return c.in.err
+ }
+ handshakeComplete := c.isHandshakeComplete.Load()
+
+ // This function modifies c.rawInput, which owns the c.input memory.
+ if c.input.Len() != 0 {
+ return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with pending application data"))
+ }
+ c.input.Reset(nil)
+
+ if c.quic != nil {
+ return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with QUIC transport"))
+ }
+
+ // Read header, payload.
+ if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil {
+ // RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
+ // is an error, but popular web sites seem to do this, so we accept it
+ // if and only if at the record boundary.
+ if err == io.ErrUnexpectedEOF && c.rawInput.Len() == 0 {
+ err = io.EOF
+ }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.in.setErrorLocked(err)
+ }
+ return err
+ }
+ hdr := c.rawInput.Bytes()[:recordHeaderLen]
+ typ := recordType(hdr[0])
+
+ // No valid TLS record has a type of 0x80, however SSLv2 handshakes
+ // start with a uint16 length where the MSB is set and the first record
+ // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+ // an SSLv2 client.
+ if !handshakeComplete && typ == 0x80 {
+ c.sendAlert(alertProtocolVersion)
+ return c.in.setErrorLocked(c.newRecordHeaderError(nil, "unsupported SSLv2 handshake received"))
+ }
+
+ vers := uint16(hdr[1])<<8 | uint16(hdr[2])
+ expectedVers := c.vers
+ if expectedVers == VersionTLS13 {
+ // All TLS 1.3 records are expected to have 0x0303 (1.2) after
+ // the initial hello (RFC 8446 Section 5.1).
+ expectedVers = VersionTLS12
+ }
+ n := int(hdr[3])<<8 | int(hdr[4])
+ if c.haveVers && vers != expectedVers {
+ c.sendAlert(alertProtocolVersion)
+ msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, expectedVers)
+ return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
+ }
+ if !c.haveVers {
+ // First message, be extra suspicious: this might not be a TLS
+ // client. Bail out before reading a full 'body', if possible.
+ // The current max version is 3.3 so if the version is >= 16.0,
+ // it's probably not real.
+ if (typ != recordTypeAlert && typ != recordTypeHandshake) || vers >= 0x1000 {
+ return c.in.setErrorLocked(c.newRecordHeaderError(c.conn, "first record does not look like a TLS handshake"))
+ }
+ }
+ if c.vers == VersionTLS13 && n > maxCiphertextTLS13 || n > maxCiphertext {
+ c.sendAlert(alertRecordOverflow)
+ msg := fmt.Sprintf("oversized record received with length %d", n)
+ return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
+ }
+ if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.in.setErrorLocked(err)
+ }
+ return err
+ }
+
+ // Process message.
+ record := c.rawInput.Next(recordHeaderLen + n)
+ data, typ, err := c.in.decrypt(record)
+ if err != nil {
+ return c.in.setErrorLocked(c.sendAlert(err.(alert)))
+ }
+ if len(data) > maxPlaintext {
+ return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow))
+ }
+
+ // Application Data messages are always protected.
+ if c.in.cipher == nil && typ == recordTypeApplicationData {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ if typ != recordTypeAlert && typ != recordTypeChangeCipherSpec && len(data) > 0 {
+ // This is a state-advancing message: reset the retry count.
+ c.retryCount = 0
+ }
+
+ // Handshake messages MUST NOT be interleaved with other record types in TLS 1.3.
+ if c.vers == VersionTLS13 && typ != recordTypeHandshake && c.hand.Len() > 0 {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ switch typ {
+ default:
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+
+ case recordTypeAlert:
+ if c.quic != nil {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ if len(data) != 2 {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ if alert(data[1]) == alertCloseNotify {
+ return c.in.setErrorLocked(io.EOF)
+ }
+ if c.vers == VersionTLS13 {
+ return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+ }
+ switch data[0] {
+ case alertLevelWarning:
+ // Drop the record on the floor and retry.
+ return c.retryReadRecord(expectChangeCipherSpec)
+ case alertLevelError:
+ return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+ default:
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ case recordTypeChangeCipherSpec:
+ if len(data) != 1 || data[0] != 1 {
+ return c.in.setErrorLocked(c.sendAlert(alertDecodeError))
+ }
+ // Handshake messages are not allowed to fragment across the CCS.
+ if c.hand.Len() > 0 {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ // In TLS 1.3, change_cipher_spec records are ignored until the
+ // Finished. See RFC 8446, Appendix D.4. Note that according to Section
+ // 5, a server can send a ChangeCipherSpec before its ServerHello, when
+ // c.vers is still unset. That's not useful though and suspicious if the
+ // server then selects a lower protocol version, so don't allow that.
+ if c.vers == VersionTLS13 && !handshakeComplete {
+ return c.retryReadRecord(expectChangeCipherSpec)
+ }
+ if !expectChangeCipherSpec {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ if err := c.in.changeCipherSpec(); err != nil {
+ return c.in.setErrorLocked(c.sendAlert(err.(alert)))
+ }
+
+ case recordTypeApplicationData:
+ if !handshakeComplete || expectChangeCipherSpec {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ // Some OpenSSL servers send empty records in order to randomize the
+ // CBC IV. Ignore a limited number of empty records.
+ if len(data) == 0 {
+ return c.retryReadRecord(expectChangeCipherSpec)
+ }
+ // Note that data is owned by c.rawInput, following the Next call above,
+ // to avoid copying the plaintext. This is safe because c.rawInput is
+ // not read from or written to until c.input is drained.
+ c.input.Reset(data)
+
+ case recordTypeHandshake:
+ if len(data) == 0 || expectChangeCipherSpec {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ c.hand.Write(data)
+ }
+
+ return nil
+}
+
+// retryReadRecord recurs into readRecordOrCCS to drop a non-advancing record, like
+// a warning alert, empty application_data, or a change_cipher_spec in TLS 1.3.
+func (c *Conn) retryReadRecord(expectChangeCipherSpec bool) error {
+ c.retryCount++
+ if c.retryCount > maxUselessRecords {
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(errors.New("tls: too many ignored records"))
+ }
+ return c.readRecordOrCCS(expectChangeCipherSpec)
+}
+
+// atLeastReader reads from R, stopping with EOF once at least N bytes have been
+// read. It is different from an io.LimitedReader in that it doesn't cut short
+// the last Read call, and in that it considers an early EOF an error.
+type atLeastReader struct {
+ R io.Reader
+ N int64
+}
+
+func (r *atLeastReader) Read(p []byte) (int, error) {
+ if r.N <= 0 {
+ return 0, io.EOF
+ }
+ n, err := r.R.Read(p)
+ r.N -= int64(n) // won't underflow unless len(p) >= n > 9223372036854775809
+ if r.N > 0 && err == io.EOF {
+ return n, io.ErrUnexpectedEOF
+ }
+ if r.N <= 0 && err == nil {
+ return n, io.EOF
+ }
+ return n, err
+}
+
+// readFromUntil reads from r into c.rawInput until c.rawInput contains
+// at least n bytes or else returns an error.
+func (c *Conn) readFromUntil(r io.Reader, n int) error {
+ if c.rawInput.Len() >= n {
+ return nil
+ }
+ needs := n - c.rawInput.Len()
+ // There might be extra input waiting on the wire. Make a best effort
+ // attempt to fetch it so that it can be used in (*Conn).Read to
+ // "predict" closeNotify alerts.
+ c.rawInput.Grow(needs + bytes.MinRead)
+ _, err := c.rawInput.ReadFrom(&atLeastReader{r, int64(needs)})
+ return err
+}
+
+// sendAlertLocked sends a TLS alert message.
+func (c *Conn) sendAlertLocked(err alert) error {
+ if c.quic != nil {
+ return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+ }
+
+ switch err {
+ case alertNoRenegotiation, alertCloseNotify:
+ c.tmp[0] = alertLevelWarning
+ default:
+ c.tmp[0] = alertLevelError
+ }
+ c.tmp[1] = byte(err)
+
+ _, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2])
+ if err == alertCloseNotify {
+ // closeNotify is a special case in that it isn't an error.
+ return writeErr
+ }
+
+ return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+}
+
+// sendAlert sends a TLS alert message.
+func (c *Conn) sendAlert(err alert) error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ return c.sendAlertLocked(err)
+}
+
+const (
+ // tcpMSSEstimate is a conservative estimate of the TCP maximum segment
+ // size (MSS). A constant is used, rather than querying the kernel for
+ // the actual MSS, to avoid complexity. The value here is the IPv6
+ // minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
+ // bytes) and a TCP header with timestamps (32 bytes).
+ tcpMSSEstimate = 1208
+
+ // recordSizeBoostThreshold is the number of bytes of application data
+ // sent after which the TLS record size will be increased to the
+ // maximum.
+ recordSizeBoostThreshold = 128 * 1024
+)
+
+// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the
+// next application data record. There is the following trade-off:
+//
+// - For latency-sensitive applications, such as web browsing, each TLS
+// record should fit in one TCP segment.
+// - For throughput-sensitive applications, such as large file transfers,
+// larger TLS records better amortize framing and encryption overheads.
+//
+// A simple heuristic that works well in practice is to use small records for
+// the first 1MB of data, then use larger records for subsequent data, and
+// reset back to smaller records after the connection becomes idle. See "High
+// Performance Web Networking", Chapter 4, or:
+// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/
+//
+// In the interests of simplicity and determinism, this code does not attempt
+// to reset the record size once the connection is idle, however.
+func (c *Conn) maxPayloadSizeForWrite(typ recordType) int {
+ if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData {
+ return maxPlaintext
+ }
+
+ if c.bytesSent >= recordSizeBoostThreshold {
+ return maxPlaintext
+ }
+
+ // Subtract TLS overheads to get the maximum payload size.
+ payloadBytes := tcpMSSEstimate - recordHeaderLen - c.out.explicitNonceLen()
+ if c.out.cipher != nil {
+ switch ciph := c.out.cipher.(type) {
+ case cipher.Stream:
+ payloadBytes -= c.out.mac.Size()
+ case cipher.AEAD:
+ payloadBytes -= ciph.Overhead()
+ case cbcMode:
+ blockSize := ciph.BlockSize()
+ // The payload must fit in a multiple of blockSize, with
+ // room for at least one padding byte.
+ payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
+ // The MAC is appended before padding so affects the
+ // payload size directly.
+ payloadBytes -= c.out.mac.Size()
+ default:
+ panic("unknown cipher type")
+ }
+ }
+ if c.vers == VersionTLS13 {
+ payloadBytes-- // encrypted ContentType
+ }
+
+ // Allow packet growth in arithmetic progression up to max.
+ pkt := c.packetsSent
+ c.packetsSent++
+ if pkt > 1000 {
+ return maxPlaintext // avoid overflow in multiply below
+ }
+
+ n := payloadBytes * int(pkt+1)
+ if n > maxPlaintext {
+ n = maxPlaintext
+ }
+ return n
+}
+
+func (c *Conn) write(data []byte) (int, error) {
+ if c.buffering {
+ c.sendBuf = append(c.sendBuf, data...)
+ return len(data), nil
+ }
+
+ n, err := c.conn.Write(data)
+ c.bytesSent += int64(n)
+ return n, err
+}
+
+func (c *Conn) flush() (int, error) {
+ if len(c.sendBuf) == 0 {
+ return 0, nil
+ }
+
+ n, err := c.conn.Write(c.sendBuf)
+ c.bytesSent += int64(n)
+ c.sendBuf = nil
+ c.buffering = false
+ return n, err
+}
+
+// outBufPool pools the record-sized scratch buffers used by writeRecordLocked.
+var outBufPool = sync.Pool{
+ New: func() any {
+ return new([]byte)
+ },
+}
+
+// writeRecordLocked writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
+ if c.quic != nil {
+ if typ != recordTypeHandshake {
+ return 0, errors.New("tls: internal error: sending non-handshake message to QUIC transport")
+ }
+ c.quicWriteCryptoData(c.out.level, data)
+ if !c.buffering {
+ if _, err := c.flush(); err != nil {
+ return 0, err
+ }
+ }
+ return len(data), nil
+ }
+
+ outBufPtr := outBufPool.Get().(*[]byte)
+ outBuf := *outBufPtr
+ defer func() {
+ // You might be tempted to simplify this by just passing &outBuf to Put,
+ // but that would make the local copy of the outBuf slice header escape
+ // to the heap, causing an allocation. Instead, we keep around the
+ // pointer to the slice header returned by Get, which is already on the
+ // heap, and overwrite and return that.
+ *outBufPtr = outBuf
+ outBufPool.Put(outBufPtr)
+ }()
+
+ var n int
+ for len(data) > 0 {
+ m := len(data)
+ if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload {
+ m = maxPayload
+ }
+
+ _, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen)
+ outBuf[0] = byte(typ)
+ vers := c.vers
+ if vers == 0 {
+ // Some TLS servers fail if the record version is
+ // greater than TLS 1.0 for the initial ClientHello.
+ vers = VersionTLS10
+ } else if vers == VersionTLS13 {
+ // TLS 1.3 froze the record layer version to 1.2.
+ // See RFC 8446, Section 5.1.
+ vers = VersionTLS12
+ }
+ outBuf[1] = byte(vers >> 8)
+ outBuf[2] = byte(vers)
+ outBuf[3] = byte(m >> 8)
+ outBuf[4] = byte(m)
+
+ var err error
+ outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand())
+ if err != nil {
+ return n, err
+ }
+ if _, err := c.write(outBuf); err != nil {
+ return n, err
+ }
+ n += m
+ data = data[m:]
+ }
+
+ if typ == recordTypeChangeCipherSpec && c.vers != VersionTLS13 {
+ if err := c.out.changeCipherSpec(); err != nil {
+ return n, c.sendAlertLocked(err.(alert))
+ }
+ }
+
+ return n, nil
+}
+
+// writeHandshakeRecord writes a handshake message to the connection and updates
+// the record layer state. If transcript is non-nil the marshaled message is
+// written to it.
+func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ data, err := msg.marshal()
+ if err != nil {
+ return 0, err
+ }
+ if transcript != nil {
+ transcript.Write(data)
+ }
+
+ return c.writeRecordLocked(recordTypeHandshake, data)
+}
+
+// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
+// updates the record layer state.
+func (c *Conn) writeChangeCipherRecord() error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ _, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1})
+ return err
+}
+
+// readHandshakeBytes reads handshake data until c.hand contains at least n bytes.
+func (c *Conn) readHandshakeBytes(n int) error {
+ if c.quic != nil {
+ return c.quicReadHandshakeBytes(n)
+ }
+ for c.hand.Len() < n {
+ if err := c.readRecord(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// readHandshake reads the next handshake message from
+// the record layer. If transcript is non-nil, the message
+// is written to the passed transcriptHash.
+func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
+ if err := c.readHandshakeBytes(4); err != nil {
+ return nil, err
+ }
+ data := c.hand.Bytes()
+
+ maxHandshakeSize := maxHandshake
+ // hasVers indicates we're past the first message, forcing someone trying to
+ // make us just allocate a large buffer to at least do the initial part of
+ // the handshake first.
+ if c.haveVers && data[0] == typeCertificate {
+ // Since certificate messages are likely to be the only messages that
+ // can be larger than maxHandshake, we use a special limit for just
+ // those messages.
+ maxHandshakeSize = maxHandshakeCertificateMsg
+ }
+
+ n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if n > maxHandshakeSize {
+ c.sendAlertLocked(alertInternalError)
+ return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshakeSize))
+ }
+ if err := c.readHandshakeBytes(4 + n); err != nil {
+ return nil, err
+ }
+ data = c.hand.Next(4 + n)
+ return c.unmarshalHandshakeMessage(data, transcript)
+}
+
+func (c *Conn) unmarshalHandshakeMessage(data []byte, transcript transcriptHash) (handshakeMessage, error) {
+ var m handshakeMessage
+ switch data[0] {
+ case typeHelloRequest:
+ m = new(helloRequestMsg)
+ case typeClientHello:
+ m = new(clientHelloMsg)
+ case typeServerHello:
+ m = new(serverHelloMsg)
+ case typeNewSessionTicket:
+ if c.vers == VersionTLS13 {
+ m = new(newSessionTicketMsgTLS13)
+ } else {
+ m = new(newSessionTicketMsg)
+ }
+ case typeCertificate:
+ if c.vers == VersionTLS13 {
+ m = new(certificateMsgTLS13)
+ } else {
+ m = new(certificateMsg)
+ }
+ case typeCertificateRequest:
+ if c.vers == VersionTLS13 {
+ m = new(certificateRequestMsgTLS13)
+ } else {
+ m = &certificateRequestMsg{
+ hasSignatureAlgorithm: c.vers >= VersionTLS12,
+ }
+ }
+ case typeCertificateStatus:
+ m = new(certificateStatusMsg)
+ case typeServerKeyExchange:
+ m = new(serverKeyExchangeMsg)
+ case typeServerHelloDone:
+ m = new(serverHelloDoneMsg)
+ case typeClientKeyExchange:
+ m = new(clientKeyExchangeMsg)
+ case typeCertificateVerify:
+ m = &certificateVerifyMsg{
+ hasSignatureAlgorithm: c.vers >= VersionTLS12,
+ }
+ case typeFinished:
+ m = new(finishedMsg)
+ // [uTLS] Commented typeEncryptedExtensions to force
+ // utlsHandshakeMessageType to handle it
+ // case typeEncryptedExtensions:
+ // m = new(encryptedExtensionsMsg)
+ case typeEndOfEarlyData:
+ m = new(endOfEarlyDataMsg)
+ case typeKeyUpdate:
+ m = new(keyUpdateMsg)
+ default:
+ // [UTLS SECTION BEGINS]
+ var err error
+ m, err = c.utlsHandshakeMessageType(data[0]) // see u_conn.go
+ if err == nil {
+ break
+ }
+ // [UTLS SECTION ENDS]
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ // The handshake message unmarshalers
+ // expect to be able to keep references to data,
+ // so pass in a fresh copy that won't be overwritten.
+ data = append([]byte(nil), data...)
+
+ if !m.unmarshal(data) {
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ if transcript != nil {
+ transcript.Write(data)
+ }
+
+ return m, nil
+}
+
+var (
+ errShutdown = errors.New("tls: protocol is shutdown")
+)
+
+// Write writes data to the connection.
+//
+// As Write calls [Conn.Handshake], in order to prevent indefinite blocking a deadline
+// must be set for both [Conn.Read] and Write before Write is called when the handshake
+// has not yet completed. See [Conn.SetDeadline], [Conn.SetReadDeadline], and
+// [Conn.SetWriteDeadline].
+func (c *Conn) Write(b []byte) (int, error) {
+ // interlock with Close below
+ for {
+ x := c.activeCall.Load()
+ if x&1 != 0 {
+ return 0, net.ErrClosed
+ }
+ if c.activeCall.CompareAndSwap(x, x+2) {
+ break
+ }
+ }
+ defer c.activeCall.Add(-2)
+
+ if err := c.Handshake(); err != nil {
+ return 0, err
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if err := c.out.err; err != nil {
+ return 0, err
+ }
+
+ if !c.isHandshakeComplete.Load() {
+ return 0, alertInternalError
+ }
+
+ if c.closeNotifySent {
+ return 0, errShutdown
+ }
+
+ // TLS 1.0 is susceptible to a chosen-plaintext
+ // attack when using block mode ciphers due to predictable IVs.
+ // This can be prevented by splitting each Application Data
+ // record into two records, effectively randomizing the IV.
+ //
+ // https://www.openssl.org/~bodo/tls-cbc.txt
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=665814
+ // https://www.imperialviolet.org/2012/01/15/beastfollowup.html
+
+ var m int
+ if len(b) > 1 && c.vers == VersionTLS10 {
+ if _, ok := c.out.cipher.(cipher.BlockMode); ok {
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
+ if err != nil {
+ return n, c.out.setErrorLocked(err)
+ }
+ m, b = 1, b[1:]
+ }
+ }
+
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b)
+ return n + m, c.out.setErrorLocked(err)
+}
+
+// handleRenegotiation processes a HelloRequest handshake message.
+func (c *Conn) handleRenegotiation() error {
+ if c.vers == VersionTLS13 {
+ return errors.New("tls: internal error: unexpected renegotiation")
+ }
+
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ helloReq, ok := msg.(*helloRequestMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(helloReq, msg)
+ }
+
+ if !c.isClient {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+
+ switch c.config.Renegotiation {
+ case RenegotiateNever:
+ return c.sendAlert(alertNoRenegotiation)
+ case RenegotiateOnceAsClient:
+ if c.handshakes > 1 {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+ case RenegotiateFreelyAsClient:
+ // Ok.
+ default:
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: unknown Renegotiation value")
+ }
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ c.isHandshakeComplete.Store(false)
+ if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
+ c.handshakes++
+ }
+ return c.handshakeErr
+}
+
+// handlePostHandshakeMessage processes a handshake message arrived after the
+// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation.
+func (c *Conn) handlePostHandshakeMessage() error {
+ if c.vers != VersionTLS13 {
+ return c.handleRenegotiation()
+ }
+
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ c.retryCount++
+ if c.retryCount > maxUselessRecords {
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(errors.New("tls: too many non-advancing records"))
+ }
+
+ switch msg := msg.(type) {
+ case *newSessionTicketMsgTLS13:
+ return c.handleNewSessionTicket(msg)
+ case *keyUpdateMsg:
+ return c.handleKeyUpdate(msg)
+ }
+ // The QUIC layer is supposed to treat an unexpected post-handshake CertificateRequest
+ // as a QUIC-level PROTOCOL_VIOLATION error (RFC 9001, Section 4.4). Returning an
+ // unexpected_message alert here doesn't provide it with enough information to distinguish
+ // this condition from other unexpected messages. This is probably fine.
+ c.sendAlert(alertUnexpectedMessage)
+ return fmt.Errorf("tls: received unexpected handshake message of type %T", msg)
+}
+
+func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
+ if c.quic != nil {
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(errors.New("tls: received unexpected key update message"))
+ }
+
+ cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
+ if cipherSuite == nil {
+ return c.in.setErrorLocked(c.sendAlert(alertInternalError))
+ }
+
+ newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
+ c.in.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
+
+ if keyUpdate.updateRequested {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ msg := &keyUpdateMsg{}
+ msgBytes, err := msg.marshal()
+ if err != nil {
+ return err
+ }
+ _, err = c.writeRecordLocked(recordTypeHandshake, msgBytes)
+ if err != nil {
+ // Surface the error at the next write.
+ c.out.setErrorLocked(err)
+ return nil
+ }
+
+ newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret)
+ c.out.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
+ }
+
+ return nil
+}
+
+// Read reads data from the connection.
+//
+// As Read calls [Conn.Handshake], in order to prevent indefinite blocking a deadline
+// must be set for both Read and [Conn.Write] before Read is called when the handshake
+// has not yet completed. See [Conn.SetDeadline], [Conn.SetReadDeadline], and
+// [Conn.SetWriteDeadline].
+func (c *Conn) Read(b []byte) (int, error) {
+ if err := c.Handshake(); err != nil {
+ return 0, err
+ }
+ if len(b) == 0 {
+ // Put this after Handshake, in case people were calling
+ // Read(nil) for the side effect of the Handshake.
+ return 0, nil
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ for c.input.Len() == 0 {
+ if err := c.readRecord(); err != nil {
+ return 0, err
+ }
+ for c.hand.Len() > 0 {
+ if err := c.handlePostHandshakeMessage(); err != nil {
+ return 0, err
+ }
+ }
+ }
+
+ n, _ := c.input.Read(b)
+
+ // If a close-notify alert is waiting, read it so that we can return (n,
+ // EOF) instead of (n, nil), to signal to the HTTP response reading
+ // goroutine that the connection is now closed. This eliminates a race
+ // where the HTTP response reading goroutine would otherwise not observe
+ // the EOF until its next read, by which time a client goroutine might
+ // have already tried to reuse the HTTP connection for a new request.
+ // See https://golang.org/cl/76400046 and https://golang.org/issue/3514
+ if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
+ recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
+ if err := c.readRecord(); err != nil {
+ return n, err // will be io.EOF on closeNotify
+ }
+ }
+
+ return n, nil
+}
+
+// Close closes the connection.
+func (c *Conn) Close() error {
+ // Interlock with Conn.Write above.
+ var x int32
+ for {
+ x = c.activeCall.Load()
+ if x&1 != 0 {
+ return net.ErrClosed
+ }
+ if c.activeCall.CompareAndSwap(x, x|1) {
+ break
+ }
+ }
+ if x != 0 {
+ // io.Writer and io.Closer should not be used concurrently.
+ // If Close is called while a Write is currently in-flight,
+ // interpret that as a sign that this Close is really just
+ // being used to break the Write and/or clean up resources and
+ // avoid sending the alertCloseNotify, which may block
+ // waiting on handshakeMutex or the c.out mutex.
+ return c.conn.Close()
+ }
+
+ var alertErr error
+ if c.isHandshakeComplete.Load() {
+ if err := c.closeNotify(); err != nil {
+ alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
+ }
+ }
+
+ if err := c.conn.Close(); err != nil {
+ return err
+ }
+ return alertErr
+}
+
+var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete")
+
+// CloseWrite shuts down the writing side of the connection. It should only be
+// called once the handshake has completed and does not call CloseWrite on the
+// underlying connection. Most callers should just use [Conn.Close].
+func (c *Conn) CloseWrite() error {
+ if !c.isHandshakeComplete.Load() {
+ return errEarlyCloseWrite
+ }
+
+ return c.closeNotify()
+}
+
+func (c *Conn) closeNotify() error {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if !c.closeNotifySent {
+ // Set a Write Deadline to prevent possibly blocking forever.
+ c.SetWriteDeadline(time.Now().Add(time.Second * 5))
+ c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
+ c.closeNotifySent = true
+ // Any subsequent writes will fail.
+ c.SetWriteDeadline(time.Now())
+ }
+ return c.closeNotifyErr
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// Most uses of this package need not call Handshake explicitly: the
+// first [Conn.Read] or [Conn.Write] will call it automatically.
+//
+// For control over canceling or setting a timeout on a handshake, use
+// [Conn.HandshakeContext] or the [Dialer]'s DialContext method instead.
+//
+// In order to avoid denial of service attacks, the maximum RSA key size allowed
+// in certificates sent by either the TLS server or client is limited to 8192
+// bits. This limit can be overridden by setting tlsmaxrsasize in the GODEBUG
+// environment variable (e.g. GODEBUG=tlsmaxrsasize=4096).
+func (c *Conn) Handshake() error {
+ return c.HandshakeContext(context.Background())
+}
+
+// HandshakeContext runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// The provided Context must be non-nil. If the context is canceled before
+// the handshake is complete, the handshake is interrupted and an error is returned.
+// Once the handshake has completed, cancellation of the context will not affect the
+// connection.
+//
+// Most uses of this package need not call HandshakeContext explicitly: the
+// first [Conn.Read] or [Conn.Write] will call it automatically.
+func (c *Conn) HandshakeContext(ctx context.Context) error {
+ // Delegate to unexported method for named return
+ // without confusing documented signature.
+ return c.handshakeContext(ctx)
+}
+
+func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
+ // Fast sync/atomic-based exit if there is no handshake in flight and the
+ // last one succeeded without an error. Avoids the expensive context setup
+ // and mutex for most Read and Write calls.
+ if c.isHandshakeComplete.Load() {
+ return nil
+ }
+
+ handshakeCtx, cancel := context.WithCancel(ctx)
+ // Note: defer this before starting the "interrupter" goroutine
+ // so that we can tell the difference between the input being canceled and
+ // this cancellation. In the former case, we need to close the connection.
+ defer cancel()
+
+ if c.quic != nil {
+ c.quic.cancelc = handshakeCtx.Done()
+ c.quic.cancel = cancel
+ } else if ctx.Done() != nil {
+ // Start the "interrupter" goroutine, if this context might be canceled.
+ // (The background context cannot).
+ //
+ // The interrupter goroutine waits for the input context to be done and
+ // closes the connection if this happens before the function returns.
+ done := make(chan struct{})
+ interruptRes := make(chan error, 1)
+ defer func() {
+ close(done)
+ if ctxErr := <-interruptRes; ctxErr != nil {
+ // Return context error to user.
+ ret = ctxErr
+ }
+ }()
+ go func() {
+ select {
+ case <-handshakeCtx.Done():
+ // Close the connection, discarding the error
+ _ = c.conn.Close()
+ interruptRes <- handshakeCtx.Err()
+ case <-done:
+ interruptRes <- nil
+ }
+ }()
+ }
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ if err := c.handshakeErr; err != nil {
+ return err
+ }
+ if c.isHandshakeComplete.Load() {
+ return nil
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ c.handshakeErr = c.handshakeFn(handshakeCtx)
+ if c.handshakeErr == nil {
+ c.handshakes++
+ } else {
+ // If an error occurred during the handshake try to flush the
+ // alert that might be left in the buffer.
+ c.flush()
+ }
+
+ if c.handshakeErr == nil && !c.isHandshakeComplete.Load() {
+ c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
+ }
+ if c.handshakeErr != nil && c.isHandshakeComplete.Load() {
+ panic("tls: internal error: handshake returned an error but is marked successful")
+ }
+
+ if c.quic != nil {
+ if c.handshakeErr == nil {
+ c.quicHandshakeComplete()
+ // Provide the 1-RTT read secret now that the handshake is complete.
+ // The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing
+ // the handshake (RFC 9001, Section 5.7).
+ c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret)
+ } else {
+ var a alert
+ c.out.Lock()
+ if !errors.As(c.out.err, &a) {
+ a = alertInternalError
+ }
+ c.out.Unlock()
+ // Return an error which wraps both the handshake error and
+ // any alert error we may have sent, or alertInternalError
+ // if we didn't send an alert.
+ // Truncate the text of the alert to 0 characters.
+ c.handshakeErr = fmt.Errorf("%w%.0w", c.handshakeErr, AlertError(a))
+ }
+ close(c.quic.blockedc)
+ close(c.quic.signalc)
+ }
+
+ return c.handshakeErr
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ return c.connectionStateLocked()
+}
+
+// var tlsunsafeekm = godebug.New("tlsunsafeekm") // [uTLS] unsupportted
+
+func (c *Conn) connectionStateLocked() ConnectionState {
+ var state ConnectionState
+ state.HandshakeComplete = c.isHandshakeComplete.Load()
+ state.Version = c.vers
+ state.NegotiatedProtocol = c.clientProtocol
+ state.DidResume = c.didResume
+ state.testingOnlyDidHRR = c.didHRR
+ // c.curveID is not set on TLS 1.0–1.2 resumptions. Fix that before exposing it.
+ state.testingOnlyCurveID = c.curveID
+ state.NegotiatedProtocolIsMutual = true
+ state.ServerName = c.serverName
+ state.CipherSuite = c.cipherSuite
+ state.PeerCertificates = c.peerCertificates
+ state.VerifiedChains = c.verifiedChains
+ state.SignedCertificateTimestamps = c.scts
+ state.OCSPResponse = c.ocspResponse
+ if (!c.didResume || c.extMasterSecret) && c.vers != VersionTLS13 {
+ if c.clientFinishedIsFirst {
+ state.TLSUnique = c.clientFinished[:]
+ } else {
+ state.TLSUnique = c.serverFinished[:]
+ }
+ }
+ if c.config.Renegotiation != RenegotiateNever {
+ state.ekm = noEKMBecauseRenegotiation
+ } else if c.vers != VersionTLS13 && !c.extMasterSecret {
+ state.ekm = func(label string, context []byte, length int) ([]byte, error) {
+ // [uTLS SECTION START]
+ // Disabling unsupported godebug package
+ // if tlsunsafeekm.Value() == "1" {
+ // tlsunsafeekm.IncNonDefault()
+ // return c.ekm(label, context, length)
+ // }
+ // [uTLS SECTION END]
+ return noEKMBecauseNoEMS(label, context, length)
+ }
+ } else {
+ state.ekm = c.ekm
+ }
+ state.ECHAccepted = c.echAccepted
+ // [UTLS SECTION START]
+ c.utlsConnectionStateLocked(&state)
+ // [UTLS SECTION END]
+ return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ return c.ocspResponse
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host. If so, it returns nil; if not, it returns an error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if !c.isClient {
+ return errors.New("tls: VerifyHostname called on TLS server connection")
+ }
+ if !c.isHandshakeComplete.Load() {
+ return errors.New("tls: handshake has not yet been performed")
+ }
+ if len(c.verifiedChains) == 0 {
+ return errors.New("tls: handshake did not verify certificate chain")
+ }
+ return c.peerCertificates[0].VerifyHostname(host)
+}
diff --git a/vendor/github.com/refraction-networking/utls/defaults.go b/vendor/github.com/refraction-networking/utls/defaults.go
new file mode 100644
index 00000000..f36b6c42
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/defaults.go
@@ -0,0 +1,140 @@
+// 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.
+
+package tls
+
+import (
+ "slices"
+ _ "unsafe" // for linkname
+)
+
+// Defaults are collected in this file to allow distributions to more easily patch
+// them to apply local policies.
+
+// var tlsmlkem = godebug.New("tlsmlkem") [uTLS]
+
+// defaultCurvePreferences is the default set of supported key exchanges, as
+// well as the preference order.
+func defaultCurvePreferences() []CurveID {
+ // [uTLS section begins]
+ // if tlsmlkem.Value() == "0" {
+ // return []CurveID{X25519, CurveP256, CurveP384, CurveP521}
+ // }
+ // [uTLS section ends]
+
+ return []CurveID{X25519MLKEM768, X25519, CurveP256, CurveP384, CurveP521}
+}
+
+// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+
+// CertificateRequest. The two fields are merged to match with TLS 1.3.
+// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc.
+var defaultSupportedSignatureAlgorithms = []SignatureScheme{
+ PSSWithSHA256,
+ ECDSAWithP256AndSHA256,
+ Ed25519,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PKCS1WithSHA1,
+ ECDSAWithSHA1,
+}
+
+// [uTLS section begins]
+// var tlsrsakex = godebug.New("tlsrsakex")
+// var tls3des = godebug.New("tls3des")
+// [uTLS section ends]
+
+func defaultCipherSuites() []uint16 {
+ suites := slices.Clone(cipherSuitesPreferenceOrder)
+ return slices.DeleteFunc(suites, func(c uint16) bool {
+ return disabledCipherSuites[c] ||
+ // [uTLS section begins]
+ // tlsrsakex.Value() != "1" && rsaKexCiphers[c] ||
+ // tls3des.Value() != "1" && tdesCiphers[c]
+ rsaKexCiphers[c] ||
+ tdesCiphers[c]
+ // [uTLS section ends]
+ })
+}
+
+// defaultCipherSuitesTLS13 is also the preference order, since there are no
+// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as
+// cipherSuitesPreferenceOrder applies.
+//
+// defaultCipherSuitesTLS13 should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/quic-go/quic-go
+// - github.com/sagernet/quic-go
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname defaultCipherSuitesTLS13
+var defaultCipherSuitesTLS13 = []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+}
+
+// defaultCipherSuitesTLS13NoAES should be an internal detail,
+// but widely used packages access it using linkname.
+// Notable members of the hall of shame include:
+// - github.com/quic-go/quic-go
+// - github.com/sagernet/quic-go
+//
+// Do not remove or change the type signature.
+// See go.dev/issue/67401.
+//
+//go:linkname defaultCipherSuitesTLS13NoAES
+var defaultCipherSuitesTLS13NoAES = []uint16{
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+}
+
+// The FIPS-only policies below match BoringSSL's
+// ssl_compliance_policy_fips_202205, which is based on NIST SP 800-52r2.
+// https://cs.opensource.google/boringssl/boringssl/+/master:ssl/ssl_lib.cc;l=3289;drc=ea7a88fa
+
+var defaultSupportedVersionsFIPS = []uint16{
+ VersionTLS12,
+ VersionTLS13,
+}
+
+// defaultCurvePreferencesFIPS are the FIPS-allowed curves,
+// in preference order (most preferable first).
+var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384}
+
+// defaultSupportedSignatureAlgorithmsFIPS currently are a subset of
+// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
+var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ ECDSAWithP256AndSHA256,
+ PKCS1WithSHA384,
+ ECDSAWithP384AndSHA384,
+ PKCS1WithSHA512,
+}
+
+// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
+var defaultCipherSuitesFIPS = []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+}
+
+// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3.
+var defaultCipherSuitesTLS13FIPS = []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/LICENSE b/vendor/github.com/refraction-networking/utls/dicttls/LICENSE
new file mode 100644
index 00000000..6b3bea46
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/LICENSE
@@ -0,0 +1,28 @@
+BSD 3-Clause License
+
+Copyright (c) 2023, Gaukas Wang
+
+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.
+
+3. Neither the name of the copyright holder 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 HOLDER 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/refraction-networking/utls/dicttls/README.md b/vendor/github.com/refraction-networking/utls/dicttls/README.md
new file mode 100644
index 00000000..7a26134a
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/README.md
@@ -0,0 +1,12 @@
+# Dict TLS
+
+This is a vendored version of [godicttls](https://github.com/gaukas/godicttls)
+
+Below is a copy of the original README.md
+
+# godicttls
+Dictionary for TLS written in Go providing bidirectional mapping values to their names, plus enum convenience for values.
+
+Last Update with data fetched from [IANA](www.iana.org) in March 2023:
+- Transport Layer Security (TLS) Parameters [link](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml)
+- Transport Layer Security (TLS) Extensions [link](https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml)
\ No newline at end of file
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/alerts.go b/vendor/github.com/refraction-networking/utls/dicttls/alerts.go
new file mode 100644
index 00000000..ec1f4e7f
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/alerts.go
@@ -0,0 +1,118 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-6
+// last updated: March 2023
+
+const (
+ Alert_close_notify uint8 = 0
+ Alert_unexpected_message uint8 = 10
+ Alert_bad_record_mac uint8 = 20
+ Alert_decryption_failed uint8 = 21
+ Alert_record_overflow uint8 = 22
+ Alert_decompression_failure uint8 = 30
+ Alert_handshake_failure uint8 = 40
+ Alert_no_certificate uint8 = 41
+ Alert_bad_certificate uint8 = 42
+ Alert_unsupported_certificate uint8 = 43
+ Alert_certificate_revoked uint8 = 44
+ Alert_certificate_expired uint8 = 45
+ Alert_certificate_unknown uint8 = 46
+ Alert_illegal_parameter uint8 = 47
+ Alert_unknown_ca uint8 = 48
+ Alert_access_denied uint8 = 49
+ Alert_decode_error uint8 = 50
+ Alert_decrypt_error uint8 = 51
+ Alert_too_many_cids_requested uint8 = 52
+ Alert_export_restriction uint8 = 60
+ Alert_protocol_version uint8 = 70
+ Alert_insufficient_security uint8 = 71
+ Alert_internal_error uint8 = 80
+ Alert_inappropriate_fallback uint8 = 86
+ Alert_user_canceled uint8 = 90
+ Alert_no_renegotiation uint8 = 100
+ Alert_missing_extension uint8 = 109
+ Alert_unsupported_extension uint8 = 110
+ Alert_certificate_unobtainable uint8 = 111
+ Alert_unrecognized_name uint8 = 112
+ Alert_bad_certificate_status_response uint8 = 113
+ Alert_bad_certificate_hash_value uint8 = 114
+ Alert_unknown_psk_identity uint8 = 115
+ Alert_certificate_required uint8 = 116
+ Alert_no_application_protocol uint8 = 120
+)
+
+var DictAlertValueIndexed = map[uint8]string{
+ 0: "close_notify",
+ 10: "unexpected_message",
+ 20: "bad_record_mac",
+ 21: "decryption_failed",
+ 22: "record_overflow",
+ 30: "decompression_failure",
+ 40: "handshake_failure",
+ 41: "no_certificate",
+ 42: "bad_certificate",
+ 43: "unsupported_certificate",
+ 44: "certificate_revoked",
+ 45: "certificate_expired",
+ 46: "certificate_unknown",
+ 47: "illegal_parameter",
+ 48: "unknown_ca",
+ 49: "access_denied",
+ 50: "decode_error",
+ 51: "decrypt_error",
+ 52: "too_many_cids_requested",
+ 60: "export_restriction",
+ 70: "protocol_version",
+ 71: "insufficient_security",
+ 80: "internal_error",
+ 86: "inappropriate_fallback",
+ 90: "user_canceled",
+ 100: "no_renegotiation",
+ 109: "missing_extension",
+ 110: "unsupported_extension",
+ 111: "certificate_unobtainable",
+ 112: "unrecognized_name",
+ 113: "bad_certificate_status_response",
+ 114: "bad_certificate_hash_value",
+ 115: "unknown_psk_identity",
+ 116: "certificate_required",
+ 120: "no_application_protocol",
+}
+
+var DictAlertNameIndexed = map[string]uint8{
+ "close_notify": 0,
+ "unexpected_message": 10,
+ "bad_record_mac": 20,
+ "decryption_failed": 21,
+ "record_overflow": 22,
+ "decompression_failure": 30,
+ "handshake_failure": 40,
+ "no_certificate": 41,
+ "bad_certificate": 42,
+ "unsupported_certificate": 43,
+ "certificate_revoked": 44,
+ "certificate_expired": 45,
+ "certificate_unknown": 46,
+ "illegal_parameter": 47,
+ "unknown_ca": 48,
+ "access_denied": 49,
+ "decode_error": 50,
+ "decrypt_error": 51,
+ "too_many_cids_requested": 52,
+ "export_restriction": 60,
+ "protocol_version": 70,
+ "insufficient_security": 71,
+ "internal_error": 80,
+ "inappropriate_fallback": 86,
+ "user_canceled": 90,
+ "no_renegotiation": 100,
+ "missing_extension": 109,
+ "unsupported_extension": 110,
+ "certificate_unobtainable": 111,
+ "unrecognized_name": 112,
+ "bad_certificate_status_response": 113,
+ "bad_certificate_hash_value": 114,
+ "unknown_psk_identity": 115,
+ "certificate_required": 116,
+ "no_application_protocol": 120,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/authorization_data_formats.go b/vendor/github.com/refraction-networking/utls/dicttls/authorization_data_formats.go
new file mode 100644
index 00000000..5a1847e4
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/authorization_data_formats.go
@@ -0,0 +1,35 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#authorization-data
+// last updated: March 2023
+
+const (
+ AuthData_x509_attr_cert uint16 = 0
+ AuthData_saml_assertion uint16 = 1
+ AuthData_x509_attr_cert_url uint16 = 2
+ AuthData_saml_assertion_url uint16 = 3
+ AuthData_keynote_assertion_list uint16 = 64
+ AuthData_keynote_assertion_list_url uint16 = 65
+ AuthData_dtcp_authorization uint16 = 66
+)
+
+var DictAuthorizationDataFormatValueIndexed = map[uint16]string{
+ 0: "x509_attr_cert",
+ 1: "saml_assertion",
+ 2: "x509_attr_cert_url",
+ 3: "saml_assertion_url",
+ 64: "keynote_assertion_list",
+ 65: "keynote_assertion_list_url",
+ 66: "dtcp_authorization",
+}
+
+var DictAuthorizationDataFormatNameIndexed = map[string]uint16{
+ "x509_attr_cert": 0,
+ "saml_assertion": 1,
+ "x509_attr_cert_url": 2,
+ "saml_assertion_url": 3,
+ "Unassigned": 0,
+ "keynote_assertion_list": 64,
+ "keynote_assertion_list_url": 65,
+ "dtcp_authorization": 66,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/cachedinformationtype_values.go b/vendor/github.com/refraction-networking/utls/dicttls/cachedinformationtype_values.go
new file mode 100644
index 00000000..8e1469b1
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/cachedinformationtype_values.go
@@ -0,0 +1,19 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#cachedinformationtype
+// last updated: March 2023
+
+const (
+ CachedInformationType_cert uint8 = 1
+ CachedInformationType_cert_req uint8 = 2
+)
+
+var DictCachedInformationTypeValueIndexed = map[uint8]string{
+ 1: "cert",
+ 2: "cert_req",
+}
+
+var DictCachedInformationTypeNameIndexed = map[string]uint8{
+ "cert": 1,
+ "cert_req": 2,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/certificate_compression_algorithm_ids.go b/vendor/github.com/refraction-networking/utls/dicttls/certificate_compression_algorithm_ids.go
new file mode 100644
index 00000000..e5ffca3f
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/certificate_compression_algorithm_ids.go
@@ -0,0 +1,22 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-certificate-compression-algorithm-ids
+// last updated: March 2023
+
+const (
+ CertCompAlg_zlib uint16 = 1
+ CertCompAlg_brotli uint16 = 2
+ CertCompAlg_zstd uint16 = 3
+)
+
+var DictCertificateCompressionAlgorithmValueIndexed = map[uint16]string{
+ 1: "zlib",
+ 2: "brotli",
+ 3: "zstd",
+}
+
+var DictCertificateCompressionAlgorithmNameIndexed = map[string]uint16{
+ "zlib": 1,
+ "brotli": 2,
+ "zstd": 3,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/certificate_status_types.go b/vendor/github.com/refraction-networking/utls/dicttls/certificate_status_types.go
new file mode 100644
index 00000000..67e02852
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/certificate_status_types.go
@@ -0,0 +1,19 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#certificate-status
+// last updated: March 2023
+
+const (
+ CertStatusType_ocsp uint8 = 1
+ CertStatusType_ocsp_multi uint8 = 2
+)
+
+var DictCertificateStatusTypeValueIndexed = map[uint8]string{
+ 1: "ocsp",
+ 2: "ocsp_multi",
+}
+
+var DictCertificateStatusTypeNameIndexed = map[string]uint8{
+ "ocsp": 1,
+ "ocsp_multi": 2,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/certificte_types.go b/vendor/github.com/refraction-networking/utls/dicttls/certificte_types.go
new file mode 100644
index 00000000..93a3285a
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/certificte_types.go
@@ -0,0 +1,25 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-3
+// last updated: March 2023
+
+const (
+ CertType_X509 uint8 = 0
+ CertType_OpenPGP uint8 = 1
+ CertType_Raw_Public_Key uint8 = 2
+ CertType_1609Dot2 uint8 = 3
+)
+
+var DictCertificateTypeValueIndexed = map[uint8]string{
+ 0: "X509",
+ 1: "OpenPGP",
+ 2: "Raw Public Key",
+ 3: "1609Dot2",
+}
+
+var DictCertificateTypeNameIndexed = map[string]uint8{
+ "X509": 0,
+ "OpenPGP": 1,
+ "Raw Public Key": 2,
+ "1609Dot2": 3,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/cipher_suites.go b/vendor/github.com/refraction-networking/utls/dicttls/cipher_suites.go
new file mode 100644
index 00000000..d7875210
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/cipher_suites.go
@@ -0,0 +1,1084 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
+// last updated: March 2023
+
+const (
+ TLS_NULL_WITH_NULL_NULL uint16 = 0x0000
+ TLS_RSA_WITH_NULL_MD5 uint16 = 0x0001
+ TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
+ TLS_RSA_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0003
+ TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
+ TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x0006
+ TLS_RSA_WITH_IDEA_CBC_SHA uint16 = 0x0007
+ TLS_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0008
+ TLS_RSA_WITH_DES_CBC_SHA uint16 = 0x0009
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000A
+ TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000B
+ TLS_DH_DSS_WITH_DES_CBC_SHA uint16 = 0x000C
+ TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x000D
+ TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000E
+ TLS_DH_RSA_WITH_DES_CBC_SHA uint16 = 0x000F
+ TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0010
+ TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0011
+ TLS_DHE_DSS_WITH_DES_CBC_SHA uint16 = 0x0012
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x0013
+ TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0014
+ TLS_DHE_RSA_WITH_DES_CBC_SHA uint16 = 0x0015
+ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0016
+ TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0017
+ TLS_DH_anon_WITH_RC4_128_MD5 uint16 = 0x0018
+ TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0019
+ TLS_DH_anon_WITH_DES_CBC_SHA uint16 = 0x001A
+ TLS_DH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0x001B
+
+ TLS_KRB5_WITH_DES_CBC_SHA uint16 = 0x001E
+ TLS_KRB5_WITH_3DES_EDE_CBC_SHA uint16 = 0x001F
+ TLS_KRB5_WITH_RC4_128_SHA uint16 = 0x0020
+ TLS_KRB5_WITH_IDEA_CBC_SHA uint16 = 0x0021
+ TLS_KRB5_WITH_DES_CBC_MD5 uint16 = 0x0022
+ TLS_KRB5_WITH_3DES_EDE_CBC_MD5 uint16 = 0x0023
+ TLS_KRB5_WITH_RC4_128_MD5 uint16 = 0x0024
+ TLS_KRB5_WITH_IDEA_CBC_MD5 uint16 = 0x0025
+ TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA uint16 = 0x0026
+ TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA uint16 = 0x0027
+ TLS_KRB5_EXPORT_WITH_RC4_40_SHA uint16 = 0x0028
+ TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 uint16 = 0x0029
+ TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x002A
+ TLS_KRB5_EXPORT_WITH_RC4_40_MD5 uint16 = 0x002B
+ TLS_PSK_WITH_NULL_SHA uint16 = 0x002C
+ TLS_DHE_PSK_WITH_NULL_SHA uint16 = 0x002D
+ TLS_RSA_PSK_WITH_NULL_SHA uint16 = 0x002E
+ TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002F
+ TLS_DH_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0030
+ TLS_DH_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0031
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0032
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0033
+ TLS_DH_anon_WITH_AES_128_CBC_SHA uint16 = 0x0034
+ TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
+ TLS_DH_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0036
+ TLS_DH_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0037
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0038
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0039
+ TLS_DH_anon_WITH_AES_256_CBC_SHA uint16 = 0x003A
+ TLS_RSA_WITH_NULL_SHA256 uint16 = 0x003B
+ TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003C
+ TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003D
+ TLS_DH_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x003E
+ TLS_DH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003F
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x0040
+ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0041
+ TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0042
+ TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0043
+ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0044
+ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0045
+ TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0046
+
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
+ TLS_DH_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x0068
+ TLS_DH_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x0069
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x006A
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006B
+ TLS_DH_anon_WITH_AES_128_CBC_SHA256 uint16 = 0x006C
+ TLS_DH_anon_WITH_AES_256_CBC_SHA256 uint16 = 0x006D
+
+ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0084
+ TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0085
+ TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0086
+ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0087
+ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0088
+ TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0089
+ TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008A
+ TLS_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008B
+ TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008C
+ TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008D
+ TLS_DHE_PSK_WITH_RC4_128_SHA uint16 = 0x008E
+ TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008F
+ TLS_DHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0090
+ TLS_DHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0091
+ TLS_RSA_PSK_WITH_RC4_128_SHA uint16 = 0x0092
+ TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x0093
+ TLS_RSA_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0094
+ TLS_RSA_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0095
+ TLS_RSA_WITH_SEED_CBC_SHA uint16 = 0x0096
+ TLS_DH_DSS_WITH_SEED_CBC_SHA uint16 = 0x0097
+ TLS_DH_RSA_WITH_SEED_CBC_SHA uint16 = 0x0098
+ TLS_DHE_DSS_WITH_SEED_CBC_SHA uint16 = 0x0099
+ TLS_DHE_RSA_WITH_SEED_CBC_SHA uint16 = 0x009A
+ TLS_DH_anon_WITH_SEED_CBC_SHA uint16 = 0x009B
+ TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009C
+ TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009D
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009E
+ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009F
+ TLS_DH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x00A0
+ TLS_DH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x00A1
+ TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A2
+ TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A3
+ TLS_DH_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A4
+ TLS_DH_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A5
+ TLS_DH_anon_WITH_AES_128_GCM_SHA256 uint16 = 0x00A6
+ TLS_DH_anon_WITH_AES_256_GCM_SHA384 uint16 = 0x00A7
+ TLS_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00A8
+ TLS_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00A9
+ TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AA
+ TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AB
+ TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AC
+ TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AD
+ TLS_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00AE
+ TLS_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00AF
+ TLS_PSK_WITH_NULL_SHA256 uint16 = 0x00B0
+ TLS_PSK_WITH_NULL_SHA384 uint16 = 0x00B1
+ TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B2
+ TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B3
+ TLS_DHE_PSK_WITH_NULL_SHA256 uint16 = 0x00B4
+ TLS_DHE_PSK_WITH_NULL_SHA384 uint16 = 0x00B5
+ TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B6
+ TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B7
+ TLS_RSA_PSK_WITH_NULL_SHA256 uint16 = 0x00B8
+ TLS_RSA_PSK_WITH_NULL_SHA384 uint16 = 0x00B9
+ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BA
+ TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BB
+ TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BC
+ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BD
+ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BE
+ TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BF
+ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C0
+ TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C1
+ TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C2
+ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C3
+ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C4
+ TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C5
+ TLS_SM4_GCM_SM3 uint16 = 0x00C6
+ TLS_SM4_CCM_SM3 uint16 = 0x00C7
+
+ TLS_EMPTY_RENEGOTIATION_INFO_SCSV uint16 = 0x00FF
+
+ TLS_AES_128_GCM_SHA256 uint16 = 0x1301
+ TLS_AES_256_GCM_SHA384 uint16 = 0x1302
+ TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303
+ TLS_AES_128_CCM_SHA256 uint16 = 0x1304
+ TLS_AES_128_CCM_8_SHA256 uint16 = 0x1305
+ TLS_AEGIS_256_SHA384 uint16 = 0x1306
+ TLS_AEGIS_128L_SHA256 uint16 = 0x1307
+
+ TLS_FALLBACK_SCSV uint16 = 0x5600
+
+ TLS_ECDH_ECDSA_WITH_NULL_SHA uint16 = 0xC001
+ TLS_ECDH_ECDSA_WITH_RC4_128_SHA uint16 = 0xC002
+ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC003
+ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC004
+ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC005
+ TLS_ECDHE_ECDSA_WITH_NULL_SHA uint16 = 0xC006
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xC007
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC008
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC009
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC00A
+ TLS_ECDH_RSA_WITH_NULL_SHA uint16 = 0xC00B
+ TLS_ECDH_RSA_WITH_RC4_128_SHA uint16 = 0xC00C
+ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC00D
+ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC00E
+ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC00F
+ TLS_ECDHE_RSA_WITH_NULL_SHA uint16 = 0xC010
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xC011
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC012
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC013
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC014
+ TLS_ECDH_anon_WITH_NULL_SHA uint16 = 0xC015
+ TLS_ECDH_anon_WITH_RC4_128_SHA uint16 = 0xC016
+ TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0xC017
+ TLS_ECDH_anon_WITH_AES_128_CBC_SHA uint16 = 0xC018
+ TLS_ECDH_anon_WITH_AES_256_CBC_SHA uint16 = 0xC019
+ TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01A
+ TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01B
+ TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01C
+ TLS_SRP_SHA_WITH_AES_128_CBC_SHA uint16 = 0xC01D
+ TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC01E
+ TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA uint16 = 0xC01F
+ TLS_SRP_SHA_WITH_AES_256_CBC_SHA uint16 = 0xC020
+ TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC021
+ TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA uint16 = 0xC022
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC023
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC024
+ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC025
+ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC026
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC027
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC028
+ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC029
+ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC02A
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02B
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02C
+ TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02D
+ TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02E
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02F
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC030
+ TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC031
+ TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC032
+ TLS_ECDHE_PSK_WITH_RC4_128_SHA uint16 = 0xC033
+ TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0xC034
+ TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xC035
+ TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xC036
+ TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0xC037
+ TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0xC038
+ TLS_ECDHE_PSK_WITH_NULL_SHA uint16 = 0xC039
+ TLS_ECDHE_PSK_WITH_NULL_SHA256 uint16 = 0xC03A
+ TLS_ECDHE_PSK_WITH_NULL_SHA384 uint16 = 0xC03B
+ TLS_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03C
+ TLS_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03D
+ TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03E
+ TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03F
+ TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC040
+ TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC041
+ TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC042
+ TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC043
+ TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC044
+ TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC045
+ TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC046
+ TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC047
+ TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC048
+ TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC049
+ TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04A
+ TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04B
+ TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04C
+ TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04D
+ TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04E
+ TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04F
+ TLS_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC050
+ TLS_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC051
+ TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC052
+ TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC053
+ TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC054
+ TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC055
+ TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC056
+ TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC057
+ TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC058
+ TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC059
+ TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05A
+ TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05B
+ TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05C
+ TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05D
+ TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05E
+ TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05F
+ TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC060
+ TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC061
+ TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC062
+ TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC063
+ TLS_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC064
+ TLS_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC065
+ TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC066
+ TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC067
+ TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC068
+ TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC069
+ TLS_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06A
+ TLS_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06B
+ TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06C
+ TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06D
+ TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06E
+ TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06F
+ TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC070
+ TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC071
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC072
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC073
+ TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC074
+ TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC075
+ TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC076
+ TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC077
+ TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC078
+ TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC079
+ TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07A
+ TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07B
+ TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07C
+ TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07D
+ TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07E
+ TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07F
+ TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC080
+ TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC081
+ TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC082
+ TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC083
+ TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC084
+ TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC085
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC086
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC087
+ TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC088
+ TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC089
+ TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08A
+ TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08B
+ TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08C
+ TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08D
+ TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08E
+ TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08F
+ TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC090
+ TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC091
+ TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC092
+ TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC093
+ TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC094
+ TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC095
+ TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC096
+ TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC097
+ TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC098
+ TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC099
+ TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC09A
+ TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC09B
+ TLS_RSA_WITH_AES_128_CCM uint16 = 0xC09C
+ TLS_RSA_WITH_AES_256_CCM uint16 = 0xC09D
+ TLS_DHE_RSA_WITH_AES_128_CCM uint16 = 0xC09E
+ TLS_DHE_RSA_WITH_AES_256_CCM uint16 = 0xC09F
+ TLS_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A0
+ TLS_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A1
+ TLS_DHE_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A2
+ TLS_DHE_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A3
+ TLS_PSK_WITH_AES_128_CCM uint16 = 0xC0A4
+ TLS_PSK_WITH_AES_256_CCM uint16 = 0xC0A5
+ TLS_DHE_PSK_WITH_AES_128_CCM uint16 = 0xC0A6
+ TLS_DHE_PSK_WITH_AES_256_CCM uint16 = 0xC0A7
+ TLS_PSK_WITH_AES_128_CCM_8 uint16 = 0xC0A8
+ TLS_PSK_WITH_AES_256_CCM_8 uint16 = 0xC0A9
+ TLS_PSK_DHE_WITH_AES_128_CCM_8 uint16 = 0xC0AA
+ TLS_PSK_DHE_WITH_AES_256_CCM_8 uint16 = 0xC0AB
+ TLS_ECDHE_ECDSA_WITH_AES_128_CCM uint16 = 0xC0AC
+ TLS_ECDHE_ECDSA_WITH_AES_256_CCM uint16 = 0xC0AD
+ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 uint16 = 0xC0AE
+ TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 uint16 = 0xC0AF
+ TLS_ECCPWD_WITH_AES_128_GCM_SHA256 uint16 = 0xC0B0
+ TLS_ECCPWD_WITH_AES_256_GCM_SHA384 uint16 = 0xC0B1
+ TLS_ECCPWD_WITH_AES_128_CCM_SHA256 uint16 = 0xC0B2
+ TLS_ECCPWD_WITH_AES_256_CCM_SHA384 uint16 = 0xC0B3
+ TLS_SHA256_SHA256 uint16 = 0xC0B4
+ TLS_SHA384_SHA384 uint16 = 0xC0B5
+
+ TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC uint16 = 0xC100
+ TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC uint16 = 0xC101
+ TLS_GOSTR341112_256_WITH_28147_CNT_IMIT uint16 = 0xC102
+ TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L uint16 = 0xC103
+)
+
+var DictCipherSuiteValueIndexed = map[uint16]string{
+ 0x0000: "TLS_NULL_WITH_NULL_NULL",
+ 0x0001: "TLS_RSA_WITH_NULL_MD5",
+ 0x0002: "TLS_RSA_WITH_NULL_SHA",
+ 0x0003: "TLS_RSA_EXPORT_WITH_RC4_40_MD5",
+ 0x0004: "TLS_RSA_WITH_RC4_128_MD5",
+ 0x0005: "TLS_RSA_WITH_RC4_128_SHA",
+ 0x0006: "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
+ 0x0007: "TLS_RSA_WITH_IDEA_CBC_SHA",
+ 0x0008: "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ 0x0009: "TLS_RSA_WITH_DES_CBC_SHA",
+ 0x000A: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
+ 0x000B: "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ 0x000C: "TLS_DH_DSS_WITH_DES_CBC_SHA",
+ 0x000D: "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",
+ 0x000E: "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ 0x000F: "TLS_DH_RSA_WITH_DES_CBC_SHA",
+ 0x0010: "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",
+ 0x0011: "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ 0x0012: "TLS_DHE_DSS_WITH_DES_CBC_SHA",
+ 0x0013: "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+ 0x0014: "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ 0x0015: "TLS_DHE_RSA_WITH_DES_CBC_SHA",
+ 0x0016: "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ 0x0017: "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
+ 0x0018: "TLS_DH_anon_WITH_RC4_128_MD5",
+ 0x0019: "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+ 0x001A: "TLS_DH_anon_WITH_DES_CBC_SHA",
+ 0x001B: "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
+
+ 0x001E: "TLS_KRB5_WITH_DES_CBC_SHA",
+ 0x001F: "TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
+ 0x0020: "TLS_KRB5_WITH_RC4_128_SHA",
+ 0x0021: "TLS_KRB5_WITH_IDEA_CBC_SHA",
+ 0x0022: "TLS_KRB5_WITH_DES_CBC_MD5",
+ 0x0023: "TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
+ 0x0024: "TLS_KRB5_WITH_RC4_128_MD5",
+ 0x0025: "TLS_KRB5_WITH_IDEA_CBC_MD5",
+ 0x0026: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
+ 0x0027: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
+ 0x0028: "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
+ 0x0029: "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
+ 0x002A: "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
+ 0x002B: "TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
+ 0x002C: "TLS_PSK_WITH_NULL_SHA",
+ 0x002D: "TLS_DHE_PSK_WITH_NULL_SHA",
+ 0x002E: "TLS_RSA_PSK_WITH_NULL_SHA",
+ 0x002F: "TLS_RSA_WITH_AES_128_CBC_SHA",
+ 0x0030: "TLS_DH_DSS_WITH_AES_128_CBC_SHA",
+ 0x0031: "TLS_DH_RSA_WITH_AES_128_CBC_SHA",
+ 0x0032: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+ 0x0033: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+ 0x0034: "TLS_DH_anon_WITH_AES_128_CBC_SHA",
+ 0x0035: "TLS_RSA_WITH_AES_256_CBC_SHA",
+ 0x0036: "TLS_DH_DSS_WITH_AES_256_CBC_SHA",
+ 0x0037: "TLS_DH_RSA_WITH_AES_256_CBC_SHA",
+ 0x0038: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+ 0x0039: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+ 0x003A: "TLS_DH_anon_WITH_AES_256_CBC_SHA",
+ 0x003B: "TLS_RSA_WITH_NULL_SHA256",
+ 0x003C: "TLS_RSA_WITH_AES_128_CBC_SHA256",
+ 0x003D: "TLS_RSA_WITH_AES_256_CBC_SHA256",
+ 0x003E: "TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
+ 0x003F: "TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
+ 0x0040: "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+ 0x0041: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
+ 0x0042: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",
+ 0x0043: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",
+ 0x0044: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
+ 0x0045: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
+ 0x0046: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
+
+ 0x0067: "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+ 0x0068: "TLS_DH_DSS_WITH_AES_256_CBC_SHA256",
+ 0x0069: "TLS_DH_RSA_WITH_AES_256_CBC_SHA256",
+ 0x006A: "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+ 0x006B: "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+ 0x006C: "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
+ 0x006D: "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
+
+ 0x0084: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
+ 0x0085: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",
+ 0x0086: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",
+ 0x0087: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
+ 0x0088: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
+ 0x0089: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
+ 0x008A: "TLS_PSK_WITH_RC4_128_SHA",
+ 0x008B: "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
+ 0x008C: "TLS_PSK_WITH_AES_128_CBC_SHA",
+ 0x008D: "TLS_PSK_WITH_AES_256_CBC_SHA",
+ 0x008E: "TLS_DHE_PSK_WITH_RC4_128_SHA",
+ 0x008F: "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
+ 0x0090: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
+ 0x0091: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
+ 0x0092: "TLS_RSA_PSK_WITH_RC4_128_SHA",
+ 0x0093: "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
+ 0x0094: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
+ 0x0095: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA",
+ 0x0096: "TLS_RSA_WITH_SEED_CBC_SHA",
+ 0x0097: "TLS_DH_DSS_WITH_SEED_CBC_SHA",
+ 0x0098: "TLS_DH_RSA_WITH_SEED_CBC_SHA",
+ 0x0099: "TLS_DHE_DSS_WITH_SEED_CBC_SHA",
+ 0x009A: "TLS_DHE_RSA_WITH_SEED_CBC_SHA",
+ 0x009B: "TLS_DH_anon_WITH_SEED_CBC_SHA",
+ 0x009C: "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ 0x009D: "TLS_RSA_WITH_AES_256_GCM_SHA384",
+ 0x009E: "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+ 0x009F: "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+ 0x00A0: "TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
+ 0x00A1: "TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
+ 0x00A2: "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+ 0x00A3: "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
+ 0x00A4: "TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
+ 0x00A5: "TLS_DH_DSS_WITH_AES_256_GCM_SHA384",
+ 0x00A6: "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
+ 0x00A7: "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
+ 0x00A8: "TLS_PSK_WITH_AES_128_GCM_SHA256",
+ 0x00A9: "TLS_PSK_WITH_AES_256_GCM_SHA384",
+ 0x00AA: "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256",
+ 0x00AB: "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384",
+ 0x00AC: "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256",
+ 0x00AD: "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384",
+ 0x00AE: "TLS_PSK_WITH_AES_128_CBC_SHA256",
+ 0x00AF: "TLS_PSK_WITH_AES_256_CBC_SHA384",
+ 0x00B0: "TLS_PSK_WITH_NULL_SHA256",
+ 0x00B1: "TLS_PSK_WITH_NULL_SHA384",
+ 0x00B2: "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",
+ 0x00B3: "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",
+ 0x00B4: "TLS_DHE_PSK_WITH_NULL_SHA256",
+ 0x00B5: "TLS_DHE_PSK_WITH_NULL_SHA384",
+ 0x00B6: "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256",
+ 0x00B7: "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384",
+ 0x00B8: "TLS_RSA_PSK_WITH_NULL_SHA256",
+ 0x00B9: "TLS_RSA_PSK_WITH_NULL_SHA384",
+ 0x00BA: "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+ 0x00BB: "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256",
+ 0x00BC: "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+ 0x00BD: "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
+ 0x00BE: "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+ 0x00BF: "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
+ 0x00C0: "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
+ 0x00C1: "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256",
+ 0x00C2: "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256",
+ 0x00C3: "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
+ 0x00C4: "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
+ 0x00C5: "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
+ 0x00C6: "TLS_SM4_GCM_SM3",
+ 0x00C7: "TLS_SM4_CCM_SM3",
+
+ 0x00FF: "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
+
+ 0x1301: "TLS_AES_128_GCM_SHA256",
+ 0x1302: "TLS_AES_256_GCM_SHA384",
+ 0x1303: "TLS_CHACHA20_POLY1305_SHA256",
+ 0x1304: "TLS_AES_128_CCM_SHA256",
+ 0x1305: "TLS_AES_128_CCM_8_SHA256",
+ 0x1306: "TLS_AEGIS_256_SHA384",
+ 0x1307: "TLS_AEGIS_128L_SHA256",
+
+ 0x5600: "TLS_FALLBACK_SCSV",
+
+ 0xC001: "TLS_ECDH_ECDSA_WITH_NULL_SHA",
+ 0xC002: "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
+ 0xC003: "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
+ 0xC004: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+ 0xC005: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+ 0xC006: "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
+ 0xC007: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
+ 0xC008: "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+ 0xC009: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ 0xC00A: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ 0xC00B: "TLS_ECDH_RSA_WITH_NULL_SHA",
+ 0xC00C: "TLS_ECDH_RSA_WITH_RC4_128_SHA",
+ 0xC00D: "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
+ 0xC00E: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+ 0xC00F: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
+ 0xC010: "TLS_ECDHE_RSA_WITH_NULL_SHA",
+ 0xC011: "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
+ 0xC012: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ 0xC013: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ 0xC014: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ 0xC015: "TLS_ECDH_anon_WITH_NULL_SHA",
+ 0xC016: "TLS_ECDH_anon_WITH_RC4_128_SHA",
+ 0xC017: "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
+ 0xC018: "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
+ 0xC019: "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
+ 0xC01A: "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA",
+ 0xC01B: "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA",
+ 0xC01C: "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA",
+ 0xC01D: "TLS_SRP_SHA_WITH_AES_128_CBC_SHA",
+ 0xC01E: "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA",
+ 0xC01F: "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA",
+ 0xC020: "TLS_SRP_SHA_WITH_AES_256_CBC_SHA",
+ 0xC021: "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA",
+ 0xC022: "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA",
+ 0xC023: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+ 0xC024: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+ 0xC025: "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+ 0xC026: "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+ 0xC027: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+ 0xC028: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+ 0xC029: "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+ 0xC02A: "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
+ 0xC02B: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ 0xC02C: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ 0xC02D: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+ 0xC02E: "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+ 0xC02F: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ 0xC030: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ 0xC031: "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+ 0xC032: "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
+ 0xC033: "TLS_ECDHE_PSK_WITH_RC4_128_SHA",
+ 0xC034: "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
+ 0xC035: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
+ 0xC036: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
+ 0xC037: "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
+ 0xC038: "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
+ 0xC039: "TLS_ECDHE_PSK_WITH_NULL_SHA",
+ 0xC03A: "TLS_ECDHE_PSK_WITH_NULL_SHA256",
+ 0xC03B: "TLS_ECDHE_PSK_WITH_NULL_SHA384",
+ 0xC03C: "TLS_RSA_WITH_ARIA_128_CBC_SHA256",
+ 0xC03D: "TLS_RSA_WITH_ARIA_256_CBC_SHA384",
+ 0xC03E: "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256",
+ 0xC03F: "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384",
+ 0xC040: "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256",
+ 0xC041: "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384",
+ 0xC042: "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256",
+ 0xC043: "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384",
+ 0xC044: "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256",
+ 0xC045: "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384",
+ 0xC046: "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256",
+ 0xC047: "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384",
+ 0xC048: "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256",
+ 0xC049: "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384",
+ 0xC04A: "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256",
+ 0xC04B: "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384",
+ 0xC04C: "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256",
+ 0xC04D: "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384",
+ 0xC04E: "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256",
+ 0xC04F: "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384",
+ 0xC050: "TLS_RSA_WITH_ARIA_128_GCM_SHA256",
+ 0xC051: "TLS_RSA_WITH_ARIA_256_GCM_SHA384",
+ 0xC052: "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256",
+ 0xC053: "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384",
+ 0xC054: "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256",
+ 0xC055: "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384",
+ 0xC056: "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256",
+ 0xC057: "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384",
+ 0xC058: "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256",
+ 0xC059: "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384",
+ 0xC05A: "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256",
+ 0xC05B: "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384",
+ 0xC05C: "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256",
+ 0xC05D: "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384",
+ 0xC05E: "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256",
+ 0xC05F: "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384",
+ 0xC060: "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256",
+ 0xC061: "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384",
+ 0xC062: "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256",
+ 0xC063: "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384",
+ 0xC064: "TLS_PSK_WITH_ARIA_128_CBC_SHA256",
+ 0xC065: "TLS_PSK_WITH_ARIA_256_CBC_SHA384",
+ 0xC066: "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256",
+ 0xC067: "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384",
+ 0xC068: "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256",
+ 0xC069: "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384",
+ 0xC06A: "TLS_PSK_WITH_ARIA_128_GCM_SHA256",
+ 0xC06B: "TLS_PSK_WITH_ARIA_256_GCM_SHA384",
+ 0xC06C: "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256",
+ 0xC06D: "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384",
+ 0xC06E: "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256",
+ 0xC06F: "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384",
+ 0xC070: "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256",
+ 0xC071: "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384",
+ 0xC072: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC073: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC074: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC075: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC076: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC077: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC078: "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC079: "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC07A: "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC07B: "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC07C: "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC07D: "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC07E: "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC07F: "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC080: "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC081: "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC082: "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC083: "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC084: "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC085: "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC086: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC087: "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC088: "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC089: "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC08A: "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC08B: "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC08C: "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC08D: "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC08E: "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC08F: "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC090: "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC091: "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC092: "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256",
+ 0xC093: "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384",
+ 0xC094: "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC095: "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC096: "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC097: "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC098: "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC099: "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC09A: "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
+ 0xC09B: "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
+ 0xC09C: "TLS_RSA_WITH_AES_128_CCM",
+ 0xC09D: "TLS_RSA_WITH_AES_256_CCM",
+ 0xC09E: "TLS_DHE_RSA_WITH_AES_128_CCM",
+ 0xC09F: "TLS_DHE_RSA_WITH_AES_256_CCM",
+ 0xC0A0: "TLS_RSA_WITH_AES_128_CCM_8",
+ 0xC0A1: "TLS_RSA_WITH_AES_256_CCM_8",
+ 0xC0A2: "TLS_DHE_RSA_WITH_AES_128_CCM_8",
+ 0xC0A3: "TLS_DHE_RSA_WITH_AES_256_CCM_8",
+ 0xC0A4: "TLS_PSK_WITH_AES_128_CCM",
+ 0xC0A5: "TLS_PSK_WITH_AES_256_CCM",
+ 0xC0A6: "TLS_DHE_PSK_WITH_AES_128_CCM",
+ 0xC0A7: "TLS_DHE_PSK_WITH_AES_256_CCM",
+ 0xC0A8: "TLS_PSK_WITH_AES_128_CCM_8",
+ 0xC0A9: "TLS_PSK_WITH_AES_256_CCM_8",
+ 0xC0AA: "TLS_PSK_DHE_WITH_AES_128_CCM_8",
+ 0xC0AB: "TLS_PSK_DHE_WITH_AES_256_CCM_8",
+ 0xC0AC: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM",
+ 0xC0AD: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM",
+ 0xC0AE: "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",
+ 0xC0AF: "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",
+ 0xC0B0: "TLS_ECCPWD_WITH_AES_128_GCM_SHA256",
+ 0xC0B1: "TLS_ECCPWD_WITH_AES_256_GCM_SHA384",
+ 0xC0B2: "TLS_ECCPWD_WITH_AES_128_CCM_SHA256",
+ 0xC0B3: "TLS_ECCPWD_WITH_AES_256_CCM_SHA384",
+ 0xC0B4: "TLS_SHA256_SHA256",
+ 0xC0B5: "TLS_SHA384_SHA384",
+
+ 0xC100: "TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC",
+ 0xC101: "TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC",
+ 0xC102: "TLS_GOSTR341112_256_WITH_28147_CNT_IMIT",
+ 0xC103: "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L",
+ 0xC104: "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L",
+ 0xC105: "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S",
+ 0xC106: "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S",
+
+ 0xCCA8: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+ 0xCCA9: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+ 0xCCAA: "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+ 0xCCAB: "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256",
+ 0xCCAC: "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
+ 0xCCAD: "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256",
+ 0xCCAE: "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256",
+
+ 0xD001: "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256",
+ 0xD002: "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384",
+ 0xD003: "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256",
+ 0xD005: "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256",
+}
+
+var DictCipherSuiteNameIndexed = map[string]uint16{
+ "TLS_NULL_WITH_NULL_NULL": 0x0000,
+ "TLS_RSA_WITH_NULL_MD5": 0x0001,
+ "TLS_RSA_WITH_NULL_SHA": 0x0002,
+ "TLS_RSA_EXPORT_WITH_RC4_40_MD5": 0x0003,
+ "TLS_RSA_WITH_RC4_128_MD5": 0x0004,
+ "TLS_RSA_WITH_RC4_128_SHA": 0x0005,
+ "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5": 0x0006,
+ "TLS_RSA_WITH_IDEA_CBC_SHA": 0x0007,
+ "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA": 0x0008,
+ "TLS_RSA_WITH_DES_CBC_SHA": 0x0009,
+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA": 0x000A,
+ "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA": 0x000B,
+ "TLS_DH_DSS_WITH_DES_CBC_SHA": 0x000C,
+ "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA": 0x000D,
+ "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA": 0x000E,
+ "TLS_DH_RSA_WITH_DES_CBC_SHA": 0x000F,
+ "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA": 0x0010,
+ "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA": 0x0011,
+ "TLS_DHE_DSS_WITH_DES_CBC_SHA": 0x0012,
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA": 0x0013,
+ "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA": 0x0014,
+ "TLS_DHE_RSA_WITH_DES_CBC_SHA": 0x0015,
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA": 0x0016,
+ "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5": 0x0017,
+ "TLS_DH_anon_WITH_RC4_128_MD5": 0x0018,
+ "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA": 0x0019,
+ "TLS_DH_anon_WITH_DES_CBC_SHA": 0x001A,
+ "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA": 0x001B,
+
+ "TLS_KRB5_WITH_DES_CBC_SHA": 0x001E,
+ "TLS_KRB5_WITH_3DES_EDE_CBC_SHA": 0x001F,
+ "TLS_KRB5_WITH_RC4_128_SHA": 0x0020,
+ "TLS_KRB5_WITH_IDEA_CBC_SHA": 0x0021,
+ "TLS_KRB5_WITH_DES_CBC_MD5": 0x0022,
+ "TLS_KRB5_WITH_3DES_EDE_CBC_MD5": 0x0023,
+ "TLS_KRB5_WITH_RC4_128_MD5": 0x0024,
+ "TLS_KRB5_WITH_IDEA_CBC_MD5": 0x0025,
+ "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA": 0x0026,
+ "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA": 0x0027,
+ "TLS_KRB5_EXPORT_WITH_RC4_40_SHA": 0x0028,
+ "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5": 0x0029,
+ "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5": 0x002A,
+ "TLS_KRB5_EXPORT_WITH_RC4_40_MD5": 0x002B,
+ "TLS_PSK_WITH_NULL_SHA": 0x002C,
+ "TLS_DHE_PSK_WITH_NULL_SHA": 0x002D,
+ "TLS_RSA_PSK_WITH_NULL_SHA": 0x002E,
+ "TLS_RSA_WITH_AES_128_CBC_SHA": 0x002F,
+ "TLS_DH_DSS_WITH_AES_128_CBC_SHA": 0x0030,
+ "TLS_DH_RSA_WITH_AES_128_CBC_SHA": 0x0031,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA": 0x0032,
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA": 0x0033,
+ "TLS_DH_anon_WITH_AES_128_CBC_SHA": 0x0034,
+ "TLS_RSA_WITH_AES_256_CBC_SHA": 0x0035,
+ "TLS_DH_DSS_WITH_AES_256_CBC_SHA": 0x0036,
+ "TLS_DH_RSA_WITH_AES_256_CBC_SHA": 0x0037,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_SHA": 0x0038,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA": 0x0039,
+ "TLS_DH_anon_WITH_AES_256_CBC_SHA": 0x003A,
+ "TLS_RSA_WITH_NULL_SHA256": 0x003B,
+ "TLS_RSA_WITH_AES_128_CBC_SHA256": 0x003C,
+ "TLS_RSA_WITH_AES_256_CBC_SHA256": 0x003D,
+ "TLS_DH_DSS_WITH_AES_128_CBC_SHA256": 0x003E,
+ "TLS_DH_RSA_WITH_AES_128_CBC_SHA256": 0x003F,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256": 0x0040,
+ "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA": 0x0041,
+ "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA": 0x0042,
+ "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA": 0x0043,
+ "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA": 0x0044,
+ "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA": 0x0045,
+ "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA": 0x0046,
+
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256": 0x0067,
+ "TLS_DH_DSS_WITH_AES_256_CBC_SHA256": 0x0068,
+ "TLS_DH_RSA_WITH_AES_256_CBC_SHA256": 0x0069,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256": 0x006A,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256": 0x006B,
+ "TLS_DH_anon_WITH_AES_128_CBC_SHA256": 0x006C,
+ "TLS_DH_anon_WITH_AES_256_CBC_SHA256": 0x006D,
+
+ "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA": 0x0084,
+ "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA": 0x0085,
+ "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA": 0x0086,
+ "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA": 0x0087,
+ "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA": 0x0088,
+ "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA": 0x0089,
+ "TLS_PSK_WITH_RC4_128_SHA": 0x008A,
+ "TLS_PSK_WITH_3DES_EDE_CBC_SHA": 0x008B,
+ "TLS_PSK_WITH_AES_128_CBC_SHA": 0x008C,
+ "TLS_PSK_WITH_AES_256_CBC_SHA": 0x008D,
+ "TLS_DHE_PSK_WITH_RC4_128_SHA": 0x008E,
+ "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA": 0x008F,
+ "TLS_DHE_PSK_WITH_AES_128_CBC_SHA": 0x0090,
+ "TLS_DHE_PSK_WITH_AES_256_CBC_SHA": 0x0091,
+ "TLS_RSA_PSK_WITH_RC4_128_SHA": 0x0092,
+ "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA": 0x0093,
+ "TLS_RSA_PSK_WITH_AES_128_CBC_SHA": 0x0094,
+ "TLS_RSA_PSK_WITH_AES_256_CBC_SHA": 0x0095,
+ "TLS_RSA_WITH_SEED_CBC_SHA": 0x0096,
+ "TLS_DH_DSS_WITH_SEED_CBC_SHA": 0x0097,
+ "TLS_DH_RSA_WITH_SEED_CBC_SHA": 0x0098,
+ "TLS_DHE_DSS_WITH_SEED_CBC_SHA": 0x0099,
+ "TLS_DHE_RSA_WITH_SEED_CBC_SHA": 0x009A,
+ "TLS_DH_anon_WITH_SEED_CBC_SHA": 0x009B,
+ "TLS_RSA_WITH_AES_128_GCM_SHA256": 0x009C,
+ "TLS_RSA_WITH_AES_256_GCM_SHA384": 0x009D,
+ "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256": 0x009E,
+ "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384": 0x009F,
+ "TLS_DH_RSA_WITH_AES_128_GCM_SHA256": 0x00A0,
+ "TLS_DH_RSA_WITH_AES_256_GCM_SHA384": 0x00A1,
+ "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256": 0x00A2,
+ "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384": 0x00A3,
+ "TLS_DH_DSS_WITH_AES_128_GCM_SHA256": 0x00A4,
+ "TLS_DH_DSS_WITH_AES_256_GCM_SHA384": 0x00A5,
+ "TLS_DH_anon_WITH_AES_128_GCM_SHA256": 0x00A6,
+ "TLS_DH_anon_WITH_AES_256_GCM_SHA384": 0x00A7,
+ "TLS_PSK_WITH_AES_128_GCM_SHA256": 0x00A8,
+ "TLS_PSK_WITH_AES_256_GCM_SHA384": 0x00A9,
+ "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256": 0x00AA,
+ "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384": 0x00AB,
+ "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256": 0x00AC,
+ "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384": 0x00AD,
+ "TLS_PSK_WITH_AES_128_CBC_SHA256": 0x00AE,
+ "TLS_PSK_WITH_AES_256_CBC_SHA384": 0x00AF,
+ "TLS_PSK_WITH_NULL_SHA256": 0x00B0,
+ "TLS_PSK_WITH_NULL_SHA384": 0x00B1,
+ "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256": 0x00B2,
+ "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384": 0x00B3,
+ "TLS_DHE_PSK_WITH_NULL_SHA256": 0x00B4,
+ "TLS_DHE_PSK_WITH_NULL_SHA384": 0x00B5,
+ "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256": 0x00B6,
+ "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384": 0x00B7,
+ "TLS_RSA_PSK_WITH_NULL_SHA256": 0x00B8,
+ "TLS_RSA_PSK_WITH_NULL_SHA384": 0x00B9,
+ "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256": 0x00BA,
+ "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256": 0x00BB,
+ "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256": 0x00BC,
+ "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256": 0x00BD,
+ "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256": 0x00BE,
+ "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256": 0x00BF,
+ "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256": 0x00C0,
+ "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256": 0x00C1,
+ "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256": 0x00C2,
+ "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256": 0x00C3,
+ "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256": 0x00C4,
+ "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256": 0x00C5,
+ "TLS_SM4_GCM_SM3": 0x00C6,
+ "TLS_SM4_CCM_SM3": 0x00C7,
+
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV": 0x00FF,
+
+ "TLS_AES_128_GCM_SHA256": 0x1301,
+ "TLS_AES_256_GCM_SHA384": 0x1302,
+ "TLS_CHACHA20_POLY1305_SHA256": 0x1303,
+ "TLS_AES_128_CCM_SHA256": 0x1304,
+ "TLS_AES_128_CCM_8_SHA256": 0x1305,
+ "TLS_AEGIS_256_SHA384": 0x1306,
+ "TLS_AEGIS_128L_SHA256": 0x1307,
+
+ "TLS_FALLBACK_SCSV": 0x5600,
+
+ "TLS_ECDH_ECDSA_WITH_NULL_SHA": 0xC001,
+ "TLS_ECDH_ECDSA_WITH_RC4_128_SHA": 0xC002,
+ "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA": 0xC003,
+ "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA": 0xC004,
+ "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA": 0xC005,
+ "TLS_ECDHE_ECDSA_WITH_NULL_SHA": 0xC006,
+ "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": 0xC007,
+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA": 0xC008,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": 0xC009,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": 0xC00A,
+ "TLS_ECDH_RSA_WITH_NULL_SHA": 0xC00B,
+ "TLS_ECDH_RSA_WITH_RC4_128_SHA": 0xC00C,
+ "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA": 0xC00D,
+ "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA": 0xC00E,
+ "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA": 0xC00F,
+ "TLS_ECDHE_RSA_WITH_NULL_SHA": 0xC010,
+ "TLS_ECDHE_RSA_WITH_RC4_128_SHA": 0xC011,
+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": 0xC012,
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": 0xC013,
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": 0xC014,
+ "TLS_ECDH_anon_WITH_NULL_SHA": 0xC015,
+ "TLS_ECDH_anon_WITH_RC4_128_SHA": 0xC016,
+ "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA": 0xC017,
+ "TLS_ECDH_anon_WITH_AES_128_CBC_SHA": 0xC018,
+ "TLS_ECDH_anon_WITH_AES_256_CBC_SHA": 0xC019,
+ "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA": 0xC01A,
+ "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA": 0xC01B,
+ "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA": 0xC01C,
+ "TLS_SRP_SHA_WITH_AES_128_CBC_SHA": 0xC01D,
+ "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA": 0xC01E,
+ "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA": 0xC01F,
+ "TLS_SRP_SHA_WITH_AES_256_CBC_SHA": 0xC020,
+ "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA": 0xC021,
+ "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA": 0xC022,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": 0xC023,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384": 0xC024,
+ "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256": 0xC025,
+ "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384": 0xC026,
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": 0xC027,
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384": 0xC028,
+ "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256": 0xC029,
+ "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384": 0xC02A,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": 0xC02B,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": 0xC02C,
+ "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256": 0xC02D,
+ "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384": 0xC02E,
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": 0xC02F,
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": 0xC030,
+ "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256": 0xC031,
+ "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384": 0xC032,
+ "TLS_ECDHE_PSK_WITH_RC4_128_SHA": 0xC033,
+ "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA": 0xC034,
+ "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA": 0xC035,
+ "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA": 0xC036,
+ "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256": 0xC037,
+ "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384": 0xC038,
+ "TLS_ECDHE_PSK_WITH_NULL_SHA": 0xC039,
+ "TLS_ECDHE_PSK_WITH_NULL_SHA256": 0xC03A,
+ "TLS_ECDHE_PSK_WITH_NULL_SHA384": 0xC03B,
+ "TLS_RSA_WITH_ARIA_128_CBC_SHA256": 0xC03C,
+ "TLS_RSA_WITH_ARIA_256_CBC_SHA384": 0xC03D,
+ "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256": 0xC03E,
+ "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384": 0xC03F,
+ "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256": 0xC040,
+ "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384": 0xC041,
+ "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256": 0xC042,
+ "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384": 0xC043,
+ "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256": 0xC044,
+ "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384": 0xC045,
+ "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256": 0xC046,
+ "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384": 0xC047,
+ "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256": 0xC048,
+ "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384": 0xC049,
+ "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256": 0xC04A,
+ "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384": 0xC04B,
+ "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256": 0xC04C,
+ "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384": 0xC04D,
+ "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256": 0xC04E,
+ "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384": 0xC04F,
+ "TLS_RSA_WITH_ARIA_128_GCM_SHA256": 0xC050,
+ "TLS_RSA_WITH_ARIA_256_GCM_SHA384": 0xC051,
+ "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256": 0xC052,
+ "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384": 0xC053,
+ "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256": 0xC054,
+ "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384": 0xC055,
+ "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256": 0xC056,
+ "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384": 0xC057,
+ "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256": 0xC058,
+ "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384": 0xC059,
+ "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256": 0xC05A,
+ "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384": 0xC05B,
+ "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256": 0xC05C,
+ "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384": 0xC05D,
+ "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256": 0xC05E,
+ "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384": 0xC05F,
+ "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256": 0xC060,
+ "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384": 0xC061,
+ "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256": 0xC062,
+ "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384": 0xC063,
+ "TLS_PSK_WITH_ARIA_128_CBC_SHA256": 0xC064,
+ "TLS_PSK_WITH_ARIA_256_CBC_SHA384": 0xC065,
+ "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256": 0xC066,
+ "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384": 0xC067,
+ "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256": 0xC068,
+ "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384": 0xC069,
+ "TLS_PSK_WITH_ARIA_128_GCM_SHA256": 0xC06A,
+ "TLS_PSK_WITH_ARIA_256_GCM_SHA384": 0xC06B,
+ "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256": 0xC06C,
+ "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384": 0xC06D,
+ "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256": 0xC06E,
+ "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384": 0xC06F,
+ "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256": 0xC070,
+ "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384": 0xC071,
+ "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256": 0xC072,
+ "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384": 0xC073,
+ "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256": 0xC074,
+ "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384": 0xC075,
+ "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256": 0xC076,
+ "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384": 0xC077,
+ "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256": 0xC078,
+ "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384": 0xC079,
+ "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256": 0xC07A,
+ "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384": 0xC07B,
+ "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256": 0xC07C,
+ "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384": 0xC07D,
+ "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256": 0xC07E,
+ "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384": 0xC07F,
+ "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256": 0xC080,
+ "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384": 0xC081,
+ "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256": 0xC082,
+ "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384": 0xC083,
+ "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256": 0xC084,
+ "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384": 0xC085,
+ "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256": 0xC086,
+ "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384": 0xC087,
+ "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256": 0xC088,
+ "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384": 0xC089,
+ "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256": 0xC08A,
+ "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384": 0xC08B,
+ "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256": 0xC08C,
+ "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384": 0xC08D,
+ "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256": 0xC08E,
+ "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384": 0xC08F,
+ "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256": 0xC090,
+ "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384": 0xC091,
+ "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256": 0xC092,
+ "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384": 0xC093,
+ "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256": 0xC094,
+ "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384": 0xC095,
+ "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256": 0xC096,
+ "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384": 0xC097,
+ "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256": 0xC098,
+ "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384": 0xC099,
+ "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256": 0xC09A,
+ "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384": 0xC09B,
+ "TLS_RSA_WITH_AES_128_CCM": 0xC09C,
+ "TLS_RSA_WITH_AES_256_CCM": 0xC09D,
+ "TLS_DHE_RSA_WITH_AES_128_CCM": 0xC09E,
+ "TLS_DHE_RSA_WITH_AES_256_CCM": 0xC09F,
+ "TLS_RSA_WITH_AES_128_CCM_8": 0xC0A0,
+ "TLS_RSA_WITH_AES_256_CCM_8": 0xC0A1,
+ "TLS_DHE_RSA_WITH_AES_128_CCM_8": 0xC0A2,
+ "TLS_DHE_RSA_WITH_AES_256_CCM_8": 0xC0A3,
+ "TLS_PSK_WITH_AES_128_CCM": 0xC0A4,
+ "TLS_PSK_WITH_AES_256_CCM": 0xC0A5,
+ "TLS_DHE_PSK_WITH_AES_128_CCM": 0xC0A6,
+ "TLS_DHE_PSK_WITH_AES_256_CCM": 0xC0A7,
+ "TLS_PSK_WITH_AES_128_CCM_8": 0xC0A8,
+ "TLS_PSK_WITH_AES_256_CCM_8": 0xC0A9,
+ "TLS_PSK_DHE_WITH_AES_128_CCM_8": 0xC0AA,
+ "TLS_PSK_DHE_WITH_AES_256_CCM_8": 0xC0AB,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CCM": 0xC0AC,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CCM": 0xC0AD,
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8": 0xC0AE,
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8": 0xC0AF,
+ "TLS_ECCPWD_WITH_AES_128_GCM_SHA256": 0xC0B0,
+ "TLS_ECCPWD_WITH_AES_256_GCM_SHA384": 0xC0B1,
+ "TLS_ECCPWD_WITH_AES_128_CCM_SHA256": 0xC0B2,
+ "TLS_ECCPWD_WITH_AES_256_CCM_SHA384": 0xC0B3,
+ "TLS_SHA256_SHA256": 0xC0B4,
+ "TLS_SHA384_SHA384": 0xC0B5,
+
+ "TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC": 0xC100,
+ "TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC": 0xC101,
+ "TLS_GOSTR341112_256_WITH_28147_CNT_IMIT": 0xC102,
+ "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L": 0xC103,
+ "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L": 0xC104,
+ "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S": 0xC105,
+ "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S": 0xC106,
+
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": 0xCCA8,
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": 0xCCA9,
+ "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256": 0xCCAA,
+ "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256": 0xCCAB,
+ "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256": 0xCCAC,
+ "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256": 0xCCAD,
+ "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256": 0xCCAE,
+
+ "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256": 0xD001,
+ "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384": 0xD002,
+ "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256": 0xD003,
+
+ "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256": 0xD005,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/clientcertificatetype_identifiers.go b/vendor/github.com/refraction-networking/utls/dicttls/clientcertificatetype_identifiers.go
new file mode 100644
index 00000000..c022bfdc
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/clientcertificatetype_identifiers.go
@@ -0,0 +1,49 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-2
+// last updated: March 2023
+
+const (
+ ClientCertTypeIdentifier_rsa_sign uint8 = 1
+ ClientCertTypeIdentifier_dss_sign uint8 = 2
+ ClientCertTypeIdentifier_rsa_fixed_dh uint8 = 3
+ ClientCertTypeIdentifier_dss_fixed_dh uint8 = 4
+ ClientCertTypeIdentifier_rsa_ephemeral_dh uint8 = 5
+ ClientCertTypeIdentifier_dss_ephemeral_dh uint8 = 6
+ ClientCertTypeIdentifier_fortezza_dms uint8 = 20
+ ClientCertTypeIdentifier_ecdsa_sign uint8 = 64
+ ClientCertTypeIdentifier_rsa_fixed_ecdh uint8 = 65
+ ClientCertTypeIdentifier_ecdsa_fixed_ecdh uint8 = 66
+ ClientCertTypeIdentifier_gost_sign256 uint8 = 67
+ ClientCertTypeIdentifier_gost_sign512 uint8 = 68
+)
+
+var DictClientCertificateTypeIdentifierValueIndexed = map[uint8]string{
+ 1: "rsa_sign",
+ 2: "dss_sign",
+ 3: "rsa_fixed_dh",
+ 4: "dss_fixed_dh",
+ 5: "rsa_ephemeral_dh",
+ 6: "dss_ephemeral_dh",
+ 20: "fortezza_dms",
+ 64: "ecdsa_sign",
+ 65: "rsa_fixed_ecdh",
+ 66: "ecdsa_fixed_ecdh",
+ 67: "gost_sign256",
+ 68: "gost_sign512",
+}
+
+var DictClientCertificateTypeIdentifierNameIndexed = map[string]uint8{
+ "rsa_sign": 1,
+ "dss_sign": 2,
+ "rsa_fixed_dh": 3,
+ "dss_fixed_dh": 4,
+ "rsa_ephemeral_dh": 5,
+ "dss_ephemeral_dh": 6,
+ "fortezza_dms": 20,
+ "ecdsa_sign": 64,
+ "rsa_fixed_ecdh": 65,
+ "ecdsa_fixed_ecdh": 66,
+ "gost_sign256": 67,
+ "gost_sign512": 68,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/comp_meth_ids.go b/vendor/github.com/refraction-networking/utls/dicttls/comp_meth_ids.go
new file mode 100644
index 00000000..a3f951d3
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/comp_meth_ids.go
@@ -0,0 +1,22 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/comp-meth-ids/comp-meth-ids-2.csv
+// last updated: March 2023
+
+const (
+ CompMeth_NULL uint8 = 0
+ CompMeth_DEFLATE uint8 = 1
+ CompMeth_LZS uint8 = 64
+)
+
+var DictCompMethValueIndexed = map[uint8]string{
+ 0: "NULL",
+ 1: "DEFLATE",
+ 64: "LZS",
+}
+
+var DictCompMethNameIndexed = map[string]uint8{
+ "NULL": 0,
+ "DEFLATE": 1,
+ "LZS": 64,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/contenttype.go b/vendor/github.com/refraction-networking/utls/dicttls/contenttype.go
new file mode 100644
index 00000000..b54c84dd
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/contenttype.go
@@ -0,0 +1,34 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-5
+// last updated: March 2023
+
+const (
+ ContentType_change_cipher_spec uint8 = 20
+ ContentType_alert uint8 = 21
+ ContentType_handshake uint8 = 22
+ ContentType_application_data uint8 = 23
+ ContentType_heartbeat uint8 = 24
+ ContentType_tls12_cid uint8 = 25
+ ContentType_ACK uint8 = 26
+)
+
+var DictContentTypeValueIndexed = map[uint8]string{
+ 20: "change_cipher_spec",
+ 21: "alert",
+ 22: "handshake",
+ 23: "application_data",
+ 24: "heartbeat",
+ 25: "tls12_cid",
+ 26: "ACK",
+}
+
+var DictContentTypeNameIndexed = map[string]uint8{
+ "change_cipher_spec": 20,
+ "alert": 21,
+ "handshake": 22,
+ "application_data": 23,
+ "heartbeat": 24,
+ "tls12_cid": 25,
+ "ACK": 26,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/ec_curve_types.go b/vendor/github.com/refraction-networking/utls/dicttls/ec_curve_types.go
new file mode 100644
index 00000000..c15db247
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/ec_curve_types.go
@@ -0,0 +1,22 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10
+// last updated: March 2023
+
+const (
+ ECCurve_explicit_prime uint16 = 1
+ ECCurve_explicit_char2 uint16 = 2
+ ECCurve_named_curve uint16 = 3
+)
+
+var DictECCurveTypeValueIndexed = map[uint16]string{
+ 1: "explicit_prime",
+ 2: "explicit_char2",
+ 3: "named_curve",
+}
+
+var DictECCurveTypeNameIndexed = map[string]uint16{
+ "explicit_prime": 1,
+ "explicit_char2": 2,
+ "named_curve": 3,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/ec_point_formats.go b/vendor/github.com/refraction-networking/utls/dicttls/ec_point_formats.go
new file mode 100644
index 00000000..bfe44bba
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/ec_point_formats.go
@@ -0,0 +1,22 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-9
+// last updated: March 2023
+
+const (
+ ECPoint_uncompressed uint8 = 0
+ ECPoint_ansiX962_compressed_prime uint8 = 1
+ ECPoint_ansiX962_compressed_char2 uint8 = 2
+)
+
+var DictECPointFormatValueIndexed = map[uint8]string{
+ 0: "uncompressed",
+ 1: "ansiX962_compressed_prime",
+ 2: "ansiX962_compressed_char2",
+}
+
+var DictECPointFormatNameIndexed = map[string]uint8{
+ "uncompressed": 0,
+ "ansiX962_compressed_prime": 1,
+ "ansiX962_compressed_char2": 2,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/exttype_values.go b/vendor/github.com/refraction-networking/utls/dicttls/exttype_values.go
new file mode 100644
index 00000000..cb0ef403
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/exttype_values.go
@@ -0,0 +1,212 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#tls-extensiontype-values-1
+// last updated: March 2023
+
+const (
+ ExtType_server_name uint16 = 0
+ ExtType_max_fragment_length uint16 = 1
+ ExtType_client_certificate_url uint16 = 2
+ ExtType_trusted_ca_keys uint16 = 3
+ ExtType_truncated_hmac uint16 = 4
+ ExtType_status_request uint16 = 5
+ ExtType_user_mapping uint16 = 6
+ ExtType_client_authz uint16 = 7
+ ExtType_server_authz uint16 = 8
+ ExtType_cert_type uint16 = 9
+ ExtType_supported_groups uint16 = 10
+ ExtType_ec_point_formats uint16 = 11
+ ExtType_srp uint16 = 12
+ ExtType_signature_algorithms uint16 = 13
+ ExtType_use_srtp uint16 = 14
+ ExtType_heartbeat uint16 = 15
+ ExtType_application_layer_protocol_negotiation uint16 = 16
+ ExtType_status_request_v2 uint16 = 17
+ ExtType_signed_certificate_timestamp uint16 = 18
+ ExtType_client_certificate_type uint16 = 19
+ ExtType_server_certificate_type uint16 = 20
+ ExtType_padding uint16 = 21
+ ExtType_encrypt_then_mac uint16 = 22
+ ExtType_extended_master_secret uint16 = 23
+ ExtType_token_binding uint16 = 24
+ ExtType_cached_info uint16 = 25
+ ExtType_tls_lts uint16 = 26
+ ExtType_compress_certificate uint16 = 27
+ ExtType_record_size_limit uint16 = 28
+ ExtType_pwd_protect uint16 = 29
+ ExtType_pwd_clear uint16 = 30
+ ExtType_password_salt uint16 = 31
+ ExtType_ticket_pinning uint16 = 32
+ ExtType_tls_cert_with_extern_psk uint16 = 33
+ ExtType_delegated_credentials uint16 = 34 // IANA name: delegated_credentials, IETF name: delegated_credential
+ ExtType_session_ticket uint16 = 35
+ ExtType_TLMSP uint16 = 36
+ ExtType_TLMSP_proxying uint16 = 37
+ ExtType_TLMSP_delegate uint16 = 38
+ ExtType_supported_ekt_ciphers uint16 = 39
+ ExtType_pre_shared_key uint16 = 41
+ ExtType_early_data uint16 = 42
+ ExtType_supported_versions uint16 = 43
+ ExtType_cookie uint16 = 44
+ ExtType_psk_key_exchange_modes uint16 = 45
+ ExtType_certificate_authorities uint16 = 47
+ ExtType_oid_filters uint16 = 48
+ ExtType_post_handshake_auth uint16 = 49
+ ExtType_signature_algorithms_cert uint16 = 50
+ ExtType_key_share uint16 = 51
+ ExtType_transparency_info uint16 = 52
+ ExtType_connection_id_deprecated uint16 = 53 // deprecated
+ ExtType_connection_id uint16 = 54
+ ExtType_external_id_hash uint16 = 55
+ ExtType_external_session_id uint16 = 56
+ ExtType_quic_transport_parameters uint16 = 57
+ ExtType_ticket_request uint16 = 58
+ ExtType_dnssec_chain uint16 = 59
+ ExtType_renegotiation_info uint16 = 65281
+)
+
+// Not IANA assigned
+const (
+ ExtType_next_protocol_negotiation uint16 = 13172 // https://datatracker.ietf.org/doc/html/draft-agl-tls-nextprotoneg-04
+ ExtType_application_settings uint16 = 17513 // https://www.ietf.org/archive/id/draft-vvv-tls-alps-01.html
+ ExtType_application_settings_new uint16 = 17613 // https://www.ietf.org/archive/id/draft-vvv-tls-alps-01.html
+ ExtType_channel_id_old uint16 = 30031 // https://datatracker.ietf.org/doc/html/draft-balfanz-tls-channelid-01
+ ExtType_channel_id uint16 = 30032 // https://datatracker.ietf.org/doc/html/draft-balfanz-tls-channelid-01
+)
+
+var DictExtTypeValueIndexed = map[uint16]string{
+ 0: "server_name",
+ 1: "max_fragment_length",
+ 2: "client_certificate_url",
+ 3: "trusted_ca_keys",
+ 4: "truncated_hmac",
+ 5: "status_request",
+ 6: "user_mapping",
+ 7: "client_authz",
+ 8: "server_authz",
+ 9: "cert_type",
+ 10: "supported_groups",
+ 11: "ec_point_formats",
+ 12: "srp",
+ 13: "signature_algorithms",
+ 14: "use_srtp",
+ 15: "heartbeat",
+ 16: "application_layer_protocol_negotiation",
+ 17: "status_request_v2",
+ 18: "signed_certificate_timestamp",
+ 19: "client_certificate_type",
+ 20: "server_certificate_type",
+ 21: "padding",
+ 22: "encrypt_then_mac",
+ 23: "extended_master_secret",
+ 24: "token_binding",
+ 25: "cached_info",
+ 26: "tls_lts",
+ 27: "compress_certificate",
+ 28: "record_size_limit",
+ 29: "pwd_protect",
+ 30: "pwd_clear",
+ 31: "password_salt",
+ 32: "ticket_pinning",
+ 33: "tls_cert_with_extern_psk",
+ 34: "delegated_credentials", // IANA name: delegated_credentials, IETF name: delegated_credential
+ 35: "session_ticket",
+ 36: "TLMSP",
+ 37: "TLMSP_proxying",
+ 38: "TLMSP_delegate",
+ 39: "supported_ekt_ciphers",
+ 41: "pre_shared_key",
+ 42: "early_data",
+ 43: "supported_versions",
+ 44: "cookie",
+ 45: "psk_key_exchange_modes",
+ 47: "certificate_authorities",
+ 48: "oid_filters",
+ 49: "post_handshake_auth",
+ 50: "signature_algorithms_cert",
+ 51: "key_share",
+ 52: "transparency_info",
+ 53: "connection_id_deprecated", // deprecated
+ 54: "connection_id",
+ 55: "external_id_hash",
+ 56: "external_session_id",
+ 57: "quic_transport_parameters",
+ 58: "ticket_request",
+ 59: "dnssec_chain",
+ 65281: "renegotiation_info",
+
+ 13172: "next_protocol_negotiation",
+ 17513: "application_settings",
+ 17613: "application_settings_new",
+ 30031: "channel_id_old",
+ 30032: "channel_id",
+}
+
+var DictExtTypeNameIndexed = map[string]uint16{
+ "server_name": 0,
+ "max_fragment_length": 1,
+ "client_certificate_url": 2,
+ "trusted_ca_keys": 3,
+ "truncated_hmac": 4,
+ "status_request": 5,
+ "user_mapping": 6,
+ "client_authz": 7,
+ "server_authz": 8,
+ "cert_type": 9,
+ "supported_groups": 10,
+ "ec_point_formats": 11,
+ "srp": 12,
+ "signature_algorithms": 13,
+ "use_srtp": 14,
+ "heartbeat": 15,
+ "application_layer_protocol_negotiation": 16,
+ "status_request_v2": 17,
+ "signed_certificate_timestamp": 18,
+ "client_certificate_type": 19,
+ "server_certificate_type": 20,
+ "padding": 21,
+ "encrypt_then_mac": 22,
+ "extended_master_secret": 23,
+ "token_binding": 24,
+ "cached_info": 25,
+ "tls_lts": 26,
+ "compress_certificate": 27,
+ "record_size_limit": 28,
+ "pwd_protect": 29,
+ "pwd_clear": 30,
+ "password_salt": 31,
+ "ticket_pinning": 32,
+ "tls_cert_with_extern_psk": 33,
+ "delegated_credentials": 34, // IANA name: delegated_credentials
+ "delegated_credential": 34, // IETF name: delegated_credential
+ "session_ticket": 35,
+ "TLMSP": 36,
+ "TLMSP_proxying": 37,
+ "TLMSP_delegate": 38,
+ "supported_ekt_ciphers": 39,
+ "pre_shared_key": 41,
+ "early_data": 42,
+ "supported_versions": 43,
+ "cookie": 44,
+ "psk_key_exchange_modes": 45,
+ "certificate_authorities": 47,
+ "oid_filters": 48,
+ "post_handshake_auth": 49,
+ "signature_algorithms_cert": 50,
+ "key_share": 51,
+ "transparency_info": 52,
+ "connection_id_deprecated": 53, // deprecated
+ "connection_id": 54,
+ "external_id_hash": 55,
+ "external_session_id": 56,
+ "quic_transport_parameters": 57,
+ "ticket_request": 58,
+ "dnssec_chain": 59,
+ "renegotiation_info": 65281,
+
+ "next_protocol_negotiation": 13172,
+ "application_settings": 17513,
+ "application_settings_new": 17613,
+ "channel_id_old": 30031,
+ "channel_id": 30032,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/handshaketype.go b/vendor/github.com/refraction-networking/utls/dicttls/handshaketype.go
new file mode 100644
index 00000000..798a1c37
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/handshaketype.go
@@ -0,0 +1,96 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-7
+// last updated: March 2023
+
+const (
+ HandshakeType_hello_request uint8 = 0
+ HandshakeType_client_hello uint8 = 1
+ HandshakeType_server_hello uint8 = 2
+ HandshakeType_hello_verify_request uint8 = 3
+ HandshakeType_new_session_ticket uint8 = 4
+ HandshakeType_end_of_early_data uint8 = 5
+ HandshakeType_hello_retry_request uint8 = 6
+ HandshakeType_encrypted_extensions uint8 = 8
+ HandshakeType_request_connection_id uint8 = 9
+ HandshakeType_new_connection_id uint8 = 10
+ HandshakeType_certificate uint8 = 11
+ HandshakeType_server_key_exchange uint8 = 12
+ HandshakeType_certificate_request uint8 = 13
+ HandshakeType_server_hello_done uint8 = 14
+ HandshakeType_certificate_verify uint8 = 15
+ HandshakeType_client_key_exchange uint8 = 16
+ HandshakeType_client_certificate_request uint8 = 17
+ HandshakeType_finished uint8 = 20
+ HandshakeType_certificate_url uint8 = 21
+ HandshakeType_certificate_status uint8 = 22
+ HandshakeType_supplemental_data uint8 = 23
+ HandshakeType_key_update uint8 = 24
+ HandshakeType_compressed_certificate uint8 = 25
+ HandshakeType_ekt_key uint8 = 26
+ HandshakeType_message_hash uint8 = 254
+
+ // Not IANA assigned
+ HandshakeType_next_protocol uint8 = 67
+)
+
+var DictHandshakeTypeValueIndexed = map[uint8]string{
+ 0: "hello_request",
+ 1: "client_hello",
+ 2: "server_hello",
+ 3: "hello_verify_request",
+ 4: "new_session_ticket",
+ 5: "end_of_early_data",
+ 6: "hello_retry_request",
+ 7: "Unassigned",
+ 8: "encrypted_extensions",
+ 9: "request_connection_id",
+ 10: "new_connection_id",
+ 11: "certificate",
+ 12: "server_key_exchange",
+ 13: "certificate_request",
+ 14: "server_hello_done",
+ 15: "certificate_verify",
+ 16: "client_key_exchange",
+ 17: "client_certificate_request",
+ 20: "finished",
+ 21: "certificate_url",
+ 22: "certificate_status",
+ 23: "supplemental_data",
+ 24: "key_update",
+ 25: "compressed_certificate",
+ 26: "ekt_key",
+ 254: "message_hash",
+
+ 67: "next_protocol",
+}
+
+var DictHandshakeTypeNameIndexed = map[string]uint8{
+ "hello_request": 0,
+ "client_hello": 1,
+ "server_hello": 2,
+ "hello_verify_request": 3,
+ "new_session_ticket": 4,
+ "end_of_early_data": 5,
+ "hello_retry_request": 6,
+ "encrypted_extensions": 8,
+ "request_connection_id": 9,
+ "new_connection_id": 10,
+ "certificate": 11,
+ "server_key_exchange": 12,
+ "certificate_request": 13,
+ "server_hello_done": 14,
+ "certificate_verify": 15,
+ "client_key_exchange": 16,
+ "client_certificate_request": 17,
+ "finished": 20,
+ "certificate_url": 21,
+ "certificate_status": 22,
+ "supplemental_data": 23,
+ "key_update": 24,
+ "compressed_certificate": 25,
+ "ekt_key": 26,
+ "message_hash": 254,
+
+ "next_protocol": 67,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/hashalgorithm.go b/vendor/github.com/refraction-networking/utls/dicttls/hashalgorithm.go
new file mode 100644
index 00000000..24e61586
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/hashalgorithm.go
@@ -0,0 +1,39 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18
+// last updated: March 2023
+
+const (
+ HashAlg_none uint8 = 0 // deprecated in TLS 1.3
+ HashAlg_md5 uint8 = 1 // deprecated in TLS 1.3
+ HashAlg_sha1 uint8 = 2
+ HashAlg_sha224 uint8 = 3 // deprecated in TLS 1.3
+ HashAlg_sha256 uint8 = 4
+ HashAlg_sha384 uint8 = 5
+ HashAlg_sha512 uint8 = 6
+ HashAlg_Intrinsic uint8 = 8
+)
+
+var DictHashAlgorithmValueIndexed = map[uint8]string{
+ 0: "none",
+ 1: "md5",
+ 2: "sha1",
+ 3: "sha224",
+ 4: "sha256",
+ 5: "sha384",
+ 6: "sha512",
+ 7: "Reserved",
+ 8: "Intrinsic",
+}
+
+var DictHashAlgorithmNameIndexed = map[string]uint8{
+ "none": 0,
+ "md5": 1,
+ "sha1": 2,
+ "sha224": 3,
+ "sha256": 4,
+ "sha384": 5,
+ "sha512": 6,
+ "Reserved": 7,
+ "Intrinsic": 8,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/heartbeat_message_types.go b/vendor/github.com/refraction-networking/utls/dicttls/heartbeat_message_types.go
new file mode 100644
index 00000000..0b076be1
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/heartbeat_message_types.go
@@ -0,0 +1,19 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/heartbeat-message-types.csv
+// last updated: March 2023
+
+const (
+ HeartbeatMessage_request uint8 = 1
+ HeartbeatMessage_response uint8 = 2
+)
+
+var DictHeartbeatMessageTypeValueIndexed = map[uint8]string{
+ 1: "heartbeat_request",
+ 2: "heartbeat_response",
+}
+
+var DictHeartbeatMessageTypeNameIndexed = map[string]uint8{
+ "heartbeat_request": 1,
+ "heartbeat_response": 2,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/heartbeat_mode.go b/vendor/github.com/refraction-networking/utls/dicttls/heartbeat_mode.go
new file mode 100644
index 00000000..747ae6e1
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/heartbeat_mode.go
@@ -0,0 +1,19 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/heartbeat-modes.csv
+// last updated: March 2023
+
+const (
+ HeartbeatMode_peer_allowed_to_send uint8 = 1
+ HeartbeatMode_peer_not_allowed_to_send uint8 = 2
+)
+
+var DictHeartbeatModeValueIndexed = map[uint8]string{
+ 1: "peer_allowed_to_send",
+ 2: "peer_not_allowed_to_send",
+}
+
+var DictHeartbeatModeNameIndexed = map[string]uint8{
+ "peer_allowed_to_send": 1,
+ "peer_not_allowed_to_send": 2,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/hpke_aead_identifiers.go b/vendor/github.com/refraction-networking/utls/dicttls/hpke_aead_identifiers.go
new file mode 100644
index 00000000..c4f82314
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/hpke_aead_identifiers.go
@@ -0,0 +1,19 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/hpke/hpke.xhtml
+// last updated: December 2023
+
+const (
+ AEAD_AES_128_GCM uint16 = 0x0001 // NIST Special Publication 800-38D
+ AEAD_AES_256_GCM uint16 = 0x0002 // NIST Special Publication 800-38D
+ AEAD_CHACHA20_POLY1305 uint16 = 0x0003 // RFC 8439
+ AEAD_EXPORT_ONLY uint16 = 0xFFFF // RFC 9180
+)
+
+var DictAEADIdentifierValueIndexed = map[uint16]string{
+ 0x0000: "Reserved", // RFC 9180
+ 0x0001: "AES-128-GCM",
+ 0x0002: "AES-256-GCM",
+ 0x0003: "ChaCha20Poly1305",
+ 0xFFFF: "Export-only", // RFC 9180
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/hpke_kdf_identifiers.go b/vendor/github.com/refraction-networking/utls/dicttls/hpke_kdf_identifiers.go
new file mode 100644
index 00000000..7471943f
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/hpke_kdf_identifiers.go
@@ -0,0 +1,24 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/hpke/hpke.xhtml
+// last updated: December 2023
+
+const (
+ HKDF_SHA256 uint16 = 0x0001
+ HKDF_SHA384 uint16 = 0x0002
+ HKDF_SHA512 uint16 = 0x0003
+)
+
+var DictKDFIdentifierValueIndexed = map[uint16]string{
+ 0x0000: "Reserved", // RFC 9180
+ 0x0001: "HKDF_SHA256",
+ 0x0002: "HKDF_SHA384",
+ 0x0003: "HKDF_SHA512",
+}
+
+var DictKDFIdentifierNameIndexed = map[string]uint16{
+ "Reserved": 0x0000, // RFC 9180
+ "HKDF_SHA256": 0x0001,
+ "HKDF_SHA384": 0x0002,
+ "HKDF_SHA512": 0x0003,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/hpke_kem_identifiers.go b/vendor/github.com/refraction-networking/utls/dicttls/hpke_kem_identifiers.go
new file mode 100644
index 00000000..213e7f8c
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/hpke_kem_identifiers.go
@@ -0,0 +1,53 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/hpke/hpke.xhtml
+// last updated: December 2023
+
+const (
+ DHKEM_P256_HKDF_SHA256 uint16 = 0x0010 // RFC 5869
+ DHKEM_P384_HKDF_SHA384 uint16 = 0x0011 // RFC 5869
+ DHKEM_P521_HKDF_SHA512 uint16 = 0x0012 // RFC 5869
+ DHKEM_CP256_HKDF_SHA256 uint16 = 0x0013 // RFC 6090
+ DHKEM_CP384_HKDF_SHA384 uint16 = 0x0014 // RFC 6090
+ DHKEM_CP521_HKDF_SHA512 uint16 = 0x0015 // RFC 6090
+ DHKEM_SECP256K1_HKDF_SHA256 uint16 = 0x0016 // draft-wahby-cfrg-hpke-kem-secp256k1-01
+
+ DHKEM_X25519_HKDF_SHA256 uint16 = 0x0020 // RFC 7748
+ DHKEM_X448_HKDF_SHA512 uint16 = 0x0021 // RFC 7748
+
+ X25519_KYBER768_DRAFT00 uint16 = 0x0030 // draft-westerbaan-cfrg-hpke-xyber768d00-02
+)
+
+var DictKEMIdentifierValueIndexed = map[uint16]string{
+ 0x0000: "Reserved", // RFC 9180
+
+ 0x0010: "DHKEM(P-256, HKDF-SHA256)",
+ 0x0011: "DHKEM(P-384, HKDF-SHA384)",
+ 0x0012: "DHKEM(P-521, HKDF-SHA512)",
+ 0x0013: "DHKEM(CP-256, HKDF-SHA256)",
+ 0x0014: "DHKEM(CP-384, HKDF-SHA384)",
+ 0x0015: "DHKEM(CP-521, HKDF-SHA512)",
+ 0x0016: "DHKEM(secp256k1, HKDF-SHA256)",
+
+ 0x0020: "DHKEM(X25519, HKDF-SHA256)",
+ 0x0021: "DHKEM(X448, HKDF-SHA512)",
+
+ 0x0030: "X25519Kyber768Draft00",
+}
+
+var DictKEMIdentifierNameIndexed = map[string]uint16{
+ "Reserved": 0x0000, // RFC 9180
+
+ "DHKEM(P-256, HKDF-SHA256)": 0x0010,
+ "DHKEM(P-384, HKDF-SHA384)": 0x0011,
+ "DHKEM(P-521, HKDF-SHA512)": 0x0012,
+ "DHKEM(CP-256, HKDF-SHA256)": 0x0013,
+ "DHKEM(CP-384, HKDF-SHA384)": 0x0014,
+ "DHKEM(CP-521, HKDF-SHA512)": 0x0015,
+ "DHKEM(secp256k1, HKDF-SHA256)": 0x0016,
+
+ "DHKEM(X25519, HKDF-SHA256)": 0x0020,
+ "DHKEM(X448, HKDF-SHA512)": 0x0021,
+
+ "X25519Kyber768Draft00": 0x0030,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/psk_key_exchange_mode.go b/vendor/github.com/refraction-networking/utls/dicttls/psk_key_exchange_mode.go
new file mode 100644
index 00000000..7f3cc388
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/psk_key_exchange_mode.go
@@ -0,0 +1,19 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-pskkeyexchangemode.csv
+// last updated: March 2023
+
+const (
+ PSKKeyExchangeMode_psk_ke uint8 = 0
+ PSKKeyExchangeMode_psk_dhe_ke uint8 = 1
+)
+
+var DictPSKKeyExchangeModeValueIndexed = map[uint8]string{
+ 0: "psk_ke",
+ 1: "psk_dhe_ke",
+}
+
+var DictPSKKeyExchangeModeNameIndexed = map[string]uint8{
+ "psk_ke": 0,
+ "psk_dhe_ke": 1,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/quic_frame_types.go b/vendor/github.com/refraction-networking/utls/dicttls/quic_frame_types.go
new file mode 100644
index 00000000..a7dd0ac6
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/quic_frame_types.go
@@ -0,0 +1,112 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/quic/quic.xhtml#quic-frame-types
+// last updated: July 2023
+
+const (
+ QUICFrameType_PADDING uint8 = 0x00
+ QUICFrameType_PING uint8 = 0x01
+ QUICFrameType_ACK uint8 = 0x02
+ QUICFrameType_ACK_ecn uint8 = 0x03
+ QUICFrameType_RESET_STREAM uint8 = 0x04
+ QUICFrameType_STOP_SENDING uint8 = 0x05
+ QUICFrameType_CRYPTO uint8 = 0x06
+ QUICFrameType_NEW_TOKEN uint8 = 0x07
+ QUICFrameType_STREAM uint8 = 0x08
+ QUICFrameType_STREAM_fin uint8 = 0x09
+ QUICFrameType_STREAM_len uint8 = 0x0a
+ QUICFrameType_STREAM_len_fin uint8 = 0x0b
+ QUICFrameType_STREAM_off uint8 = 0x0c
+ QUICFrameType_STREAM_off_fin uint8 = 0x0d
+ QUICFrameType_STREAM_off_len uint8 = 0x0e
+ QUICFrameType_STREAM_off_len_fin uint8 = 0x0f
+ QUICFrameType_MAX_DATA uint8 = 0x10
+ QUICFrameType_MAX_STREAM_DATA uint8 = 0x11
+ QUICFrameType_MAX_STREAMS_bidi uint8 = 0x12
+ QUICFrameType_MAX_STREAMS_uni uint8 = 0x13
+ QUICFrameType_DATA_BLOCKED uint8 = 0x14
+ QUICFrameType_STREAM_DATA_BLOCKED uint8 = 0x15
+ QUICFrameType_STREAMS_BLOCKED_bidi uint8 = 0x16
+ QUICFrameType_STREAMS_BLOCKED_uni uint8 = 0x17
+ QUICFrameType_NEW_CONNECTION_ID uint8 = 0x18
+ QUICFrameType_RETIRE_CONNECTION_ID uint8 = 0x19
+ QUICFrameType_PATH_CHALLENGE uint8 = 0x1a
+ QUICFrameType_PATH_RESPONSE uint8 = 0x1b
+ QUICFrameType_CONNECTION_CLOSE uint8 = 0x1c
+ QUICFrameType_CONNECTION_CLOSE_app uint8 = 0x1d
+ QUICFrameType_HANDSHAKE_DONE uint8 = 0x1e
+ QUICFrameType_DATAGRAM uint8 = 0x30 // RFC9221
+ QUICFrameType_DATAGRAM_len uint8 = 0x31 // RFC9221
+)
+
+var DictQUICFrameTypeValueIndexed = map[uint8]string{
+ 0x00: "PADDING",
+ 0x01: "PING",
+ 0x02: "ACK",
+ 0x03: "ACK_ecn",
+ 0x04: "RESET_STREAM",
+ 0x05: "STOP_SENDING",
+ 0x06: "CRYPTO",
+ 0x07: "NEW_TOKEN",
+ 0x08: "STREAM",
+ 0x09: "STREAM_fin",
+ 0x0a: "STREAM_len",
+ 0x0b: "STREAM_len_fin",
+ 0x0c: "STREAM_off",
+ 0x0d: "STREAM_off_fin",
+ 0x0e: "STREAM_off_len",
+ 0x0f: "STREAM_off_len_fin",
+ 0x10: "MAX_DATA",
+ 0x11: "MAX_STREAM_DATA",
+ 0x12: "MAX_STREAMS_bidi",
+ 0x13: "MAX_STREAMS_uni",
+ 0x14: "DATA_BLOCKED",
+ 0x15: "STREAM_DATA_BLOCKED",
+ 0x16: "STREAMS_BLOCKED_bidi",
+ 0x17: "STREAMS_BLOCKED_uni",
+ 0x18: "NEW_CONNECTION_ID",
+ 0x19: "RETIRE_CONNECTION_ID",
+ 0x1a: "PATH_CHALLENGE",
+ 0x1b: "PATH_RESPONSE",
+ 0x1c: "CONNECTION_CLOSE",
+ 0x1d: "CONNECTION_CLOSE_app",
+ 0x1e: "HANDSHAKE_DONE",
+ 0x30: "DATAGRAM",
+ 0x31: "DATAGRAM_len",
+}
+
+var DictQUICFrameTypeNameIndexed = map[string]uint8{
+ "PADDING": 0x00,
+ "PING": 0x01,
+ "ACK": 0x02,
+ "ACK_ecn": 0x03,
+ "RESET_STREAM": 0x04,
+ "STOP_SENDING": 0x05,
+ "CRYPTO": 0x06,
+ "NEW_TOKEN": 0x07,
+ "STREAM": 0x08,
+ "STREAM_fin": 0x09,
+ "STREAM_len": 0x0a,
+ "STREAM_len_fin": 0x0b,
+ "STREAM_off": 0x0c,
+ "STREAM_off_fin": 0x0d,
+ "STREAM_off_len": 0x0e,
+ "STREAM_off_len_fin": 0x0f,
+ "MAX_DATA": 0x10,
+ "MAX_STREAM_DATA": 0x11,
+ "MAX_STREAMS_bidi": 0x12,
+ "MAX_STREAMS_uni": 0x13,
+ "DATA_BLOCKED": 0x14,
+ "STREAM_DATA_BLOCKED": 0x15,
+ "STREAMS_BLOCKED_bidi": 0x16,
+ "STREAMS_BLOCKED_uni": 0x17,
+ "NEW_CONNECTION_ID": 0x18,
+ "RETIRE_CONNECTION_ID": 0x19,
+ "PATH_CHALLENGE": 0x1a,
+ "PATH_RESPONSE": 0x1b,
+ "CONNECTION_CLOSE": 0x1c,
+ "CONNECTION_CLOSE_app": 0x1d,
+ "HANDSHAKE_DONE": 0x1e,
+ "DATAGRAM": 0x30,
+ "DATAGRAM_len": 0x31,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/quic_transport_error_codes.go b/vendor/github.com/refraction-networking/utls/dicttls/quic_transport_error_codes.go
new file mode 100644
index 00000000..52d2c8bd
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/quic_transport_error_codes.go
@@ -0,0 +1,70 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/quic/quic.xhtml#quic-transport-error-codes
+// last updated: July 2023
+
+const (
+ QUICTransportErrorCode_NO_ERROR uint16 = 0x0000
+ QUICTransportErrorCode_INTERNAL_ERROR uint16 = 0x0001
+ QUICTransportErrorCode_CONNECTION_REFUSED uint16 = 0x0002
+ QUICTransportErrorCode_FLOW_CONTROL_ERROR uint16 = 0x0003
+ QUICTransportErrorCode_STREAM_LIMIT_ERROR uint16 = 0x0004
+ QUICTransportErrorCode_STREAM_STATE_ERROR uint16 = 0x0005
+ QUICTransportErrorCode_FINAL_SIZE_ERROR uint16 = 0x0006
+ QUICTransportErrorCode_FRAME_ENCODING_ERROR uint16 = 0x0007
+ QUICTransportErrorCode_TRANSPORT_PARAMETER_ERROR uint16 = 0x0008
+ QUICTransportErrorCode_CONNECTION_ID_LIMIT_ERROR uint16 = 0x0009
+ QUICTransportErrorCode_PROTOCOL_VIOLATION uint16 = 0x000A
+ QUICTransportErrorCode_INVALID_TOKEN uint16 = 0x000B
+ QUICTransportErrorCode_APPLICATION_ERROR uint16 = 0x000C
+ QUICTransportErrorCode_CRYPTO_BUFFER_EXCEEDED uint16 = 0x000D
+ QUICTransportErrorCode_KEY_UPDATE_ERROR uint16 = 0x000E
+ QUICTransportErrorCode_AEAD_LIMIT_REACHED uint16 = 0x000F
+ QUICTransportErrorCode_NO_VIABLE_PATH uint16 = 0x0010
+ QUICTransportErrorCode_VERSION_NEGOTIATION_ERROR uint16 = 0x0011 // RFC9368
+ QUICTransportErrorCode_CRYPTO_ERROR uint16 = 0x0100 // 0x0100-0x01FF, use with bitwise operator
+)
+
+var DictQUICTransportErrorCodeValueIndexed = map[uint16]string{
+ 0x0000: "NO_ERROR",
+ 0x0001: "INTERNAL_ERROR",
+ 0x0002: "CONNECTION_REFUSED",
+ 0x0003: "FLOW_CONTROL_ERROR",
+ 0x0004: "STREAM_LIMIT_ERROR",
+ 0x0005: "STREAM_STATE_ERROR",
+ 0x0006: "FINAL_SIZE_ERROR",
+ 0x0007: "FRAME_ENCODING_ERROR",
+ 0x0008: "TRANSPORT_PARAMETER_ERROR",
+ 0x0009: "CONNECTION_ID_LIMIT_ERROR",
+ 0x000A: "PROTOCOL_VIOLATION",
+ 0x000B: "INVALID_TOKEN",
+ 0x000C: "APPLICATION_ERROR",
+ 0x000D: "CRYPTO_BUFFER_EXCEEDED",
+ 0x000E: "KEY_UPDATE_ERROR",
+ 0x000F: "AEAD_LIMIT_REACHED",
+ 0x0010: "NO_VIABLE_PATH",
+ 0x0011: "VERSION_NEGOTIATION_ERROR",
+ 0x0100: "CRYPTO_ERROR",
+}
+
+var DictQUICTransportErrorCodeNameIndexed = map[string]uint16{
+ "NO_ERROR": 0x0000,
+ "INTERNAL_ERROR": 0x0001,
+ "CONNECTION_REFUSED": 0x0002,
+ "FLOW_CONTROL_ERROR": 0x0003,
+ "STREAM_LIMIT_ERROR": 0x0004,
+ "STREAM_STATE_ERROR": 0x0005,
+ "FINAL_SIZE_ERROR": 0x0006,
+ "FRAME_ENCODING_ERROR": 0x0007,
+ "TRANSPORT_PARAMETER_ERROR": 0x0008,
+ "CONNECTION_ID_LIMIT_ERROR": 0x0009,
+ "PROTOCOL_VIOLATION": 0x000A,
+ "INVALID_TOKEN": 0x000B,
+ "APPLICATION_ERROR": 0x000C,
+ "CRYPTO_BUFFER_EXCEEDED": 0x000D,
+ "KEY_UPDATE_ERROR": 0x000E,
+ "AEAD_LIMIT_REACHED": 0x000F,
+ "NO_VIABLE_PATH": 0x0010,
+ "VERSION_NEGOTIATION_ERROR": 0x0011,
+ "CRYPTO_ERROR": 0x0100,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/quic_transport_parameters.go b/vendor/github.com/refraction-networking/utls/dicttls/quic_transport_parameters.go
new file mode 100644
index 00000000..66eb881b
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/quic_transport_parameters.go
@@ -0,0 +1,91 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/quic/quic.xhtml#quic-transport
+// last updated: July 2023
+
+const (
+ QUICTransportParameter_original_destination_connection_id uint64 = 0x00
+ QUICTransportParameter_max_idle_timeout uint64 = 0x01
+ QUICTransportParameter_stateless_reset_token uint64 = 0x02
+ QUICTransportParameter_max_udp_payload_size uint64 = 0x03
+ QUICTransportParameter_initial_max_data uint64 = 0x04
+ QUICTransportParameter_initial_max_stream_data_bidi_local uint64 = 0x05
+ QUICTransportParameter_initial_max_stream_data_bidi_remote uint64 = 0x06
+ QUICTransportParameter_initial_max_stream_data_uni uint64 = 0x07
+ QUICTransportParameter_initial_max_streams_bidi uint64 = 0x08
+ QUICTransportParameter_initial_max_streams_uni uint64 = 0x09
+ QUICTransportParameter_ack_delay_exponent uint64 = 0x0a
+ QUICTransportParameter_max_ack_delay uint64 = 0x0b
+ QUICTransportParameter_disable_active_migration uint64 = 0x0c
+ QUICTransportParameter_preferred_address uint64 = 0x0d
+ QUICTransportParameter_active_connection_id_limit uint64 = 0x0e
+ QUICTransportParameter_initial_source_connection_id uint64 = 0x0f
+ QUICTransportParameter_retry_source_connection_id uint64 = 0x10
+ QUICTransportParameter_version_information uint64 = 0x11 // RFC9368
+ QUICTransportParameter_max_datagram_frame_size uint64 = 0x20 // RFC9221
+ QUICTransportParameter_discard uint64 = 0x173e // David_Schinazi: Receiver silently discards. https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test
+ QUICTransportParameter_google_handshake_message uint64 = 0x26ab // Google: Used to carry Google internal handshake message
+ QUICTransportParameter_grease_quic_bit uint64 = 0x2ab2 // RFC9287
+ QUICTransportParameter_initial_rtt uint64 = 0x3127 // Google: Initial RTT in microseconds
+ QUICTransportParameter_google_connection_options uint64 = 0x3128 // Google: Google connection options for experimentation
+ QUICTransportParameter_user_agent uint64 = 0x3129 // Google: User agent string (deprecated)
+ QUICTransportParameter_google_version uint64 = 0x4752 // Google: Google QUIC version downgrade prevention
+)
+
+var DictQUICTransportParameterValueIndexed = map[uint64]string{
+ 0x00: "original_destination_connection_id",
+ 0x01: "max_idle_timeout",
+ 0x02: "stateless_reset_token",
+ 0x03: "max_udp_payload_size",
+ 0x04: "initial_max_data",
+ 0x05: "initial_max_stream_data_bidi_local",
+ 0x06: "initial_max_stream_data_bidi_remote",
+ 0x07: "initial_max_stream_data_uni",
+ 0x08: "initial_max_streams_bidi",
+ 0x09: "initial_max_streams_uni",
+ 0x0a: "ack_delay_exponent",
+ 0x0b: "max_ack_delay",
+ 0x0c: "disable_active_migration",
+ 0x0d: "preferred_address",
+ 0x0e: "active_connection_id_limit",
+ 0x0f: "initial_source_connection_id",
+ 0x10: "retry_source_connection_id",
+ 0x11: "version_information",
+ 0x20: "max_datagram_frame_size",
+ 0x173e: "discard",
+ 0x26ab: "google handshake message",
+ 0x2ab2: "grease_quic_bit",
+ 0x3127: "initial_rtt",
+ 0x3128: "google_connection_options",
+ 0x3129: "user_agent",
+ 0x4752: "google_version",
+}
+
+var DictQUICTransportParameterNameIndexed = map[string]uint64{
+ "original_destination_connection_id": 0x00,
+ "max_idle_timeout": 0x01,
+ "stateless_reset_token": 0x02,
+ "max_udp_payload_size": 0x03,
+ "initial_max_data": 0x04,
+ "initial_max_stream_data_bidi_local": 0x05,
+ "initial_max_stream_data_bidi_remote": 0x06,
+ "initial_max_stream_data_uni": 0x07,
+ "initial_max_streams_bidi": 0x08,
+ "initial_max_streams_uni": 0x09,
+ "ack_delay_exponent": 0x0a,
+ "max_ack_delay": 0x0b,
+ "disable_active_migration": 0x0c,
+ "preferred_address": 0x0d,
+ "active_connection_id_limit": 0x0e,
+ "initial_source_connection_id": 0x0f,
+ "retry_source_connection_id": 0x10,
+ "version_information": 0x11,
+ "max_datagram_frame_size": 0x20,
+ "discard": 0x173e,
+ "google handshake message": 0x26ab,
+ "grease_quic_bit": 0x2ab2,
+ "initial_rtt": 0x3127,
+ "google_connection_options": 0x3128,
+ "user_agent": 0x3129,
+ "google_version": 0x4752,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/signaturealgorithm.go b/vendor/github.com/refraction-networking/utls/dicttls/signaturealgorithm.go
new file mode 100644
index 00000000..65c40c4f
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/signaturealgorithm.go
@@ -0,0 +1,41 @@
+package dicttls
+
+// Note: values in this file was used in TLS 1.2's signature_algorithms extension
+// in combination with the values in hashalgorithm.go.
+// signature_algorithms extension in TLS 1.3 uses values in signaturescheme.go
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16
+// last updated: March 2023
+
+const (
+ SigAlg_anonymous uint8 = 0 // deprecated in TLS 1.3
+ SigAlg_rsa uint8 = 1
+ SigAlg_dsa uint8 = 2 // deprecated in TLS 1.3
+ SigAlg_ecdsa uint8 = 3
+ SigAlg_ed25519 uint8 = 7
+ SigAlg_ed448 uint8 = 8
+ SigAlg_gostr34102012_256 uint8 = 64 // value changed in TLS 1.3, to 0x0709-0x070C
+ SigAlg_gostr34102012_512 uint8 = 65 // value changed in TLS 1.3, to 0x070D-0x070F
+)
+
+var DictSignatureAlgorithmValueIndexed = map[uint8]string{
+ 0: "anonymous",
+ 1: "rsa",
+ 2: "dsa",
+ 3: "ecdsa",
+ 7: "ed25519",
+ 8: "ed448",
+ 64: "gostr34102012_256",
+ 65: "gostr34102012_512",
+}
+
+var DictSignatureAlgorithmNameIndexed = map[string]uint8{
+ "anonymous": 0,
+ "rsa": 1,
+ "dsa": 2,
+ "ecdsa": 3,
+ "ed25519": 7,
+ "ed448": 8,
+ "gostr34102012_256": 64,
+ "gostr34102012_512": 65,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/signaturescheme.go b/vendor/github.com/refraction-networking/utls/dicttls/signaturescheme.go
new file mode 100644
index 00000000..d0b9803f
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/signaturescheme.go
@@ -0,0 +1,116 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-signaturescheme.csv
+// last updated: March 2023
+
+const (
+ SigScheme_rsa_pkcs1_sha1 uint16 = 0x0201
+ SigScheme_ecdsa_sha1 uint16 = 0x0203
+ SigScheme_rsa_pkcs1_sha256 uint16 = 0x0401
+ SigScheme_ecdsa_secp256r1_sha256 uint16 = 0x0403
+ SigScheme_rsa_pkcs1_sha256_legacy uint16 = 0x0420
+ SigScheme_rsa_pkcs1_sha384 uint16 = 0x0501
+ SigScheme_ecdsa_secp384r1_sha384 uint16 = 0x0503
+ SigScheme_rsa_pkcs1_sha384_legacy uint16 = 0x0520
+ SigScheme_rsa_pkcs1_sha512 uint16 = 0x0601
+ SigScheme_ecdsa_secp521r1_sha512 uint16 = 0x0603
+ SigScheme_rsa_pkcs1_sha512_legacy uint16 = 0x0620
+ SigScheme_eccsi_sha256 uint16 = 0x0704
+ SigScheme_iso_ibs1 uint16 = 0x0705
+ SigScheme_iso_ibs2 uint16 = 0x0706
+ SigScheme_iso_chinese_ibs uint16 = 0x0707
+ SigScheme_sm2sig_sm3 uint16 = 0x0708
+ SigScheme_gostr34102012_256a uint16 = 0x0709
+ SigScheme_gostr34102012_256b uint16 = 0x070A
+ SigScheme_gostr34102012_256c uint16 = 0x070B
+ SigScheme_gostr34102012_256d uint16 = 0x070C
+ SigScheme_gostr34102012_512a uint16 = 0x070D
+ SigScheme_gostr34102012_512b uint16 = 0x070E
+ SigScheme_gostr34102012_512c uint16 = 0x070F
+ SigScheme_rsa_pss_rsae_sha256 uint16 = 0x0804
+ SigScheme_rsa_pss_rsae_sha384 uint16 = 0x0805
+ SigScheme_rsa_pss_rsae_sha512 uint16 = 0x0806
+ SigScheme_ed25519 uint16 = 0x0807
+ SigScheme_ed448 uint16 = 0x0808
+ SigScheme_rsa_pss_pss_sha256 uint16 = 0x0809
+ SigScheme_rsa_pss_pss_sha384 uint16 = 0x080A
+ SigScheme_rsa_pss_pss_sha512 uint16 = 0x080B
+ SigScheme_ecdsa_brainpoolP256r1tls13_sha256 uint16 = 0x081A
+ SigScheme_ecdsa_brainpoolP384r1tls13_sha384 uint16 = 0x081B
+ SigScheme_ecdsa_brainpoolP512r1tls13_sha512 uint16 = 0x081C
+)
+
+var DictSignatureSchemeValueIndexed = map[uint16]string{
+ 0x0201: "rsa_pkcs1_sha1",
+ 0x0203: "ecdsa_sha1",
+ 0x0401: "rsa_pkcs1_sha256",
+ 0x0403: "ecdsa_secp256r1_sha256",
+ 0x0420: "rsa_pkcs1_sha256_legacy",
+ 0x0501: "rsa_pkcs1_sha384",
+ 0x0503: "ecdsa_secp384r1_sha384",
+ 0x0520: "rsa_pkcs1_sha384_legacy",
+ 0x0601: "rsa_pkcs1_sha512",
+ 0x0603: "ecdsa_secp521r1_sha512",
+ 0x0620: "rsa_pkcs1_sha512_legacy",
+ 0x0704: "eccsi_sha256",
+ 0x0705: "iso_ibs1",
+ 0x0706: "iso_ibs2",
+ 0x0707: "iso_chinese_ibs",
+ 0x0708: "sm2sig_sm3",
+ 0x0709: "gostr34102012_256a",
+ 0x070A: "gostr34102012_256b",
+ 0x070B: "gostr34102012_256c",
+ 0x070C: "gostr34102012_256d",
+ 0x070D: "gostr34102012_512a",
+ 0x070E: "gostr34102012_512b",
+ 0x070F: "gostr34102012_512c",
+ 0x0804: "rsa_pss_rsae_sha256",
+ 0x0805: "rsa_pss_rsae_sha384",
+ 0x0806: "rsa_pss_rsae_sha512",
+ 0x0807: "ed25519",
+ 0x0808: "ed448",
+ 0x0809: "rsa_pss_pss_sha256",
+ 0x080A: "rsa_pss_pss_sha384",
+ 0x080B: "rsa_pss_pss_sha512",
+ 0x081A: "ecdsa_brainpoolP256r1tls13_sha256",
+ 0x081B: "ecdsa_brainpoolP384r1tls13_sha384",
+ 0x081C: "ecdsa_brainpoolP512r1tls13_sha512",
+}
+
+var DictSignatureSchemeNameIndexed = map[string]uint16{
+ "rsa_pkcs1_sha1": 0x0201,
+ "Reserved for backward compatibility": 0x0202,
+ "ecdsa_sha1": 0x0203,
+ "rsa_pkcs1_sha256": 0x0401,
+ "ecdsa_secp256r1_sha256": 0x0403,
+ "rsa_pkcs1_sha256_legacy": 0x0420,
+ "rsa_pkcs1_sha384": 0x0501,
+ "ecdsa_secp384r1_sha384": 0x0503,
+ "rsa_pkcs1_sha384_legacy": 0x0520,
+ "rsa_pkcs1_sha512": 0x0601,
+ "ecdsa_secp521r1_sha512": 0x0603,
+ "rsa_pkcs1_sha512_legacy": 0x0620,
+ "eccsi_sha256": 0x0704,
+ "iso_ibs1": 0x0705,
+ "iso_ibs2": 0x0706,
+ "iso_chinese_ibs": 0x0707,
+ "sm2sig_sm3": 0x0708,
+ "gostr34102012_256a": 0x0709,
+ "gostr34102012_256b": 0x070A,
+ "gostr34102012_256c": 0x070B,
+ "gostr34102012_256d": 0x070C,
+ "gostr34102012_512a": 0x070D,
+ "gostr34102012_512b": 0x070E,
+ "gostr34102012_512c": 0x070F,
+ "rsa_pss_rsae_sha256": 0x0804,
+ "rsa_pss_rsae_sha384": 0x0805,
+ "rsa_pss_rsae_sha512": 0x0806,
+ "ed25519": 0x0807,
+ "ed448": 0x0808,
+ "rsa_pss_pss_sha256": 0x0809,
+ "rsa_pss_pss_sha384": 0x080A,
+ "rsa_pss_pss_sha512": 0x080B,
+ "ecdsa_brainpoolP256r1tls13_sha256": 0x081A,
+ "ecdsa_brainpoolP384r1tls13_sha384": 0x081B,
+ "ecdsa_brainpoolP512r1tls13_sha512": 0x081C,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/supplemental_data_formats.go b/vendor/github.com/refraction-networking/utls/dicttls/supplemental_data_formats.go
new file mode 100644
index 00000000..9dd7f176
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/supplemental_data_formats.go
@@ -0,0 +1,19 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-12
+// last updated: March 2023
+
+const (
+ SupplementalDataType_user_mapping_data uint16 = 0
+ SupplementalDataType_authz_data uint16 = 16386
+)
+
+var DictSupplementalDataFormatValueIndexed = map[uint16]string{
+ 0: "user_mapping_data",
+ 16386: "authz_data",
+}
+
+var DictSupplementalDataFormatNameIndexed = map[string]uint16{
+ "user_mapping_data": 0,
+ "authz_data": 16386,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/supported_groups.go b/vendor/github.com/refraction-networking/utls/dicttls/supported_groups.go
new file mode 100644
index 00000000..7c5cb541
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/supported_groups.go
@@ -0,0 +1,157 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+// last updated: March 2023
+
+const (
+ SupportedGroups_sect163k1 uint16 = 1
+ SupportedGroups_sect163r1 uint16 = 2
+ SupportedGroups_sect163r2 uint16 = 3
+ SupportedGroups_sect193r1 uint16 = 4
+ SupportedGroups_sect193r2 uint16 = 5
+ SupportedGroups_sect233k1 uint16 = 6
+ SupportedGroups_sect233r1 uint16 = 7
+ SupportedGroups_sect239k1 uint16 = 8
+ SupportedGroups_sect283k1 uint16 = 9
+ SupportedGroups_sect283r1 uint16 = 10
+ SupportedGroups_sect409k1 uint16 = 11
+ SupportedGroups_sect409r1 uint16 = 12
+ SupportedGroups_sect571k1 uint16 = 13
+ SupportedGroups_sect571r1 uint16 = 14
+ SupportedGroups_secp160k1 uint16 = 15
+ SupportedGroups_secp160r1 uint16 = 16
+ SupportedGroups_secp160r2 uint16 = 17
+ SupportedGroups_secp192k1 uint16 = 18
+ SupportedGroups_secp192r1 uint16 = 19
+ SupportedGroups_secp224k1 uint16 = 20
+ SupportedGroups_secp224r1 uint16 = 21
+ SupportedGroups_secp256k1 uint16 = 22
+ SupportedGroups_secp256r1 uint16 = 23
+ SupportedGroups_secp384r1 uint16 = 24
+ SupportedGroups_secp521r1 uint16 = 25
+ SupportedGroups_brainpoolP256r1 uint16 = 26
+ SupportedGroups_brainpoolP384r1 uint16 = 27
+ SupportedGroups_brainpoolP512r1 uint16 = 28
+ SupportedGroups_x25519 uint16 = 29
+ SupportedGroups_x448 uint16 = 30
+ SupportedGroups_brainpoolP256r1tls13 uint16 = 31
+ SupportedGroups_brainpoolP384r1tls13 uint16 = 32
+ SupportedGroups_brainpoolP512r1tls13 uint16 = 33
+ SupportedGroups_GC256A uint16 = 34
+ SupportedGroups_GC256B uint16 = 35
+ SupportedGroups_GC256C uint16 = 36
+ SupportedGroups_GC256D uint16 = 37
+ SupportedGroups_GC512A uint16 = 38
+ SupportedGroups_GC512B uint16 = 39
+ SupportedGroups_GC512C uint16 = 40
+ SupportedGroups_curveSM2 uint16 = 41
+ SupportedGroups_ffdhe2048 uint16 = 256
+ SupportedGroups_ffdhe3072 uint16 = 257
+ SupportedGroups_ffdhe4096 uint16 = 258
+ SupportedGroups_ffdhe6144 uint16 = 259
+ SupportedGroups_ffdhe8192 uint16 = 260
+ SupportedGroups_arbitrary_explicit_prime_curves uint16 = 65281
+ SupportedGroups_arbitrary_explicit_char2_curves uint16 = 65282
+)
+
+var DictSupportedGroupsValueIndexed = map[uint16]string{
+ 1: "sect163k1",
+ 2: "sect163r1",
+ 3: "sect163r2",
+ 4: "sect193r1",
+ 5: "sect193r2",
+ 6: "sect233k1",
+ 7: "sect233r1",
+ 8: "sect239k1",
+ 9: "sect283k1",
+ 10: "sect283r1",
+ 11: "sect409k1",
+ 12: "sect409r1",
+ 13: "sect571k1",
+ 14: "sect571r1",
+ 15: "secp160k1",
+ 16: "secp160r1",
+ 17: "secp160r2",
+ 18: "secp192k1",
+ 19: "secp192r1",
+ 20: "secp224k1",
+ 21: "secp224r1",
+ 22: "secp256k1",
+ 23: "secp256r1",
+ 24: "secp384r1",
+ 25: "secp521r1",
+ 26: "brainpoolP256r1",
+ 27: "brainpoolP384r1",
+ 28: "brainpoolP512r1",
+ 29: "x25519",
+ 30: "x448",
+ 31: "brainpoolP256r1tls13",
+ 32: "brainpoolP384r1tls13",
+ 33: "brainpoolP512r1tls13",
+ 34: "GC256A",
+ 35: "GC256B",
+ 36: "GC256C",
+ 37: "GC256D",
+ 38: "GC512A",
+ 39: "GC512B",
+ 40: "GC512C",
+ 41: "curveSM2",
+ 256: "ffdhe2048",
+ 257: "ffdhe3072",
+ 258: "ffdhe4096",
+ 259: "ffdhe6144",
+ 260: "ffdhe8192",
+ 65281: "arbitrary_explicit_prime_curves",
+ 65282: "arbitrary_explicit_char2_curves",
+}
+
+var DictSupportedGroupsNameIndexed = map[string]uint16{
+ "sect163k1": 1,
+ "sect163r1": 2,
+ "sect163r2": 3,
+ "sect193r1": 4,
+ "sect193r2": 5,
+ "sect233k1": 6,
+ "sect233r1": 7,
+ "sect239k1": 8,
+ "sect283k1": 9,
+ "sect283r1": 10,
+ "sect409k1": 11,
+ "sect409r1": 12,
+ "sect571k1": 13,
+ "sect571r1": 14,
+ "secp160k1": 15,
+ "secp160r1": 16,
+ "secp160r2": 17,
+ "secp192k1": 18,
+ "secp192r1": 19,
+ "secp224k1": 20,
+ "secp224r1": 21,
+ "secp256k1": 22,
+ "secp256r1": 23,
+ "secp384r1": 24,
+ "secp521r1": 25,
+ "brainpoolP256r1": 26,
+ "brainpoolP384r1": 27,
+ "brainpoolP512r1": 28,
+ "x25519": 29,
+ "x448": 30,
+ "brainpoolP256r1tls13": 31,
+ "brainpoolP384r1tls13": 32,
+ "brainpoolP512r1tls13": 33,
+ "GC256A": 34,
+ "GC256B": 35,
+ "GC256C": 36,
+ "GC256D": 37,
+ "GC512A": 38,
+ "GC512B": 39,
+ "GC512C": 40,
+ "curveSM2": 41,
+ "ffdhe2048": 256,
+ "ffdhe3072": 257,
+ "ffdhe4096": 258,
+ "ffdhe6144": 259,
+ "ffdhe8192": 260,
+ "arbitrary_explicit_prime_curves": 65281,
+ "arbitrary_explicit_char2_curves": 65282,
+}
diff --git a/vendor/github.com/refraction-networking/utls/dicttls/usermappingtype_values.go b/vendor/github.com/refraction-networking/utls/dicttls/usermappingtype_values.go
new file mode 100644
index 00000000..a16d071f
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/dicttls/usermappingtype_values.go
@@ -0,0 +1,16 @@
+package dicttls
+
+// source: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-14
+// last updated: March 2023
+
+const (
+ UserMappingType_upn_domain_hint uint8 = 64
+)
+
+var DictUserMappingTypeValueIndexed = map[uint8]string{
+ 64: "upn_domain_hint",
+}
+
+var DictUserMappingTypeNameIndexed = map[string]uint8{
+ "upn_domain_hint": 64,
+}
diff --git a/vendor/github.com/refraction-networking/utls/ech.go b/vendor/github.com/refraction-networking/utls/ech.go
new file mode 100644
index 00000000..184c4682
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/ech.go
@@ -0,0 +1,646 @@
+// 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.
+
+package tls
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "slices"
+ "strings"
+
+ "github.com/refraction-networking/utls/internal/hpke"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// sortedSupportedAEADs is just a sorted version of hpke.SupportedAEADS.
+// We need this so that when we insert them into ECHConfigs the ordering
+// is stable.
+var sortedSupportedAEADs []uint16
+
+func init() {
+ for aeadID := range hpke.SupportedAEADs {
+ sortedSupportedAEADs = append(sortedSupportedAEADs, aeadID)
+ }
+ slices.Sort(sortedSupportedAEADs)
+}
+
+type echCipher struct {
+ KDFID uint16
+ AEADID uint16
+}
+
+type echExtension struct {
+ Type uint16
+ Data []byte
+}
+
+type echConfig struct {
+ raw []byte
+
+ Version uint16
+ Length uint16
+
+ ConfigID uint8
+ KemID uint16
+ PublicKey []byte
+ SymmetricCipherSuite []echCipher
+
+ MaxNameLength uint8
+ PublicName []byte
+ Extensions []echExtension
+}
+
+var errMalformedECHConfig = errors.New("tls: malformed ECHConfigList")
+
+func parseECHConfig(enc []byte) (skip bool, ec echConfig, err error) {
+ s := cryptobyte.String(enc)
+ ec.raw = []byte(enc)
+ if !s.ReadUint16(&ec.Version) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ if !s.ReadUint16(&ec.Length) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ if len(ec.raw) < int(ec.Length)+4 {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ ec.raw = ec.raw[:ec.Length+4]
+ if ec.Version != extensionEncryptedClientHello {
+ s.Skip(int(ec.Length))
+ return true, echConfig{}, nil
+ }
+ if !s.ReadUint8(&ec.ConfigID) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ if !s.ReadUint16(&ec.KemID) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ if !readUint16LengthPrefixed(&s, &ec.PublicKey) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ var cipherSuites cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&cipherSuites) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ for !cipherSuites.Empty() {
+ var c echCipher
+ if !cipherSuites.ReadUint16(&c.KDFID) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ if !cipherSuites.ReadUint16(&c.AEADID) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c)
+ }
+ if !s.ReadUint8(&ec.MaxNameLength) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ var publicName cryptobyte.String
+ if !s.ReadUint8LengthPrefixed(&publicName) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ ec.PublicName = publicName
+ var extensions cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&extensions) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ for !extensions.Empty() {
+ var e echExtension
+ if !extensions.ReadUint16(&e.Type) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) {
+ return false, echConfig{}, errMalformedECHConfig
+ }
+ ec.Extensions = append(ec.Extensions, e)
+ }
+
+ return false, ec, nil
+}
+
+// parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a
+// slice of parsed ECHConfigs, in the same order they were parsed, or an error
+// if the list is malformed.
+func parseECHConfigList(data []byte) ([]echConfig, error) {
+ s := cryptobyte.String(data)
+ var length uint16
+ if !s.ReadUint16(&length) {
+ return nil, errMalformedECHConfig
+ }
+ if length != uint16(len(data)-2) {
+ return nil, errMalformedECHConfig
+ }
+ var configs []echConfig
+ for len(s) > 0 {
+ if len(s) < 4 {
+ return nil, errors.New("tls: malformed ECHConfig")
+ }
+ configLen := uint16(s[2])<<8 | uint16(s[3])
+ skip, ec, err := parseECHConfig(s)
+ if err != nil {
+ return nil, err
+ }
+ s = s[configLen+4:]
+ if !skip {
+ configs = append(configs, ec)
+ }
+ }
+ return configs, nil
+}
+
+func pickECHConfig(list []echConfig) *echConfig {
+ for _, ec := range list {
+ if _, ok := hpke.SupportedKEMs[ec.KemID]; !ok {
+ continue
+ }
+ var validSCS bool
+ for _, cs := range ec.SymmetricCipherSuite {
+ if _, ok := hpke.SupportedAEADs[cs.AEADID]; !ok {
+ continue
+ }
+ if _, ok := hpke.SupportedKDFs[cs.KDFID]; !ok {
+ continue
+ }
+ validSCS = true
+ break
+ }
+ if !validSCS {
+ continue
+ }
+ if !validDNSName(string(ec.PublicName)) {
+ continue
+ }
+ var unsupportedExt bool
+ for _, ext := range ec.Extensions {
+ // If high order bit is set to 1 the extension is mandatory.
+ // Since we don't support any extensions, if we see a mandatory
+ // bit, we skip the config.
+ if ext.Type&uint16(1<<15) != 0 {
+ unsupportedExt = true
+ }
+ }
+ if unsupportedExt {
+ continue
+ }
+ return &ec
+ }
+ return nil
+}
+
+func pickECHCipherSuite(suites []echCipher) (echCipher, error) {
+ for _, s := range suites {
+ // NOTE: all of the supported AEADs and KDFs are fine, rather than
+ // imposing some sort of preference here, we just pick the first valid
+ // suite.
+ if _, ok := hpke.SupportedAEADs[s.AEADID]; !ok {
+ continue
+ }
+ if _, ok := hpke.SupportedKDFs[s.KDFID]; !ok {
+ continue
+ }
+ return s, nil
+ }
+ return echCipher{}, errors.New("tls: no supported symmetric ciphersuites for ECH")
+}
+
+// [uTLS SECTION BEGIN]
+func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, error) {
+ return encodeInnerClientHelloReorderOuterExts(inner, maxNameLength, nil)
+}
+
+// [uTLS SECTION END]
+
+// func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, error) {
+func encodeInnerClientHelloReorderOuterExts(inner *clientHelloMsg, maxNameLength int, outerExts []uint16) ([]byte, error) { // uTLS
+ h, err := inner.marshalMsgReorderOuterExts(true, outerExts)
+ if err != nil {
+ return nil, err
+ }
+ h = h[4:] // strip four byte prefix
+
+ var paddingLen int
+ if inner.serverName != "" {
+ paddingLen = max(0, maxNameLength-len(inner.serverName))
+ } else {
+ paddingLen = maxNameLength + 9
+ }
+ paddingLen = 31 - ((len(h) + paddingLen - 1) % 32)
+
+ return append(h, make([]byte, paddingLen)...), nil
+}
+
+func skipUint8LengthPrefixed(s *cryptobyte.String) bool {
+ var skip uint8
+ if !s.ReadUint8(&skip) {
+ return false
+ }
+ return s.Skip(int(skip))
+}
+
+func skipUint16LengthPrefixed(s *cryptobyte.String) bool {
+ var skip uint16
+ if !s.ReadUint16(&skip) {
+ return false
+ }
+ return s.Skip(int(skip))
+}
+
+type rawExtension struct {
+ extType uint16
+ data []byte
+}
+
+func extractRawExtensions(hello *clientHelloMsg) ([]rawExtension, error) {
+ s := cryptobyte.String(hello.original)
+ if !s.Skip(4+2+32) || // header, version, random
+ !skipUint8LengthPrefixed(&s) || // session ID
+ !skipUint16LengthPrefixed(&s) || // cipher suites
+ !skipUint8LengthPrefixed(&s) { // compression methods
+ return nil, errors.New("tls: malformed outer client hello")
+ }
+ var rawExtensions []rawExtension
+ var extensions cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&extensions) {
+ return nil, errors.New("tls: malformed outer client hello")
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return nil, errors.New("tls: invalid inner client hello")
+ }
+ rawExtensions = append(rawExtensions, rawExtension{extension, extData})
+ }
+ return rawExtensions, nil
+}
+
+func decodeInnerClientHello(outer *clientHelloMsg, encoded []byte) (*clientHelloMsg, error) {
+ // Reconstructing the inner client hello from its encoded form is somewhat
+ // complicated. It is missing its header (message type and length), session
+ // ID, and the extensions may be compressed. Since we need to put the
+ // extensions back in the same order as they were in the raw outer hello,
+ // and since we don't store the raw extensions, or the order we parsed them
+ // in, we need to reparse the raw extensions from the outer hello in order
+ // to properly insert them into the inner hello. This _should_ result in raw
+ // bytes which match the hello as it was generated by the client.
+ innerReader := cryptobyte.String(encoded)
+ var versionAndRandom, sessionID, cipherSuites, compressionMethods []byte
+ var extensions cryptobyte.String
+ if !innerReader.ReadBytes(&versionAndRandom, 2+32) ||
+ !readUint8LengthPrefixed(&innerReader, &sessionID) ||
+ len(sessionID) != 0 ||
+ !readUint16LengthPrefixed(&innerReader, &cipherSuites) ||
+ !readUint8LengthPrefixed(&innerReader, &compressionMethods) ||
+ !innerReader.ReadUint16LengthPrefixed(&extensions) {
+ return nil, errors.New("tls: invalid inner client hello")
+ }
+
+ // The specification says we must verify that the trailing padding is all
+ // zeros. This is kind of weird for TLS messages, where we generally just
+ // throw away any trailing garbage.
+ for _, p := range innerReader {
+ if p != 0 {
+ return nil, errors.New("tls: invalid inner client hello")
+ }
+ }
+
+ rawOuterExts, err := extractRawExtensions(outer)
+ if err != nil {
+ return nil, err
+ }
+
+ recon := cryptobyte.NewBuilder(nil)
+ recon.AddUint8(typeClientHello)
+ recon.AddUint24LengthPrefixed(func(recon *cryptobyte.Builder) {
+ recon.AddBytes(versionAndRandom)
+ recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) {
+ recon.AddBytes(outer.sessionId)
+ })
+ recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
+ recon.AddBytes(cipherSuites)
+ })
+ recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) {
+ recon.AddBytes(compressionMethods)
+ })
+ recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ recon.SetError(errors.New("tls: invalid inner client hello"))
+ return
+ }
+ if extension == extensionECHOuterExtensions {
+ if !extData.ReadUint8LengthPrefixed(&extData) {
+ recon.SetError(errors.New("tls: invalid inner client hello"))
+ return
+ }
+ var i int
+ for !extData.Empty() {
+ var extType uint16
+ if !extData.ReadUint16(&extType) {
+ recon.SetError(errors.New("tls: invalid inner client hello"))
+ return
+ }
+ if extType == extensionEncryptedClientHello {
+ recon.SetError(errors.New("tls: invalid outer extensions"))
+ return
+ }
+ for ; i <= len(rawOuterExts); i++ {
+ if i == len(rawOuterExts) {
+ recon.SetError(errors.New("tls: invalid outer extensions"))
+ return
+ }
+ if rawOuterExts[i].extType == extType {
+ break
+ }
+ }
+ recon.AddUint16(rawOuterExts[i].extType)
+ recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
+ recon.AddBytes(rawOuterExts[i].data)
+ })
+ }
+ } else {
+ recon.AddUint16(extension)
+ recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) {
+ recon.AddBytes(extData)
+ })
+ }
+ }
+ })
+ })
+
+ reconBytes, err := recon.Bytes()
+ if err != nil {
+ return nil, err
+ }
+ inner := &clientHelloMsg{}
+ if !inner.unmarshal(reconBytes) {
+ return nil, errors.New("tls: invalid reconstructed inner client hello")
+ }
+
+ if !bytes.Equal(inner.encryptedClientHello, []byte{uint8(innerECHExt)}) {
+ return nil, errInvalidECHExt
+ }
+
+ if len(inner.supportedVersions) != 1 || (len(inner.supportedVersions) >= 1 && inner.supportedVersions[0] != VersionTLS13) {
+ return nil, errors.New("tls: client sent encrypted_client_hello extension and offered incompatible versions")
+ }
+
+ return inner, nil
+}
+
+func decryptECHPayload(context *hpke.Receipient, hello, payload []byte) ([]byte, error) {
+ outerAAD := bytes.Replace(hello[4:], payload, make([]byte, len(payload)), 1)
+ return context.Open(outerAAD, payload)
+}
+
+func generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payload []byte) ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(0) // outer
+ b.AddUint16(kdfID)
+ b.AddUint16(aeadID)
+ b.AddUint8(id)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(encodedKey) })
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(payload) })
+ return b.Bytes()
+}
+
+func computeAndUpdateOuterECHExtension(outer, inner *clientHelloMsg, ech *echClientContext, useKey bool) error {
+ var encapKey []byte
+ if useKey {
+ encapKey = ech.encapsulatedKey
+ }
+ encodedInner, err := encodeInnerClientHello(inner, int(ech.config.MaxNameLength))
+ if err != nil {
+ return err
+ }
+ // NOTE: the tag lengths for all of the supported AEADs are the same (16
+ // bytes), so we have hardcoded it here. If we add support for another AEAD
+ // with a different tag length, we will need to change this.
+ encryptedLen := len(encodedInner) + 16 // AEAD tag length
+ outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen))
+ if err != nil {
+ return err
+ }
+ serializedOuter, err := outer.marshal()
+ if err != nil {
+ return err
+ }
+ serializedOuter = serializedOuter[4:] // strip the four byte prefix
+ encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner)
+ if err != nil {
+ return err
+ }
+ outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// validDNSName is a rather rudimentary check for the validity of a DNS name.
+// This is used to check if the public_name in a ECHConfig is valid when we are
+// picking a config. This can be somewhat lax because even if we pick a
+// valid-looking name, the DNS layer will later reject it anyway.
+func validDNSName(name string) bool {
+ if len(name) > 253 {
+ return false
+ }
+ labels := strings.Split(name, ".")
+ if len(labels) <= 1 {
+ return false
+ }
+ for _, l := range labels {
+ labelLen := len(l)
+ if labelLen == 0 {
+ return false
+ }
+ for i, r := range l {
+ if r == '-' && (i == 0 || i == labelLen-1) {
+ return false
+ }
+ if (r < '0' || r > '9') && (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && r != '-' {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// ECHRejectionError is the error type returned when ECH is rejected by a remote
+// server. If the server offered a ECHConfigList to use for retries, the
+// RetryConfigList field will contain this list.
+//
+// The client may treat an ECHRejectionError with an empty set of RetryConfigs
+// as a secure signal from the server.
+type ECHRejectionError struct {
+ RetryConfigList []byte
+}
+
+func (e *ECHRejectionError) Error() string {
+ return "tls: server rejected ECH"
+}
+
+var errMalformedECHExt = errors.New("tls: malformed encrypted_client_hello extension")
+var errInvalidECHExt = errors.New("tls: client sent invalid encrypted_client_hello extension")
+
+type echExtType uint8
+
+const (
+ innerECHExt echExtType = 1
+ outerECHExt echExtType = 0
+)
+
+func parseECHExt(ext []byte) (echType echExtType, cs echCipher, configID uint8, encap []byte, payload []byte, err error) {
+ data := make([]byte, len(ext))
+ copy(data, ext)
+ s := cryptobyte.String(data)
+ var echInt uint8
+ if !s.ReadUint8(&echInt) {
+ err = errMalformedECHExt
+ return
+ }
+ echType = echExtType(echInt)
+ if echType == innerECHExt {
+ if !s.Empty() {
+ err = errMalformedECHExt
+ return
+ }
+ return echType, cs, 0, nil, nil, nil
+ }
+ if echType != outerECHExt {
+ err = errInvalidECHExt
+ return
+ }
+ if !s.ReadUint16(&cs.KDFID) {
+ err = errMalformedECHExt
+ return
+ }
+ if !s.ReadUint16(&cs.AEADID) {
+ err = errMalformedECHExt
+ return
+ }
+ if !s.ReadUint8(&configID) {
+ err = errMalformedECHExt
+ return
+ }
+ if !readUint16LengthPrefixed(&s, &encap) {
+ err = errMalformedECHExt
+ return
+ }
+ if !readUint16LengthPrefixed(&s, &payload) {
+ err = errMalformedECHExt
+ return
+ }
+
+ // NOTE: clone encap and payload so that mutating them does not mutate the
+ // raw extension bytes.
+ return echType, cs, configID, bytes.Clone(encap), bytes.Clone(payload), nil
+}
+
+func marshalEncryptedClientHelloConfigList(configs []EncryptedClientHelloKey) ([]byte, error) {
+ builder := cryptobyte.NewBuilder(nil)
+ builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
+ for _, c := range configs {
+ builder.AddBytes(c.Config)
+ }
+ })
+ return builder.Bytes()
+}
+
+func (c *Conn) processECHClientHello(outer *clientHelloMsg) (*clientHelloMsg, *echServerContext, error) {
+ echType, echCiphersuite, configID, encap, payload, err := parseECHExt(outer.encryptedClientHello)
+ if err != nil {
+ if errors.Is(err, errInvalidECHExt) {
+ c.sendAlert(alertIllegalParameter)
+ } else {
+ c.sendAlert(alertDecodeError)
+ }
+
+ return nil, nil, errInvalidECHExt
+ }
+
+ if echType == innerECHExt {
+ return outer, &echServerContext{inner: true}, nil
+ }
+
+ if len(c.config.EncryptedClientHelloKeys) == 0 {
+ return outer, nil, nil
+ }
+
+ for _, echKey := range c.config.EncryptedClientHelloKeys {
+ skip, config, err := parseECHConfig(echKey.Config)
+ if err != nil || skip {
+ c.sendAlert(alertInternalError)
+ return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys Config: %s", err)
+ }
+ if skip {
+ continue
+ }
+ echPriv, err := hpke.ParseHPKEPrivateKey(config.KemID, echKey.PrivateKey)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return nil, nil, fmt.Errorf("tls: invalid EncryptedClientHelloKeys PrivateKey: %s", err)
+ }
+ info := append([]byte("tls ech\x00"), echKey.Config...)
+ hpkeContext, err := hpke.SetupReceipient(hpke.DHKEM_X25519_HKDF_SHA256, echCiphersuite.KDFID, echCiphersuite.AEADID, echPriv, info, encap)
+ if err != nil {
+ // attempt next trial decryption
+ continue
+ }
+
+ encodedInner, err := decryptECHPayload(hpkeContext, outer.original, payload)
+ if err != nil {
+ // attempt next trial decryption
+ continue
+ }
+
+ // NOTE: we do not enforce that the sent server_name matches the ECH
+ // configs PublicName, since this is not particularly important, and
+ // the client already had to know what it was in order to properly
+ // encrypt the payload. This is only a MAY in the spec, so we're not
+ // doing anything revolutionary.
+
+ echInner, err := decodeInnerClientHello(outer, encodedInner)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return nil, nil, errInvalidECHExt
+ }
+
+ c.echAccepted = true
+
+ return echInner, &echServerContext{
+ hpkeContext: hpkeContext,
+ configID: configID,
+ ciphersuite: echCiphersuite,
+ }, nil
+ }
+
+ return outer, nil, nil
+}
+
+func buildRetryConfigList(keys []EncryptedClientHelloKey) ([]byte, error) {
+ var atLeastOneRetryConfig bool
+ var retryBuilder cryptobyte.Builder
+ retryBuilder.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, c := range keys {
+ if !c.SendAsRetry {
+ continue
+ }
+ atLeastOneRetryConfig = true
+ b.AddBytes(c.Config)
+ }
+ })
+ if !atLeastOneRetryConfig {
+ return nil, nil
+ }
+ return retryBuilder.Bytes()
+}
diff --git a/vendor/github.com/refraction-networking/utls/handshake_client.go b/vendor/github.com/refraction-networking/utls/handshake_client.go
new file mode 100644
index 00000000..bba58a5a
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/handshake_client.go
@@ -0,0 +1,1370 @@
+// 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 tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/mlkem"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "net"
+ "slices"
+ "strings"
+ "time"
+
+ "github.com/refraction-networking/utls/internal/byteorder"
+ "github.com/refraction-networking/utls/internal/fips140tls"
+ "github.com/refraction-networking/utls/internal/hpke"
+ "github.com/refraction-networking/utls/internal/tls13"
+)
+
+type clientHandshakeState struct {
+ c *Conn
+ ctx context.Context
+ serverHello *serverHelloMsg
+ hello *clientHelloMsg
+ suite *cipherSuite
+ finishedHash finishedHash
+ masterSecret []byte
+ session *SessionState // the session being resumed
+ ticket []byte // a fresh ticket received during this handshake
+
+ uconn *UConn // [uTLS]
+}
+
+var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
+
+func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echClientContext, error) {
+ config := c.config
+
+ // [UTLS SECTION START]
+ if len(config.ServerName) == 0 && !config.InsecureSkipVerify && len(config.InsecureServerNameToVerify) == 0 {
+ return nil, nil, nil, errors.New("tls: at least one of ServerName, InsecureSkipVerify or InsecureServerNameToVerify must be specified in the tls.Config")
+ }
+ // [UTLS SECTION END]
+
+ nextProtosLength := 0
+ for _, proto := range config.NextProtos {
+ if l := len(proto); l == 0 || l > 255 {
+ return nil, nil, nil, errors.New("tls: invalid NextProtos value")
+ } else {
+ nextProtosLength += 1 + l
+ }
+ }
+ if nextProtosLength > 0xffff {
+ return nil, nil, nil, errors.New("tls: NextProtos values too large")
+ }
+
+ supportedVersions := config.supportedVersions(roleClient)
+ if len(supportedVersions) == 0 {
+ return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
+ }
+ maxVersion := config.maxSupportedVersion(roleClient)
+
+ hello := &clientHelloMsg{
+ vers: maxVersion,
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ extendedMasterSecret: true,
+ ocspStapling: true,
+ scts: true,
+ serverName: hostnameInSNI(config.ServerName),
+ supportedCurves: config.curvePreferences(maxVersion),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ secureRenegotiationSupported: true,
+ alpnProtocols: config.NextProtos,
+ supportedVersions: supportedVersions,
+ }
+
+ // The version at the beginning of the ClientHello was capped at TLS 1.2
+ // for compatibility reasons. The supported_versions extension is used
+ // to negotiate versions now. See RFC 8446, Section 4.2.1.
+ if hello.vers > VersionTLS12 {
+ hello.vers = VersionTLS12
+ }
+
+ if c.handshakes > 0 {
+ hello.secureRenegotiation = c.clientFinished[:]
+ }
+
+ preferenceOrder := cipherSuitesPreferenceOrder
+ if !hasAESGCMHardwareSupport {
+ preferenceOrder = cipherSuitesPreferenceOrderNoAES
+ }
+ configCipherSuites := config.cipherSuites()
+ hello.cipherSuites = make([]uint16, 0, len(configCipherSuites))
+
+ for _, suiteId := range preferenceOrder {
+ suite := mutualCipherSuite(configCipherSuites, suiteId)
+ if suite == nil {
+ continue
+ }
+ // Don't advertise TLS 1.2-only cipher suites unless
+ // we're attempting TLS 1.2.
+ if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
+ continue
+ }
+ hello.cipherSuites = append(hello.cipherSuites, suiteId)
+ }
+
+ _, err := io.ReadFull(config.rand(), hello.random)
+ if err != nil {
+ return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+ }
+
+ // A random session ID is used to detect when the server accepted a ticket
+ // and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
+ // a compatibility measure (see RFC 8446, Section 4.1.2).
+ //
+ // The session ID is not set for QUIC connections (see RFC 9001, Section 8.4).
+ if c.quic == nil {
+ hello.sessionId = make([]byte, 32)
+ if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {
+ return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+ }
+ }
+
+ if maxVersion >= VersionTLS12 {
+ hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+ if testingOnlyForceClientHelloSignatureAlgorithms != nil {
+ hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
+ }
+
+ var keyShareKeys *keySharePrivateKeys
+ if hello.supportedVersions[0] == VersionTLS13 {
+ // Reset the list of ciphers when the client only supports TLS 1.3.
+ if len(hello.supportedVersions) == 1 {
+ hello.cipherSuites = nil
+ }
+ if fips140tls.Required() {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
+ } else if hasAESGCMHardwareSupport {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
+ } else {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
+ }
+
+ if len(hello.supportedCurves) == 0 {
+ return nil, nil, nil, errors.New("tls: no supported elliptic curves for ECDHE")
+ }
+ curveID := hello.supportedCurves[0]
+ keyShareKeys = &keySharePrivateKeys{curveID: curveID}
+ // Note that if X25519MLKEM768 is supported, it will be first because
+ // the preference order is fixed.
+ if curveID == X25519MLKEM768 {
+ keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ seed := make([]byte, mlkem.SeedSize)
+ if _, err := io.ReadFull(config.rand(), seed); err != nil {
+ return nil, nil, nil, err
+ }
+ keyShareKeys.mlkem, err = mlkem.NewDecapsulationKey768(seed)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ mlkemEncapsulationKey := keyShareKeys.mlkem.EncapsulationKey().Bytes()
+ x25519EphemeralKey := keyShareKeys.ecdhe.PublicKey().Bytes()
+ hello.keyShares = []keyShare{
+ {group: X25519MLKEM768, data: append(mlkemEncapsulationKey, x25519EphemeralKey...)},
+ }
+ // If both X25519MLKEM768 and X25519 are supported, we send both key
+ // shares (as a fallback) and we reuse the same X25519 ephemeral
+ // key, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2.
+ if slices.Contains(hello.supportedCurves, X25519) {
+ hello.keyShares = append(hello.keyShares, keyShare{group: X25519, data: x25519EphemeralKey})
+ }
+ } else {
+ if _, ok := curveForCurveID(curveID); !ok {
+ return nil, nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+ keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), curveID)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ hello.keyShares = []keyShare{{group: curveID, data: keyShareKeys.ecdhe.PublicKey().Bytes()}}
+ }
+ }
+
+ if c.quic != nil {
+ p, err := c.quicGetTransportParameters()
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ if p == nil {
+ p = []byte{}
+ }
+ hello.quicTransportParameters = p
+ }
+
+ var ech *echClientContext
+ if c.config.EncryptedClientHelloConfigList != nil {
+ if c.config.MinVersion != 0 && c.config.MinVersion < VersionTLS13 {
+ return nil, nil, nil, errors.New("tls: MinVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
+ }
+ if c.config.MaxVersion != 0 && c.config.MaxVersion <= VersionTLS12 {
+ return nil, nil, nil, errors.New("tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
+ }
+ echConfigs, err := parseECHConfigList(c.config.EncryptedClientHelloConfigList)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ echConfig := pickECHConfig(echConfigs)
+ if echConfig == nil {
+ return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs")
+ }
+ ech = &echClientContext{config: echConfig}
+ hello.encryptedClientHello = []byte{1} // indicate inner hello
+ // We need to explicitly set these 1.2 fields to nil, as we do not
+ // marshal them when encoding the inner hello, otherwise transcripts
+ // will later mismatch.
+ hello.supportedPoints = nil
+ hello.ticketSupported = false
+ hello.secureRenegotiationSupported = false
+ hello.extendedMasterSecret = false
+
+ echPK, err := hpke.ParseHPKEPublicKey(ech.config.KemID, ech.config.PublicKey)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ suite, err := pickECHCipherSuite(ech.config.SymmetricCipherSuite)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ ech.kdfID, ech.aeadID = suite.KDFID, suite.AEADID
+ info := append([]byte("tls ech\x00"), ech.config.raw...)
+ ech.encapsulatedKey, ech.hpkeContext, err = hpke.SetupSender(ech.config.KemID, suite.KDFID, suite.AEADID, echPK, info)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ }
+
+ return hello, keyShareKeys, ech, nil
+}
+
+type echClientContext struct {
+ config *echConfig
+ hpkeContext *hpke.Sender
+ encapsulatedKey []byte
+ innerHello *clientHelloMsg
+ innerTranscript hash.Hash
+ kdfID uint16
+ aeadID uint16
+ echRejected bool
+ retryConfigs []byte
+}
+
+func (c *Conn) clientHandshake(ctx context.Context) (err error) {
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
+
+ // This may be a renegotiation handshake, in which case some fields
+ // need to be reset.
+ c.didResume = false
+
+ hello, keyShareKeys, ech, err := c.makeClientHello()
+ if err != nil {
+ return err
+ }
+
+ session, earlySecret, binderKey, err := c.loadSession(hello)
+ if err != nil {
+ return err
+ }
+ if session != nil {
+ defer func() {
+ // If we got a handshake failure when resuming a session, throw away
+ // the session ticket. See RFC 5077, Section 3.2.
+ //
+ // RFC 8446 makes no mention of dropping tickets on failure, but it
+ // does require servers to abort on invalid binders, so we need to
+ // delete tickets to recover from a corrupted PSK.
+ if err != nil {
+ if cacheKey := c.clientSessionCacheKey(); cacheKey != "" {
+ c.config.ClientSessionCache.Put(cacheKey, nil)
+ }
+ }
+ }()
+ }
+
+ if ech != nil {
+ // Split hello into inner and outer
+ ech.innerHello = hello.clone()
+
+ // Overwrite the server name in the outer hello with the public facing
+ // name.
+ hello.serverName = string(ech.config.PublicName)
+ // Generate a new random for the outer hello.
+ hello.random = make([]byte, 32)
+ _, err = io.ReadFull(c.config.rand(), hello.random)
+ if err != nil {
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+
+ // NOTE: we don't do PSK GREASE, in line with boringssl, it's meant to
+ // work around _possibly_ broken middleboxes, but there is little-to-no
+ // evidence that this is actually a problem.
+
+ if err := computeAndUpdateOuterECHExtension(hello, ech.innerHello, ech, true); err != nil {
+ return err
+ }
+ }
+
+ c.serverName = hello.serverName
+
+ if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
+ return err
+ }
+
+ if hello.earlyData {
+ suite := cipherSuiteTLS13ByID(session.cipherSuite)
+ transcript := suite.hash.New()
+ if err := transcriptMsg(hello, transcript); err != nil {
+ return err
+ }
+ earlyTrafficSecret := earlySecret.ClientEarlyTrafficSecret(transcript)
+ c.quicSetWriteSecret(QUICEncryptionLevelEarly, suite.id, earlyTrafficSecret)
+ }
+
+ // serverHelloMsg is not included in the transcript
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
+ }
+
+ if err := c.pickTLSVersion(serverHello); err != nil {
+ return err
+ }
+
+ // If we are negotiating a protocol version that's lower than what we
+ // support, check for the server downgrade canaries.
+ // See RFC 8446, Section 4.1.3.
+ maxVers := c.config.maxSupportedVersion(roleClient)
+ tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
+ tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
+ if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
+ maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox")
+ }
+
+ if c.vers == VersionTLS13 {
+ hs := &clientHandshakeStateTLS13{
+ c: c,
+ ctx: ctx,
+ serverHello: serverHello,
+ hello: hello,
+ keyShareKeys: keyShareKeys,
+ session: session,
+ earlySecret: earlySecret,
+ binderKey: binderKey,
+ echContext: ech,
+ }
+ return hs.handshake()
+ }
+
+ hs := &clientHandshakeState{
+ c: c,
+ ctx: ctx,
+ serverHello: serverHello,
+ hello: hello,
+ session: session,
+ }
+ return hs.handshake()
+}
+
+func (c *Conn) loadSession(hello *clientHelloMsg) (
+ session *SessionState, earlySecret *tls13.EarlySecret, binderKey []byte, err error) {
+ // [UTLS SECTION START]
+ if c.utls.sessionController != nil {
+ c.utls.sessionController.onEnterLoadSessionCheck()
+ defer c.utls.sessionController.onLoadSessionReturn()
+ }
+ // [UTLS SECTION END]
+ if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
+ return nil, nil, nil, nil
+ }
+
+ echInner := bytes.Equal(hello.encryptedClientHello, []byte{1})
+
+ // ticketSupported is a TLS 1.2 extension (as TLS 1.3 replaced tickets with PSK
+ // identities) and ECH requires and forces TLS 1.3.
+ hello.ticketSupported = true && !echInner
+
+ if hello.supportedVersions[0] == VersionTLS13 {
+ // Require DHE on resumption as it guarantees forward secrecy against
+ // compromise of the session ticket key. See RFC 8446, Section 4.2.9.
+ hello.pskModes = []uint8{pskModeDHE}
+ }
+
+ // Session resumption is not allowed if renegotiating because
+ // renegotiation is primarily used to allow a client to send a client
+ // certificate, which would be skipped if session resumption occurred.
+ if c.handshakes != 0 {
+ return nil, nil, nil, nil
+ }
+
+ // Try to resume a previously negotiated TLS session, if available.
+ cacheKey := c.clientSessionCacheKey()
+ if cacheKey == "" {
+ return nil, nil, nil, nil
+ }
+ cs, ok := c.config.ClientSessionCache.Get(cacheKey)
+ if !ok || cs == nil {
+ return nil, nil, nil, nil
+ }
+ session = cs.session
+
+ // Check that version used for the previous session is still valid.
+ versOk := false
+ for _, v := range hello.supportedVersions {
+ if v == session.version {
+ versOk = true
+ break
+ }
+ }
+ if !versOk {
+ return nil, nil, nil, nil
+ }
+
+ // Check that the cached server certificate is not expired, and that it's
+ // valid for the ServerName. This should be ensured by the cache key, but
+ // protect the application from a faulty ClientSessionCache implementation.
+ // [UTLS SECTION START]
+ if !c.config.InsecureSkipTimeVerify {
+ if c.config.time().After(session.peerCertificates[0].NotAfter) {
+ // Expired certificate, delete the entry.
+ c.config.ClientSessionCache.Put(cacheKey, nil)
+ return nil, nil, nil, nil
+ }
+ }
+ // [UTLS SECTION END]
+ if !c.config.InsecureSkipVerify {
+ if len(session.verifiedChains) == 0 {
+ // The original connection had InsecureSkipVerify, while this doesn't.
+ return nil, nil, nil, nil
+ }
+ // [UTLS SECTION START]
+ var dnsName string
+ if len(c.config.InsecureServerNameToVerify) == 0 {
+ dnsName = c.config.ServerName
+ } else if c.config.InsecureServerNameToVerify != "*" {
+ dnsName = c.config.InsecureServerNameToVerify
+ }
+ if len(dnsName) > 0 {
+ if err := session.peerCertificates[0].VerifyHostname(dnsName); err != nil {
+ return nil, nil, nil, nil
+ }
+ }
+ // [UTLS SECTION END]
+ }
+
+ if session.version != VersionTLS13 {
+ // In TLS 1.2 the cipher suite must match the resumed session. Ensure we
+ // are still offering it.
+ if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil {
+ return nil, nil, nil, nil
+ }
+
+ hello.sessionTicket = session.ticket
+ return
+ }
+
+ // Check that the session ticket is not expired.
+ if c.config.time().After(time.Unix(int64(session.useBy), 0)) {
+ c.config.ClientSessionCache.Put(cacheKey, nil)
+ return nil, nil, nil, nil
+ }
+
+ // In TLS 1.3 the KDF hash must match the resumed session. Ensure we
+ // offer at least one cipher suite with that hash.
+ cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
+ if cipherSuite == nil {
+ return nil, nil, nil, nil
+ }
+ cipherSuiteOk := false
+ for _, offeredID := range hello.cipherSuites {
+ offeredSuite := cipherSuiteTLS13ByID(offeredID)
+ if offeredSuite != nil && offeredSuite.hash == cipherSuite.hash {
+ cipherSuiteOk = true
+ break
+ }
+ }
+ if !cipherSuiteOk {
+ return nil, nil, nil, nil
+ }
+
+ if c.quic != nil {
+ if c.quic.enableSessionEvents {
+ c.quicResumeSession(session)
+ }
+
+ // For 0-RTT, the cipher suite has to match exactly, and we need to be
+ // offering the same ALPN.
+ if session.EarlyData && mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil {
+ for _, alpn := range hello.alpnProtocols {
+ if alpn == session.alpnProtocol {
+ hello.earlyData = true
+ break
+ }
+ }
+ }
+ }
+
+ // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
+ ticketAge := c.config.time().Sub(time.Unix(int64(session.createdAt), 0))
+ identity := pskIdentity{
+ label: session.ticket,
+ obfuscatedTicketAge: uint32(ticketAge/time.Millisecond) + session.ageAdd,
+ }
+ hello.pskIdentities = []pskIdentity{identity}
+ hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())}
+
+ // Compute the PSK binders. See RFC 8446, Section 4.2.11.2.
+ earlySecret = tls13.NewEarlySecret(cipherSuite.hash.New, session.secret)
+ binderKey = earlySecret.ResumptionBinderKey()
+ // [UTLS SECTION START]
+ if c.utls.sessionController != nil && !c.utls.sessionController.shouldLoadSessionWriteBinders() {
+ return
+ }
+ // [UTLS SECTION END]
+ transcript := cipherSuite.hash.New()
+ if err := computeAndUpdatePSK(hello, binderKey, transcript, cipherSuite.finishedHash); err != nil {
+ return nil, nil, nil, err
+ }
+
+ return
+}
+
+func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error {
+ peerVersion := serverHello.vers
+ if serverHello.supportedVersion != 0 {
+ peerVersion = serverHello.supportedVersion
+ }
+
+ vers, ok := c.config.mutualVersion(roleClient, []uint16{peerVersion})
+ if !ok {
+ c.sendAlert(alertProtocolVersion)
+ return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion)
+ }
+
+ c.vers = vers
+ c.haveVers = true
+ c.in.version = vers
+ c.out.version = vers
+
+ return nil
+}
+
+// Does the handshake, either a full one or resumes old session. Requires hs.c,
+// hs.hello, hs.serverHello, and, optionally, hs.session to be set.
+func (hs *clientHandshakeState) handshake() error {
+ c := hs.c
+
+ isResume, err := hs.processServerHello()
+ if err != nil {
+ return err
+ }
+
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+
+ // No signatures of the handshake are needed in a resumption.
+ // Otherwise, in a full handshake, if we don't have any certificates
+ // configured then we will never send a CertificateVerify message and
+ // thus no signatures are needed in that case either.
+ if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) {
+ hs.finishedHash.discardHandshakeBuffer()
+ }
+
+ if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil {
+ return err
+ }
+ if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ c.buffering = true
+ c.didResume = isResume
+ if isResume {
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = false
+ // Make sure the connection is still being verified whether or not this
+ // is a resumption. Resumptions currently don't reverify certificates so
+ // they don't call verifyServerCertificate. See Issue 31641.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+ if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ } else {
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = true
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ }
+ if err := hs.saveSessionTicket(); err != nil {
+ return err
+ }
+
+ c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+func (hs *clientHandshakeState) pickCipherSuite() error {
+ if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil {
+ hs.c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server chose an unconfigured cipher suite")
+ }
+
+ // [UTLS SECTION START]
+ // if hs.c.config.CipherSuites == nil && !fips140tls.Required() && rsaKexCiphers[hs.suite.id] {
+ // tlsrsakex.Value() // ensure godebug is initialized
+ // tlsrsakex.IncNonDefault()
+ // }
+ // if hs.c.config.CipherSuites == nil && !fips140tls.Required() && tdesCiphers[hs.suite.id] {
+ // tls3des.Value() // ensure godebug is initialized
+ // tls3des.IncNonDefault()
+ // }
+ // [UTLS SECTION END]
+
+ hs.c.cipherSuite = hs.suite.id
+ return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok || len(certMsg.certificates) == 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+
+ cs, ok := msg.(*certificateStatusMsg)
+ if ok {
+ // RFC4366 on Certificate Status Request:
+ // The server MAY return a "certificate_status" message.
+
+ if !hs.serverHello.ocspStapling {
+ // If a server returns a "CertificateStatus" message, then the
+ // server MUST have included an extension of type "status_request"
+ // with empty "extension_data" in the extended server hello.
+
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: received unexpected CertificateStatus message")
+ }
+
+ c.ocspResponse = cs.response
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+
+ if c.handshakes == 0 {
+ // If this is the first handshake on a connection, process and
+ // (optionally) verify the server's certificates.
+ if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
+ return err
+ }
+ } else {
+ // This is a renegotiation handshake. We require that the
+ // server's identity (i.e. leaf certificate) is unchanged and
+ // thus any previous trust decision is still valid.
+ //
+ // See https://mitls.org/pages/attacks/3SHAKE for the
+ // motivation behind this requirement.
+ if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: server's identity changed during renegotiation")
+ }
+ }
+
+ keyAgreement := hs.suite.ka(c.vers)
+
+ skx, ok := msg.(*serverKeyExchangeMsg)
+ if ok {
+ err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ {
+ c.curveID = CurveID(byteorder.BEUint16(skx.key[1:]))
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+
+ var chainToSend *Certificate
+ var certRequested bool
+ certReq, ok := msg.(*certificateRequestMsg)
+ if ok {
+ certRequested = true
+
+ cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
+ if chainToSend, err = c.getClientCertificate(cri); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+
+ shd, ok := msg.(*serverHelloDoneMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(shd, msg)
+ }
+
+ // If the server requested a certificate then we have to send a
+ // Certificate message, even if it's empty because we don't have a
+ // certificate to send.
+ if certRequested {
+ certMsg = new(certificateMsg)
+ certMsg.certificates = chainToSend.Certificate
+ if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ if ckx != nil {
+ if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ if hs.serverHello.extendedMasterSecret {
+ c.extMasterSecret = true
+ hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+ hs.finishedHash.Sum())
+ } else {
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+ hs.hello.random, hs.serverHello.random)
+ }
+ if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to write to key log: " + err.Error())
+ }
+
+ if chainToSend != nil && len(chainToSend.Certificate) > 0 {
+ certVerify := &certificateVerifyMsg{}
+
+ key, ok := chainToSend.PrivateKey.(crypto.Signer)
+ if !ok {
+ c.sendAlert(alertInternalError)
+ return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
+ }
+
+ var sigType uint8
+ var sigHash crypto.Hash
+ if c.vers >= VersionTLS12 {
+ signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ certVerify.hasSignatureAlgorithm = true
+ certVerify.signatureAlgorithm = signatureAlgorithm
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public())
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ }
+
+ signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ hs.finishedHash.discardHandshakeBuffer()
+
+ return nil
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+ c := hs.c
+
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+ var clientCipher, serverCipher any
+ var clientHash, serverHash hash.Hash
+ if hs.suite.cipher != nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+ clientHash = hs.suite.mac(clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+ serverHash = hs.suite.mac(serverMAC)
+ } else {
+ clientCipher = hs.suite.aead(clientKey, clientIV)
+ serverCipher = hs.suite.aead(serverKey, serverIV)
+ }
+
+ c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+ c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
+ return nil
+}
+
+func (hs *clientHandshakeState) serverResumedSession() bool {
+ // If the server responded with the same sessionId then it means the
+ // sessionTicket is being used to resume a TLS session.
+ return hs.session != nil && hs.hello.sessionId != nil &&
+ bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
+
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+ c := hs.c
+
+ if err := hs.pickCipherSuite(); err != nil {
+ return false, err
+ }
+
+ if hs.serverHello.compressionMethod != compressionNone {
+ c.sendAlert(alertUnexpectedMessage)
+ return false, errors.New("tls: server selected unsupported compression format")
+ }
+
+ if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
+ c.secureRenegotiation = true
+ if len(hs.serverHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+ }
+
+ if c.handshakes > 0 && c.secureRenegotiation {
+ var expectedSecureRenegotiation [24]byte
+ copy(expectedSecureRenegotiation[:], c.clientFinished[:])
+ copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
+ if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: incorrect renegotiation extension contents")
+ }
+ }
+
+ if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol, false); err != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return false, err
+ }
+ c.clientProtocol = hs.serverHello.alpnProtocol
+
+ c.scts = hs.serverHello.scts
+
+ if !hs.serverResumedSession() {
+ return false, nil
+ }
+
+ if hs.session.version != c.vers {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: server resumed a session with a different version")
+ }
+
+ if hs.session.cipherSuite != hs.suite.id {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: server resumed a session with a different cipher suite")
+ }
+
+ // RFC 7627, Section 5.3
+ if hs.session.extMasterSecret != hs.serverHello.extendedMasterSecret {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: server resumed a session with a different EMS extension")
+ }
+
+ // Restore master secret and certificates from previous state
+ hs.masterSecret = hs.session.secret
+ c.extMasterSecret = hs.session.extMasterSecret
+ c.peerCertificates = hs.session.peerCertificates
+ c.activeCertHandles = hs.c.activeCertHandles
+ c.verifiedChains = hs.session.verifiedChains
+ c.ocspResponse = hs.session.ocspResponse
+ // Let the ServerHello SCTs override the session SCTs from the original
+ // connection, if any are provided
+ if len(c.scts) == 0 && len(hs.session.scts) != 0 {
+ c.scts = hs.session.scts
+ }
+
+ return true, nil
+}
+
+// checkALPN ensure that the server's choice of ALPN protocol is compatible with
+// the protocols that we advertised in the ClientHello.
+func checkALPN(clientProtos []string, serverProto string, quic bool) error {
+ if serverProto == "" {
+ if quic && len(clientProtos) > 0 {
+ // RFC 9001, Section 8.1
+ return errors.New("tls: server did not select an ALPN protocol")
+ }
+ return nil
+ }
+ if len(clientProtos) == 0 {
+ return errors.New("tls: server advertised unrequested ALPN extension")
+ }
+ for _, proto := range clientProtos {
+ if proto == serverProto {
+ return nil
+ }
+ }
+ return errors.New("tls: server selected unadvertised ALPN protocol")
+}
+
+func (hs *clientHandshakeState) readFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.readChangeCipherSpec(); err != nil {
+ return err
+ }
+
+ // finishedMsg is included in the transcript, but not until after we
+ // check the client version, since the state before this message was
+ // sent is used during verification.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ serverFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverFinished, msg)
+ }
+
+ verify := hs.finishedHash.serverSum(hs.masterSecret)
+ if len(verify) != len(serverFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server's Finished message was incorrect")
+ }
+
+ if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ copy(out, verify)
+ return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+ if !hs.serverHello.ticketSupported {
+ return nil
+ }
+ c := hs.c
+
+ if !hs.hello.ticketSupported {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server sent unrequested session ticket")
+ }
+
+ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(sessionTicketMsg, msg)
+ }
+
+ hs.ticket = sessionTicketMsg.ticket
+ return nil
+}
+
+func (hs *clientHandshakeState) saveSessionTicket() error {
+ if hs.ticket == nil {
+ return nil
+ }
+ c := hs.c
+
+ cacheKey := c.clientSessionCacheKey()
+ if cacheKey == "" {
+ return nil
+ }
+
+ session := c.sessionState()
+ session.secret = hs.masterSecret
+ session.ticket = hs.ticket
+
+ cs := &ClientSessionState{session: session}
+ // [UTLS BEGIN]
+ if c.config.ClientSessionCache != nil { // skip saving session if cache is nil
+ c.config.ClientSessionCache.Put(cacheKey, cs)
+ }
+ // [UTLS END]
+ return nil
+}
+
+func (hs *clientHandshakeState) sendFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.writeChangeCipherRecord(); err != nil {
+ return err
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+ if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
+ return err
+ }
+ copy(out, finished.verifyData)
+ return nil
+}
+
+// defaultMaxRSAKeySize is the maximum RSA key size in bits that we are willing
+// to verify the signatures of during a TLS handshake.
+const defaultMaxRSAKeySize = 8192
+
+// var tlsmaxrsasize = godebug.New("tlsmaxrsasize") // [uTLS] unused
+
+func checkKeySize(n int) (max int, ok bool) {
+ // [uTLS SECTION START]
+ // Disable the unsupported godebug package
+ // if v := tlsmaxrsasize.Value(); v != "" {
+ // if max, err := strconv.Atoi(v); err == nil {
+ // if (n <= max) != (n <= defaultMaxRSAKeySize) {
+ // tlsmaxrsasize.IncNonDefault()
+ // }
+ // return max, n <= max
+ // }
+ // }
+ // [uTLS SECTION END]
+ return defaultMaxRSAKeySize, n <= defaultMaxRSAKeySize
+}
+
+// verifyServerCertificate parses and verifies the provided chain, setting
+// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
+func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
+ activeHandles := make([]*activeCert, len(certificates))
+ certs := make([]*x509.Certificate, len(certificates))
+ for i, asn1Data := range certificates {
+ cert, err := globalCertCache.newCert(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ }
+ if cert.cert.PublicKeyAlgorithm == x509.RSA {
+ n := cert.cert.PublicKey.(*rsa.PublicKey).N.BitLen()
+ if max, ok := checkKeySize(n); !ok {
+ c.sendAlert(alertBadCertificate)
+ return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", max)
+ }
+ }
+ activeHandles[i] = cert
+ certs[i] = cert.cert
+ }
+
+ echRejected := c.config.EncryptedClientHelloConfigList != nil && !c.echAccepted
+ if echRejected {
+ if c.config.EncryptedClientHelloRejectionVerify != nil {
+ if err := c.config.EncryptedClientHelloRejectionVerify(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ } else {
+ opts := x509.VerifyOptions{
+ Roots: c.config.RootCAs,
+ CurrentTime: c.config.time(),
+ // DNSName: c.serverName, // [uTLS]
+ Intermediates: x509.NewCertPool(),
+ }
+
+ // [UTLS SECTION START]
+ if c.config.InsecureSkipTimeVerify {
+ opts.CurrentTime = certs[0].NotAfter
+ }
+
+ if len(c.config.InsecureServerNameToVerify) == 0 {
+ opts.DNSName = c.config.ServerName
+ } else if c.config.InsecureServerNameToVerify != "*" {
+ opts.DNSName = c.config.InsecureServerNameToVerify
+ }
+ // [UTLS SECTION END]
+
+ for _, cert := range certs[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+ chains, err := certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+
+ c.verifiedChains, err = fipsAllowedChains(chains)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+ }
+ } else if !c.config.InsecureSkipVerify {
+ // [UTLS SECTION START]
+ opts := x509.VerifyOptions{
+ Roots: c.config.RootCAs,
+ CurrentTime: c.config.time(),
+ // DNSName: c.serverName, // [uTLS]
+ Intermediates: x509.NewCertPool(),
+ }
+
+ if c.config.InsecureSkipTimeVerify {
+ opts.CurrentTime = certs[0].NotAfter
+ }
+
+ if len(c.config.InsecureServerNameToVerify) == 0 {
+ opts.DNSName = c.config.ServerName
+ } else if c.config.InsecureServerNameToVerify != "*" {
+ opts.DNSName = c.config.InsecureServerNameToVerify
+ }
+ // [UTLS SECTION END]
+
+ for _, cert := range certs[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+ chains, err := certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+
+ c.verifiedChains, err = fipsAllowedChains(chains)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+ }
+
+ switch certs[0].PublicKey.(type) {
+ case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
+ break
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+ }
+
+ c.activeCertHandles = activeHandles
+ c.peerCertificates = certs
+
+ if c.config.VerifyPeerCertificate != nil && !echRejected {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ if c.config.VerifyConnection != nil && !echRejected {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ return nil
+}
+
+// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
+// <= 1.2 CertificateRequest, making an effort to fill in missing information.
+func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
+ cri := &CertificateRequestInfo{
+ AcceptableCAs: certReq.certificateAuthorities,
+ Version: vers,
+ ctx: ctx,
+ }
+
+ var rsaAvail, ecAvail bool
+ for _, certType := range certReq.certificateTypes {
+ switch certType {
+ case certTypeRSASign:
+ rsaAvail = true
+ case certTypeECDSASign:
+ ecAvail = true
+ }
+ }
+
+ if !certReq.hasSignatureAlgorithm {
+ // Prior to TLS 1.2, signature schemes did not exist. In this case we
+ // make up a list based on the acceptable certificate types, to help
+ // GetClientCertificate and SupportsCertificate select the right certificate.
+ // The hash part of the SignatureScheme is a lie here, because
+ // TLS 1.0 and 1.1 always use MD5+SHA1 for RSA and SHA1 for ECDSA.
+ switch {
+ case rsaAvail && ecAvail:
+ cri.SignatureSchemes = []SignatureScheme{
+ ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+ PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+ }
+ case rsaAvail:
+ cri.SignatureSchemes = []SignatureScheme{
+ PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+ }
+ case ecAvail:
+ cri.SignatureSchemes = []SignatureScheme{
+ ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+ }
+ }
+ return cri
+ }
+
+ // Filter the signature schemes based on the certificate types.
+ // See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated").
+ cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms))
+ for _, sigScheme := range certReq.supportedSignatureAlgorithms {
+ sigType, _, err := typeAndHashFromSignatureScheme(sigScheme)
+ if err != nil {
+ continue
+ }
+ switch sigType {
+ case signatureECDSA, signatureEd25519:
+ if ecAvail {
+ cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
+ }
+ case signatureRSAPSS, signaturePKCS1v15:
+ if rsaAvail {
+ cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
+ }
+ }
+ }
+
+ return cri
+}
+
+func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) {
+ if c.config.GetClientCertificate != nil {
+ return c.config.GetClientCertificate(cri)
+ }
+
+ for _, chain := range c.config.Certificates {
+ if err := cri.SupportsCertificate(&chain); err != nil {
+ continue
+ }
+ return &chain, nil
+ }
+
+ // No acceptable certificate found. Don't send a certificate.
+ return new(Certificate), nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func (c *Conn) clientSessionCacheKey() string {
+ if len(c.config.ServerName) > 0 {
+ return c.config.ServerName
+ }
+ if c.conn != nil {
+ return c.conn.RemoteAddr().String()
+ }
+ return ""
+}
+
+// hostnameInSNI converts name into an appropriate hostname for SNI.
+// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
+// See RFC 6066, Section 3.
+func hostnameInSNI(name string) string {
+ host := name
+ if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+ host = host[1 : len(host)-1]
+ }
+ if i := strings.LastIndex(host, "%"); i > 0 {
+ host = host[:i]
+ }
+ if net.ParseIP(host) != nil {
+ return ""
+ }
+ for len(name) > 0 && name[len(name)-1] == '.' {
+ name = name[:len(name)-1]
+ }
+ return name
+}
+
+func computeAndUpdatePSK(m *clientHelloMsg, binderKey []byte, transcript hash.Hash, finishedHash func([]byte, hash.Hash) []byte) error {
+ helloBytes, err := m.marshalWithoutBinders()
+ if err != nil {
+ return err
+ }
+ transcript.Write(helloBytes)
+ pskBinders := [][]byte{finishedHash(binderKey, transcript)}
+ return m.updateBinders(pskBinders)
+}
diff --git a/vendor/github.com/refraction-networking/utls/handshake_client_tls13.go b/vendor/github.com/refraction-networking/utls/handshake_client_tls13.go
new file mode 100644
index 00000000..01c2756c
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/handshake_client_tls13.go
@@ -0,0 +1,1079 @@
+// 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 tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdh"
+ "crypto/hmac"
+ "crypto/mlkem"
+ "crypto/rsa"
+ "crypto/subtle"
+ "errors"
+ "fmt"
+ "hash"
+ "slices"
+ "time"
+
+ "github.com/refraction-networking/utls/internal/hkdf"
+ "github.com/refraction-networking/utls/internal/tls13"
+)
+
+type clientHandshakeStateTLS13 struct {
+ c *Conn
+ ctx context.Context
+ serverHello *serverHelloMsg
+ hello *clientHelloMsg
+ keyShareKeys *keySharePrivateKeys
+
+ session *SessionState
+ earlySecret *tls13.EarlySecret
+ binderKey []byte
+
+ certReq *certificateRequestMsgTLS13
+ usingPSK bool
+ sentDummyCCS bool
+ suite *cipherSuiteTLS13
+ transcript hash.Hash
+ masterSecret *tls13.MasterSecret
+ trafficSecret []byte // client_application_traffic_secret_0
+
+ echContext *echClientContext
+
+ uconn *UConn // [uTLS]
+}
+
+// handshake requires hs.c, hs.hello, hs.serverHello, hs.keyShareKeys, and,
+// optionally, hs.session, hs.earlySecret and hs.binderKey to be set.
+func (hs *clientHandshakeStateTLS13) handshake() error {
+ c := hs.c
+
+ // The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
+ // sections 4.1.2 and 4.1.3.
+ if c.handshakes > 0 {
+ c.sendAlert(alertProtocolVersion)
+ return errors.New("tls: server selected TLS 1.3 in a renegotiation")
+ }
+
+ // Consistency check on the presence of a keyShare and its parameters.
+ if hs.keyShareKeys == nil || hs.keyShareKeys.ecdhe == nil || len(hs.hello.keyShares) == 0 {
+ return c.sendAlert(alertInternalError)
+ }
+
+ if err := hs.checkServerHelloOrHRR(); err != nil {
+ return err
+ }
+
+ hs.transcript = hs.suite.hash.New()
+
+ if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
+ return err
+ }
+
+ if hs.echContext != nil {
+ hs.echContext.innerTranscript = hs.suite.hash.New()
+ // [uTLS SECTION BEGIN]
+ if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
+ if err := hs.uconn.echTranscriptMsg(hs.hello, hs.echContext); err != nil {
+ return err
+ }
+ } else {
+ if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil {
+ return err
+ }
+ }
+ // [uTLS SECTION END]
+ }
+
+ if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return err
+ }
+ if err := hs.processHelloRetryRequest(); err != nil {
+ return err
+ }
+ }
+
+ if hs.echContext != nil {
+ confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash)
+ confTranscript.Write(hs.serverHello.original[:30])
+ confTranscript.Write(make([]byte, 8))
+ confTranscript.Write(hs.serverHello.original[38:])
+ acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New,
+ hkdf.Extract(hs.suite.hash.New, hs.echContext.innerHello.random, nil),
+ "ech accept confirmation",
+ confTranscript.Sum(nil),
+ 8,
+ )
+ if subtle.ConstantTimeCompare(acceptConfirmation, hs.serverHello.random[len(hs.serverHello.random)-8:]) == 1 {
+ hs.hello = hs.echContext.innerHello
+ c.serverName = c.config.ServerName
+ hs.transcript = hs.echContext.innerTranscript
+ c.echAccepted = true
+
+ if hs.serverHello.encryptedClientHello != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected encrypted client hello extension in server hello despite ECH being accepted")
+ }
+
+ if hs.hello.serverName == "" && hs.serverHello.serverNameAck {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected server_name extension in server hello")
+ }
+ } else {
+ hs.echContext.echRejected = true
+ }
+ }
+
+ if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
+ return err
+ }
+
+ c.buffering = true
+ if err := hs.processServerHello(); err != nil {
+ return err
+ }
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return err
+ }
+ if err := hs.establishHandshakeKeys(); err != nil {
+ return err
+ }
+ if err := hs.readServerParameters(); err != nil {
+ return err
+ }
+ if err := hs.readServerCertificate(); err != nil {
+ return err
+ }
+ if err := hs.readServerFinished(); err != nil {
+ return err
+ }
+ // [UTLS SECTION START]
+ if err := hs.serverFinishedReceived(); err != nil {
+ return err
+ }
+ // [UTLS SECTION END]
+ if err := hs.sendClientCertificate(); err != nil {
+ return err
+ }
+ if err := hs.sendClientFinished(); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+
+ if hs.echContext != nil && hs.echContext.echRejected {
+ c.sendAlert(alertECHRequired)
+ return &ECHRejectionError{hs.echContext.retryConfigs}
+ }
+
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+// checkServerHelloOrHRR does validity checks that apply to both ServerHello and
+// HelloRetryRequest messages. It sets hs.suite.
+func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error {
+ c := hs.c
+
+ if hs.serverHello.supportedVersion == 0 {
+ c.sendAlert(alertMissingExtension)
+ return errors.New("tls: server selected TLS 1.3 using the legacy version field")
+ }
+
+ if hs.serverHello.supportedVersion != VersionTLS13 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected an invalid version after a HelloRetryRequest")
+ }
+
+ if hs.serverHello.vers != VersionTLS12 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server sent an incorrect legacy version")
+ }
+
+ if hs.serverHello.ocspStapling ||
+ hs.serverHello.ticketSupported ||
+ hs.serverHello.extendedMasterSecret ||
+ hs.serverHello.secureRenegotiationSupported ||
+ len(hs.serverHello.secureRenegotiation) != 0 ||
+ len(hs.serverHello.alpnProtocol) != 0 ||
+ len(hs.serverHello.scts) != 0 {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3")
+ }
+
+ if !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server did not echo the legacy session ID")
+ }
+
+ if hs.serverHello.compressionMethod != compressionNone {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected unsupported compression format")
+ }
+
+ selectedSuite := mutualCipherSuiteTLS13(hs.hello.cipherSuites, hs.serverHello.cipherSuite)
+ if hs.suite != nil && selectedSuite != hs.suite {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server changed cipher suite after a HelloRetryRequest")
+ }
+ if selectedSuite == nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server chose an unconfigured cipher suite")
+ }
+ hs.suite = selectedSuite
+ c.cipherSuite = hs.suite.id
+
+ return nil
+}
+
+// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
+// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
+func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
+ if hs.c.quic != nil {
+ return nil
+ }
+ if hs.sentDummyCCS {
+ return nil
+ }
+ hs.sentDummyCCS = true
+
+ return hs.c.writeChangeCipherRecord()
+}
+
+// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
+// resends hs.hello, and reads the new ServerHello into hs.serverHello.
+func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
+ c := hs.c
+
+ // The first ClientHello gets double-hashed into the transcript upon a
+ // HelloRetryRequest. (The idea is that the server might offload transcript
+ // storage to the client in the cookie.) See RFC 8446, Section 4.4.1.
+ chHash := hs.transcript.Sum(nil)
+ hs.transcript.Reset()
+ hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+ hs.transcript.Write(chHash)
+ if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
+ return err
+ }
+
+ var isInnerHello bool
+ hello := hs.hello
+ if hs.echContext != nil {
+ chHash = hs.echContext.innerTranscript.Sum(nil)
+ hs.echContext.innerTranscript.Reset()
+ hs.echContext.innerTranscript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+ hs.echContext.innerTranscript.Write(chHash)
+
+ if hs.serverHello.encryptedClientHello != nil {
+ if len(hs.serverHello.encryptedClientHello) != 8 {
+ hs.c.sendAlert(alertDecodeError)
+ return errors.New("tls: malformed encrypted client hello extension")
+ }
+
+ confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash)
+ hrrHello := make([]byte, len(hs.serverHello.original))
+ copy(hrrHello, hs.serverHello.original)
+ hrrHello = bytes.Replace(hrrHello, hs.serverHello.encryptedClientHello, make([]byte, 8), 1)
+ confTranscript.Write(hrrHello)
+ acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New,
+ hkdf.Extract(hs.suite.hash.New, hs.echContext.innerHello.random, nil),
+ "hrr ech accept confirmation",
+ confTranscript.Sum(nil),
+ 8,
+ )
+ if subtle.ConstantTimeCompare(acceptConfirmation, hs.serverHello.encryptedClientHello) == 1 {
+ hello = hs.echContext.innerHello
+ c.serverName = c.config.ServerName
+ isInnerHello = true
+ c.echAccepted = true
+ }
+ }
+
+ if err := transcriptMsg(hs.serverHello, hs.echContext.innerTranscript); err != nil {
+ return err
+ }
+ } else if hs.serverHello.encryptedClientHello != nil {
+ // Unsolicited ECH extension should be rejected
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected encrypted client hello extension in serverHello")
+ }
+
+ // The only HelloRetryRequest extensions we support are key_share and
+ // cookie, and clients must abort the handshake if the HRR would not result
+ // in any change in the ClientHello.
+ if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
+ }
+
+ if hs.serverHello.cookie != nil {
+ hello.cookie = hs.serverHello.cookie
+ }
+
+ if hs.serverHello.serverShare.group != 0 {
+ c.sendAlert(alertDecodeError)
+ return errors.New("tls: received malformed key_share extension")
+ }
+
+ // If the server sent a key_share extension selecting a group, ensure it's
+ // a group we advertised but did not send a key share for, and send a key
+ // share for it this time.
+ if curveID := hs.serverHello.selectedGroup; curveID != 0 {
+ if !slices.Contains(hello.supportedCurves, curveID) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected unsupported group")
+ }
+ if slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool {
+ return ks.group == curveID
+ }) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
+ }
+ // Note: we don't support selecting X25519MLKEM768 in a HRR, because it
+ // is currently first in preference order, so if it's enabled we'll
+ // always send a key share for it.
+ //
+ // This will have to change once we support multiple hybrid KEMs.
+ if _, ok := curveForCurveID(curveID); !ok {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+ key, err := generateECDHEKey(c.config.rand(), curveID)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ hs.keyShareKeys = &keySharePrivateKeys{curveID: curveID, ecdhe: key}
+ hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
+ }
+
+ if len(hello.pskIdentities) > 0 {
+ pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
+ if pskSuite == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if pskSuite.hash == hs.suite.hash {
+ // Update binders and obfuscated_ticket_age.
+ ticketAge := c.config.time().Sub(time.Unix(int64(hs.session.createdAt), 0))
+ hello.pskIdentities[0].obfuscatedTicketAge = uint32(ticketAge/time.Millisecond) + hs.session.ageAdd
+
+ transcript := hs.suite.hash.New()
+ transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+ transcript.Write(chHash)
+ if err := transcriptMsg(hs.serverHello, transcript); err != nil {
+ return err
+ }
+
+ if err := computeAndUpdatePSK(hello, hs.binderKey, transcript, hs.suite.finishedHash); err != nil {
+ return err
+ }
+ } else {
+ // Server selected a cipher suite incompatible with the PSK.
+ hello.pskIdentities = nil
+ hello.pskBinders = nil
+ }
+ }
+
+ // [uTLS SECTION BEGINS]
+ // crypto/tls code above this point had changed crypto/tls structures in accordance with HRR, and is about
+ // to call default marshaller.
+ // Instead, we fill uTLS-specific structs and call uTLS marshaller.
+ // Only extensionCookie, extensionPreSharedKey, extensionKeyShare, extensionEarlyData, extensionSupportedVersions,
+ // and utlsExtensionPadding are supposed to change
+ if hs.uconn != nil {
+ if hs.uconn.ClientHelloID != HelloGolang {
+ if len(hs.hello.pskIdentities) > 0 {
+ // TODO: wait for someone who cares about PSK to implement
+ return errors.New("uTLS does not support reprocessing of PSK key triggered by HelloRetryRequest")
+ }
+
+ keyShareExtFound := false
+ for _, ext := range hs.uconn.Extensions {
+ // new ks seems to be generated either way
+ if ks, ok := ext.(*KeyShareExtension); ok {
+ ks.KeyShares = keyShares(hs.hello.keyShares).ToPublic()
+ keyShareExtFound = true
+ }
+ }
+ if !keyShareExtFound {
+ return errors.New("uTLS: received HelloRetryRequest, but keyshare not found among client's " +
+ "uconn.Extensions")
+ }
+
+ if len(hs.serverHello.cookie) > 0 {
+ // serverHello specified a cookie, let's echo it
+ cookieFound := false
+ for _, ext := range hs.uconn.Extensions {
+ if ks, ok := ext.(*CookieExtension); ok {
+ ks.Cookie = hs.serverHello.cookie
+ cookieFound = true
+ }
+ }
+
+ if !cookieFound {
+ // pick a random index where to add cookieExtension
+ // -2 instead of -1 is a lazy way to ensure that PSK is still a last extension
+ p, err := newPRNG()
+ if err != nil {
+ return err
+ }
+ cookieIndex := p.Intn(len(hs.uconn.Extensions) - 2)
+ if cookieIndex >= len(hs.uconn.Extensions) {
+ // this check is for empty hs.uconn.Extensions
+ return fmt.Errorf("cookieIndex >= len(hs.uconn.Extensions): %v >= %v",
+ cookieIndex, len(hs.uconn.Extensions))
+ }
+ hs.uconn.Extensions = append(hs.uconn.Extensions[:cookieIndex],
+ append([]TLSExtension{&CookieExtension{Cookie: hs.serverHello.cookie}},
+ hs.uconn.Extensions[cookieIndex:]...)...)
+ }
+ }
+ if err := hs.uconn.MarshalClientHelloNoECH(); err != nil {
+ return err
+ }
+ hs.hello.original = hs.uconn.HandshakeState.Hello.Raw
+ }
+ }
+ // [uTLS SECTION ENDS]
+ if hello.earlyData {
+ hello.earlyData = false
+ c.quicRejectedEarlyData()
+ }
+
+ if isInnerHello {
+ // Any extensions which have changed in hello, but are mirrored in the
+ // outer hello and compressed, need to be copied to the outer hello, so
+ // they can be properly decompressed by the server. For now, the only
+ // extension which may have changed is keyShares.
+ hs.hello.keyShares = hello.keyShares
+ hs.echContext.innerHello = hello
+ if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
+ if err := hs.uconn.computeAndUpdateOuterECHExtension(hs.echContext.innerHello, hs.echContext, false); err != nil {
+ return err
+ }
+
+ hs.hello.original = hs.uconn.HandshakeState.Hello.Raw
+
+ if err := hs.uconn.echTranscriptMsg(hs.hello, hs.echContext); err != nil {
+ return err
+ }
+
+ } else {
+ if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil {
+ return err
+ }
+
+ if err := computeAndUpdateOuterECHExtension(hs.hello, hs.echContext.innerHello, hs.echContext, false); err != nil {
+ return err
+ }
+ }
+ } else {
+ hs.hello = hello
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
+ return err
+ }
+
+ // serverHelloMsg is not included in the transcript
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
+ }
+ hs.serverHello = serverHello
+
+ if err := hs.checkServerHelloOrHRR(); err != nil {
+ return err
+ }
+
+ c.didHRR = true
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) processServerHello() error {
+ c := hs.c
+
+ if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: server sent two HelloRetryRequest messages")
+ }
+
+ if len(hs.serverHello.cookie) != 0 {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server sent a cookie in a normal ServerHello")
+ }
+
+ if hs.serverHello.selectedGroup != 0 {
+ c.sendAlert(alertDecodeError)
+ return errors.New("tls: malformed key_share extension")
+ }
+
+ if hs.serverHello.serverShare.group == 0 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server did not send a key share")
+ }
+ if !slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool {
+ return ks.group == hs.serverHello.serverShare.group
+ }) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected unsupported group")
+ }
+
+ if !hs.serverHello.selectedIdentityPresent {
+ return nil
+ }
+
+ if int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected an invalid PSK")
+ }
+
+ if len(hs.hello.pskIdentities) != 1 || hs.session == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
+ if pskSuite == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if pskSuite.hash != hs.suite.hash {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected an invalid PSK and cipher suite pair")
+ }
+
+ hs.usingPSK = true
+ c.didResume = true
+ c.peerCertificates = hs.session.peerCertificates
+ c.activeCertHandles = hs.session.activeCertHandles
+ c.verifiedChains = hs.session.verifiedChains
+ c.ocspResponse = hs.session.ocspResponse
+ c.scts = hs.session.scts
+ return nil
+}
+
+// [uTLS] SECTION BEGIN
+func getSharedKey(peerData []byte, key *ecdh.PrivateKey) ([]byte, error) {
+ peerKey, err := key.Curve().NewPublicKey(peerData)
+ if err != nil {
+ return nil, errors.New("tls: invalid server key share")
+ }
+ sharedKey, err := key.ECDH(peerKey)
+ if err != nil {
+ return nil, errors.New("tls: invalid server key share")
+ }
+
+ return sharedKey, nil
+}
+
+// [uTLS] SECTION END
+
+func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
+ c := hs.c
+
+ ecdhePeerData := hs.serverHello.serverShare.data
+ if hs.serverHello.serverShare.group == X25519MLKEM768 {
+ if len(ecdhePeerData) != mlkem.CiphertextSize768+x25519PublicKeySize {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server X25519MLKEM768 key share")
+ }
+ ecdhePeerData = hs.serverHello.serverShare.data[mlkem.CiphertextSize768:]
+ }
+ // [uTLS] SECTION BEGIN
+ if hs.serverHello.serverShare.group == X25519Kyber768Draft00 {
+ if len(ecdhePeerData) != x25519PublicKeySize+mlkem.CiphertextSize768 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server X25519Kyber768Draft00 key share")
+ }
+ ecdhePeerData = hs.serverHello.serverShare.data[:x25519PublicKeySize]
+ }
+ sharedKey, err := getSharedKey(ecdhePeerData, hs.keyShareKeys.ecdhe)
+ // [uTLS] SECTION END
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server key share")
+ }
+ if hs.serverHello.serverShare.group == X25519MLKEM768 {
+ if hs.keyShareKeys.mlkem == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ // [uTLS] SECTION BEGIN
+ if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
+ if sharedKey, err = getSharedKey(ecdhePeerData, hs.keyShareKeys.mlkemEcdhe); err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server key share")
+ }
+ }
+ // [uTLS] SECTION END
+ ciphertext := hs.serverHello.serverShare.data[:mlkem.CiphertextSize768]
+ mlkemShared, err := hs.keyShareKeys.mlkem.Decapsulate(ciphertext)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid X25519MLKEM768 server key share")
+ }
+ sharedKey = append(mlkemShared, sharedKey...)
+ }
+ // [uTLS] SECTION BEGIN
+ if hs.serverHello.serverShare.group == X25519Kyber768Draft00 {
+ if hs.keyShareKeys.mlkem == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if hs.uconn != nil && hs.uconn.clientHelloBuildStatus == BuildByUtls {
+ if sharedKey, err = getSharedKey(ecdhePeerData, hs.keyShareKeys.mlkemEcdhe); err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server key share")
+ }
+ }
+ ciphertext := hs.serverHello.serverShare.data[x25519PublicKeySize:]
+ kyberShared, err := kyberDecapsulate(hs.keyShareKeys.mlkem, ciphertext)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid X25519Kyber768Draft00 server key share")
+ }
+ sharedKey = append(sharedKey, kyberShared...)
+ }
+ // [uTLS] SECTION END
+ c.curveID = hs.serverHello.serverShare.group
+
+ earlySecret := hs.earlySecret
+ if !hs.usingPSK {
+ earlySecret = tls13.NewEarlySecret(hs.suite.hash.New, nil)
+ }
+
+ handshakeSecret := earlySecret.HandshakeSecret(sharedKey)
+
+ clientSecret := handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript)
+ c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
+ serverSecret := handshakeSecret.ServerHandshakeTrafficSecret(hs.transcript)
+ c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+
+ if c.quic != nil {
+ if c.hand.Len() != 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ }
+ c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
+ c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
+ }
+
+ err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ hs.masterSecret = handshakeSecret.MasterSecret()
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerParameters() error {
+ c := hs.c
+
+ msg, err := c.readHandshake(hs.transcript)
+ if err != nil {
+ return err
+ }
+
+ encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(encryptedExtensions, msg)
+ }
+
+ if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol, c.quic != nil); err != nil {
+ // RFC 8446 specifies that no_application_protocol is sent by servers, but
+ // does not specify how clients handle the selection of an incompatible protocol.
+ // RFC 9001 Section 8.1 specifies that QUIC clients send no_application_protocol
+ // in this case. Always sending no_application_protocol seems reasonable.
+ c.sendAlert(alertNoApplicationProtocol)
+ return err
+ }
+ c.clientProtocol = encryptedExtensions.alpnProtocol
+
+ // [UTLS SECTION STARTS]
+ if hs.uconn != nil {
+ err = hs.utlsReadServerParameters(encryptedExtensions)
+ if err != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return err
+ }
+ }
+ // [UTLS SECTION ENDS]
+
+ if c.quic != nil {
+ if encryptedExtensions.quicTransportParameters == nil {
+ // RFC 9001 Section 8.2.
+ c.sendAlert(alertMissingExtension)
+ return errors.New("tls: server did not send a quic_transport_parameters extension")
+ }
+ c.quicSetTransportParameters(encryptedExtensions.quicTransportParameters)
+ } else {
+ if encryptedExtensions.quicTransportParameters != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server sent an unexpected quic_transport_parameters extension")
+ }
+ }
+
+ if !hs.hello.earlyData && encryptedExtensions.earlyData {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server sent an unexpected early_data extension")
+ }
+ if hs.hello.earlyData && !encryptedExtensions.earlyData {
+ c.quicRejectedEarlyData()
+ }
+ if encryptedExtensions.earlyData {
+ if hs.session.cipherSuite != c.cipherSuite {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server accepted 0-RTT with the wrong cipher suite")
+ }
+ if hs.session.alpnProtocol != c.clientProtocol {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server accepted 0-RTT with the wrong ALPN")
+ }
+ }
+ if hs.echContext != nil {
+ if hs.echContext.echRejected {
+ hs.echContext.retryConfigs = encryptedExtensions.echRetryConfigs
+ } else if encryptedExtensions.echRetryConfigs != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server sent encrypted client hello retry configs after accepting encrypted client hello")
+ }
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
+ c := hs.c
+
+ // Either a PSK or a certificate is always used, but not both.
+ // See RFC 8446, Section 4.1.1.
+ if hs.usingPSK {
+ // Make sure the connection is still being verified whether or not this
+ // is a resumption. Resumptions currently don't reverify certificates so
+ // they don't call verifyServerCertificate. See Issue 31641.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+ return nil
+ }
+
+ // [UTLS SECTION BEGINS]
+ // msg, err := c.readHandshake(hs.transcript)
+ msg, err := c.readHandshake(nil) // hold writing to transcript until we know it is not compressed cert
+ // [UTLS SECTION ENDS]
+ if err != nil {
+ return err
+ }
+
+ certReq, ok := msg.(*certificateRequestMsgTLS13)
+ if ok {
+ hs.certReq = certReq
+ transcriptMsg(certReq, hs.transcript) // [UTLS] if it is certReq (not compressedCert), write to transcript
+
+ // msg, err = c.readHandshake(hs.transcript)
+ msg, err = c.readHandshake(nil) // [UTLS] we don't write to transcript until make sure it is not compressed cert
+ if err != nil {
+ return err
+ }
+ }
+
+ // [UTLS SECTION BEGINS]
+ var skipWritingCertToTranscript bool = false
+ if hs.uconn != nil {
+ processedMsg, err := hs.utlsReadServerCertificate(msg)
+ if err != nil {
+ return err
+ }
+ if processedMsg != nil {
+ skipWritingCertToTranscript = true
+ msg = processedMsg // msg is now a processed-by-extension certificateMsg
+ }
+ }
+ // [UTLS SECTION ENDS]
+
+ certMsg, ok := msg.(*certificateMsgTLS13)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+ if len(certMsg.certificate.Certificate) == 0 {
+ c.sendAlert(alertDecodeError)
+ return errors.New("tls: received empty certificates message")
+ }
+ // [UTLS SECTION BEGINS]
+ if !skipWritingCertToTranscript { // write to transcript only if it is not compressedCert (i.e. if not processed by extension)
+ if err = transcriptMsg(certMsg, hs.transcript); err != nil {
+ return err
+ }
+ }
+ // [UTLS SECTION ENDS]
+
+ c.scts = certMsg.certificate.SignedCertificateTimestamps
+ c.ocspResponse = certMsg.certificate.OCSPStaple
+
+ if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil {
+ return err
+ }
+
+ // certificateVerifyMsg is included in the transcript, but not until
+ // after we verify the handshake signature, since the state before
+ // this message was sent is used.
+ msg, err = c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ // See RFC 8446, Section 4.4.3.
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: certificate used with invalid signature algorithm")
+ }
+ signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
+ if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
+ sigHash, signed, certVerify.signature); err != nil {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid signature by the server certificate: " + err.Error())
+ }
+
+ if err := transcriptMsg(certVerify, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerFinished() error {
+ c := hs.c
+
+ // finishedMsg is included in the transcript, but not until after we
+ // check the client version, since the state before this message was
+ // sent is used during verification.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ finished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(finished, msg)
+ }
+
+ expectedMAC := hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
+ if !hmac.Equal(expectedMAC, finished.verifyData) {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid server finished hash")
+ }
+
+ if err := transcriptMsg(finished, hs.transcript); err != nil {
+ return err
+ }
+
+ // Derive secrets that take context through the server Finished.
+
+ hs.trafficSecret = hs.masterSecret.ClientApplicationTrafficSecret(hs.transcript)
+ serverSecret := hs.masterSecret.ServerApplicationTrafficSecret(hs.transcript)
+ c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
+
+ err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
+ c := hs.c
+
+ if hs.certReq == nil {
+ return nil
+ }
+
+ if hs.echContext != nil && hs.echContext.echRejected {
+ if _, err := hs.c.writeHandshakeRecord(&certificateMsgTLS13{}, hs.transcript); err != nil {
+ return err
+ }
+ return nil
+ }
+
+ cert, err := c.getClientCertificate(&CertificateRequestInfo{
+ AcceptableCAs: hs.certReq.certificateAuthorities,
+ SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
+ Version: c.vers,
+ ctx: hs.ctx,
+ })
+ if err != nil {
+ return err
+ }
+
+ certMsg := new(certificateMsgTLS13)
+
+ certMsg.certificate = *cert
+ certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
+ certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
+
+ if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ // If we sent an empty certificate message, skip the CertificateVerify.
+ if len(cert.Certificate) == 0 {
+ return nil
+ }
+
+ certVerifyMsg := new(certificateVerifyMsg)
+ certVerifyMsg.hasSignatureAlgorithm = true
+
+ certVerifyMsg.signatureAlgorithm, err = selectSignatureScheme(c.vers, cert, hs.certReq.supportedSignatureAlgorithms)
+ if err != nil {
+ // getClientCertificate returned a certificate incompatible with the
+ // CertificateRequestInfo supported signature algorithms.
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+
+ signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to sign handshake: " + err.Error())
+ }
+ certVerifyMsg.signature = sig
+
+ if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
+ c := hs.c
+
+ finished := &finishedMsg{
+ verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
+ return err
+ }
+
+ c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
+
+ if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
+ c.resumptionSecret = hs.masterSecret.ResumptionMasterSecret(hs.transcript)
+ }
+
+ if c.quic != nil {
+ if c.hand.Len() != 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ }
+ c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, hs.trafficSecret)
+ }
+
+ return nil
+}
+
+func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
+ if !c.isClient {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: received new session ticket from a client")
+ }
+
+ if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
+ return nil
+ }
+
+ // See RFC 8446, Section 4.6.1.
+ if msg.lifetime == 0 {
+ return nil
+ }
+ lifetime := time.Duration(msg.lifetime) * time.Second
+ if lifetime > maxSessionTicketLifetime {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: received a session ticket with invalid lifetime")
+ }
+
+ // RFC 9001, Section 4.6.1
+ if c.quic != nil && msg.maxEarlyData != 0 && msg.maxEarlyData != 0xffffffff {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid early data for QUIC connection")
+ }
+
+ cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
+ if cipherSuite == nil || c.resumptionSecret == nil {
+ return c.sendAlert(alertInternalError)
+ }
+
+ psk := tls13.ExpandLabel(cipherSuite.hash.New, c.resumptionSecret, "resumption",
+ msg.nonce, cipherSuite.hash.Size())
+
+ session := c.sessionState()
+ session.secret = psk
+ session.useBy = uint64(c.config.time().Add(lifetime).Unix())
+ session.ageAdd = msg.ageAdd
+ session.EarlyData = c.quic != nil && msg.maxEarlyData == 0xffffffff // RFC 9001, Section 4.6.1
+ session.ticket = msg.label
+ if c.quic != nil && c.quic.enableSessionEvents {
+ c.quicStoreSession(session)
+ return nil
+ }
+ cs := &ClientSessionState{session: session}
+ if cacheKey := c.clientSessionCacheKey(); cacheKey != "" {
+ c.config.ClientSessionCache.Put(cacheKey, cs)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/handshake_messages.go b/vendor/github.com/refraction-networking/utls/handshake_messages.go
new file mode 100644
index 00000000..33042830
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/handshake_messages.go
@@ -0,0 +1,2004 @@
+// 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 tls
+
+import (
+ "errors"
+ "fmt"
+ "slices"
+ "strings"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// The marshalingFunction type is an adapter to allow the use of ordinary
+// functions as cryptobyte.MarshalingValue.
+type marshalingFunction func(b *cryptobyte.Builder) error
+
+func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error {
+ return f(b)
+}
+
+// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If
+// the length of the sequence is not the value specified, it produces an error.
+func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) {
+ b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error {
+ if len(v) != n {
+ return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v))
+ }
+ b.AddBytes(v)
+ return nil
+ }))
+}
+
+// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder.
+func addUint64(b *cryptobyte.Builder, v uint64) {
+ b.AddUint32(uint32(v >> 32))
+ b.AddUint32(uint32(v))
+}
+
+// readUint64 decodes a big-endian, 64-bit value into out and advances over it.
+// It reports whether the read was successful.
+func readUint64(s *cryptobyte.String, out *uint64) bool {
+ var hi, lo uint32
+ if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) {
+ return false
+ }
+ *out = uint64(hi)<<32 | uint64(lo)
+ return true
+}
+
+// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+ return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out))
+}
+
+// readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+ return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
+}
+
+// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+ return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out))
+}
+
+type clientHelloMsg struct {
+ original []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ serverName string
+ ocspStapling bool
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ ticketSupported bool
+ sessionTicket []uint8
+ supportedSignatureAlgorithms []SignatureScheme
+ supportedSignatureAlgorithmsCert []SignatureScheme
+ secureRenegotiationSupported bool
+ secureRenegotiation []byte
+ extendedMasterSecret bool
+ alpnProtocols []string
+ scts bool
+ // ems bool // [uTLS] actually implemented due to its prevalence // removed since crypto/tls implements it
+ supportedVersions []uint16
+ cookie []byte
+ keyShares []keyShare
+ earlyData bool
+ pskModes []uint8
+ pskIdentities []pskIdentity
+ pskBinders [][]byte
+ quicTransportParameters []byte
+ encryptedClientHello []byte
+ // extensions are only populated on the server-side of a handshake
+ extensions []uint16
+
+ // [uTLS]
+ nextProtoNeg bool
+}
+
+func (m *clientHelloMsg) marshalMsg(echInner bool) ([]byte, error) {
+ // [uTLS SECTION BEGIN]
+ return m.marshalMsgReorderOuterExts(echInner, nil)
+}
+
+func (m *clientHelloMsg) marshalMsgReorderOuterExts(echInner bool, outerExts []uint16) ([]byte, error) {
+ // [uTLS SECTION END]
+ var exts cryptobyte.Builder
+ if len(m.serverName) > 0 {
+ // RFC 6066, Section 3
+ exts.AddUint16(extensionServerName)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8(0) // name_type = host_name
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes([]byte(m.serverName))
+ })
+ })
+ })
+ }
+ if len(m.supportedPoints) > 0 && !echInner {
+ // RFC 4492, Section 5.1.2
+ exts.AddUint16(extensionSupportedPoints)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.supportedPoints)
+ })
+ })
+ }
+ if m.ticketSupported && !echInner {
+ // RFC 5077, Section 3.2
+ exts.AddUint16(extensionSessionTicket)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.sessionTicket)
+ })
+ }
+ if m.secureRenegotiationSupported && !echInner {
+ // RFC 5746, Section 3.2
+ exts.AddUint16(extensionRenegotiationInfo)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.secureRenegotiation)
+ })
+ })
+ }
+ if m.extendedMasterSecret && !echInner {
+ // RFC 7627
+ exts.AddUint16(extensionExtendedMasterSecret)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if m.scts {
+ // RFC 6962, Section 3.3.1
+ exts.AddUint16(extensionSCT)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if m.earlyData {
+ // RFC 8446, Section 4.2.10
+ exts.AddUint16(extensionEarlyData)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if m.quicTransportParameters != nil { // marshal zero-length parameters when present
+ // RFC 9001, Section 8.2
+ exts.AddUint16(extensionQUICTransportParameters)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.quicTransportParameters)
+ })
+ }
+ if len(m.encryptedClientHello) > 0 {
+ exts.AddUint16(extensionEncryptedClientHello)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.encryptedClientHello)
+ })
+ }
+ // Note that any extension that can be compressed during ECH must be
+ // contiguous. If any additional extensions are to be compressed they must
+ // be added to the following block, so that they can be properly
+ // decompressed on the other side.
+ var echOuterExts []uint16
+ if m.ocspStapling {
+ // RFC 4366, Section 3.6
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionStatusRequest)
+ } else {
+ exts.AddUint16(extensionStatusRequest)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8(1) // status_type = ocsp
+ exts.AddUint16(0) // empty responder_id_list
+ exts.AddUint16(0) // empty request_extensions
+ })
+ }
+ }
+ if len(m.supportedCurves) > 0 {
+ // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionSupportedCurves)
+ } else {
+ exts.AddUint16(extensionSupportedCurves)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, curve := range m.supportedCurves {
+ exts.AddUint16(uint16(curve))
+ }
+ })
+ })
+ }
+ }
+ if len(m.supportedSignatureAlgorithms) > 0 {
+ // RFC 5246, Section 7.4.1.4.1
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionSignatureAlgorithms)
+ } else {
+ exts.AddUint16(extensionSignatureAlgorithms)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithms {
+ exts.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ }
+ if len(m.supportedSignatureAlgorithmsCert) > 0 {
+ // RFC 8446, Section 4.2.3
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionSignatureAlgorithmsCert)
+ } else {
+ exts.AddUint16(extensionSignatureAlgorithmsCert)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
+ exts.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ }
+ if len(m.alpnProtocols) > 0 {
+ // RFC 7301, Section 3.1
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionALPN)
+ } else {
+ exts.AddUint16(extensionALPN)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, proto := range m.alpnProtocols {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes([]byte(proto))
+ })
+ }
+ })
+ })
+ }
+ }
+ if len(m.supportedVersions) > 0 {
+ // RFC 8446, Section 4.2.1
+ if echInner && outerExts == nil { // uTLS
+ echOuterExts = append(echOuterExts, extensionSupportedVersions)
+ } else {
+ exts.AddUint16(extensionSupportedVersions)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, vers := range m.supportedVersions {
+ exts.AddUint16(vers)
+ }
+ })
+ })
+ }
+ }
+ if len(m.cookie) > 0 {
+ // RFC 8446, Section 4.2.2
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionCookie)
+ } else {
+ exts.AddUint16(extensionCookie)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.cookie)
+ })
+ })
+ }
+ }
+ if len(m.keyShares) > 0 {
+ // RFC 8446, Section 4.2.8
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionKeyShare)
+ } else {
+ exts.AddUint16(extensionKeyShare)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, ks := range m.keyShares {
+ exts.AddUint16(uint16(ks.group))
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(ks.data)
+ })
+ }
+ })
+ })
+ }
+ }
+ if len(m.pskModes) > 0 {
+ // RFC 8446, Section 4.2.9
+ if echInner {
+ echOuterExts = append(echOuterExts, extensionPSKModes)
+ } else {
+ exts.AddUint16(extensionPSKModes)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.pskModes)
+ })
+ })
+ }
+ }
+ // [uTLS SECTION BEGIN]
+ // reorder OuterExtensions according to their order in the spec
+ if echInner && outerExts != nil {
+ echOuterExtsReordered := slices.Collect(func(yield func(uint16) bool) {
+ for _, ext := range outerExts {
+ if slices.Contains(echOuterExts, ext) {
+ if !yield(ext) {
+ return
+ }
+ }
+ }
+ })
+ echOuterExts = echOuterExtsReordered
+ }
+ // [uTLS SECTION END]
+ if len(echOuterExts) > 0 && echInner {
+ exts.AddUint16(extensionECHOuterExtensions)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, e := range echOuterExts {
+ exts.AddUint16(e)
+ }
+ })
+ })
+ }
+ if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
+ // RFC 8446, Section 4.2.11
+ exts.AddUint16(extensionPreSharedKey)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, psk := range m.pskIdentities {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(psk.label)
+ })
+ exts.AddUint32(psk.obfuscatedTicketAge)
+ }
+ })
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, binder := range m.pskBinders {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(binder)
+ })
+ }
+ })
+ })
+ }
+ extBytes, err := exts.Bytes()
+ if err != nil {
+ return nil, err
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeClientHello)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16(m.vers)
+ addBytesWithLength(b, m.random, 32)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ if !echInner {
+ b.AddBytes(m.sessionId)
+ }
+ })
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, suite := range m.cipherSuites {
+ b.AddUint16(suite)
+ }
+ })
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.compressionMethods)
+ })
+
+ if len(extBytes) > 0 {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(extBytes)
+ })
+ }
+ })
+
+ return b.Bytes()
+}
+
+func (m *clientHelloMsg) marshal() ([]byte, error) {
+ // [uTLS SECTION START]
+ if m.original != nil {
+ return m.original, nil
+ }
+ // [uTLS SECTION END]
+
+ return m.marshalMsg(false)
+}
+
+// marshalWithoutBinders returns the ClientHello through the
+// PreSharedKeyExtension.identities field, according to RFC 8446, Section
+// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length.
+func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) {
+ bindersLen := 2 // uint16 length prefix
+ for _, binder := range m.pskBinders {
+ bindersLen += 1 // uint8 length prefix
+ bindersLen += len(binder)
+ }
+
+ var fullMessage []byte
+ if m.original != nil {
+ fullMessage = m.original
+ } else {
+ var err error
+ fullMessage, err = m.marshal()
+ if err != nil {
+ return nil, err
+ }
+ }
+ return fullMessage[:len(fullMessage)-bindersLen], nil
+}
+
+// updateBinders updates the m.pskBinders field. The supplied binders must have
+// the same length as the current m.pskBinders.
+func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error {
+ if len(pskBinders) != len(m.pskBinders) {
+ return errors.New("tls: internal error: pskBinders length mismatch")
+ }
+ for i := range m.pskBinders {
+ if len(pskBinders[i]) != len(m.pskBinders[i]) {
+ return errors.New("tls: internal error: pskBinders length mismatch")
+ }
+ }
+ m.pskBinders = pskBinders
+
+ return nil
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+ *m = clientHelloMsg{original: data}
+ s := cryptobyte.String(data)
+
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) ||
+ !readUint8LengthPrefixed(&s, &m.sessionId) {
+ return false
+ }
+
+ var cipherSuites cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&cipherSuites) {
+ return false
+ }
+ m.cipherSuites = []uint16{}
+ m.secureRenegotiationSupported = false
+ for !cipherSuites.Empty() {
+ var suite uint16
+ if !cipherSuites.ReadUint16(&suite) {
+ return false
+ }
+ if suite == scsvRenegotiation {
+ m.secureRenegotiationSupported = true
+ }
+ m.cipherSuites = append(m.cipherSuites, suite)
+ }
+
+ if !readUint8LengthPrefixed(&s, &m.compressionMethods) {
+ return false
+ }
+
+ if s.Empty() {
+ // ClientHello is optionally followed by extension data
+ return true
+ }
+
+ var extensions cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+ return false
+ }
+
+ seenExts := make(map[uint16]bool)
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ if seenExts[extension] {
+ return false
+ }
+ seenExts[extension] = true
+ m.extensions = append(m.extensions, extension)
+
+ switch extension {
+ case extensionServerName:
+ // RFC 6066, Section 3
+ var nameList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
+ return false
+ }
+ for !nameList.Empty() {
+ var nameType uint8
+ var serverName cryptobyte.String
+ if !nameList.ReadUint8(&nameType) ||
+ !nameList.ReadUint16LengthPrefixed(&serverName) ||
+ serverName.Empty() {
+ return false
+ }
+ if nameType != 0 {
+ continue
+ }
+ if len(m.serverName) != 0 {
+ // Multiple names of the same name_type are prohibited.
+ return false
+ }
+ m.serverName = string(serverName)
+ // An SNI value may not include a trailing dot.
+ if strings.HasSuffix(m.serverName, ".") {
+ return false
+ }
+ }
+ case extensionStatusRequest:
+ // RFC 4366, Section 3.6
+ var statusType uint8
+ var ignored cryptobyte.String
+ if !extData.ReadUint8(&statusType) ||
+ !extData.ReadUint16LengthPrefixed(&ignored) ||
+ !extData.ReadUint16LengthPrefixed(&ignored) {
+ return false
+ }
+ m.ocspStapling = statusType == statusTypeOCSP
+ case extensionSupportedCurves:
+ // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+ var curves cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() {
+ return false
+ }
+ for !curves.Empty() {
+ var curve uint16
+ if !curves.ReadUint16(&curve) {
+ return false
+ }
+ m.supportedCurves = append(m.supportedCurves, CurveID(curve))
+ }
+ case extensionSupportedPoints:
+ // RFC 4492, Section 5.1.2
+ if !readUint8LengthPrefixed(&extData, &m.supportedPoints) ||
+ len(m.supportedPoints) == 0 {
+ return false
+ }
+ case extensionSessionTicket:
+ // RFC 5077, Section 3.2
+ m.ticketSupported = true
+ extData.ReadBytes(&m.sessionTicket, len(extData))
+ case extensionSignatureAlgorithms:
+ // RFC 5246, Section 7.4.1.4.1
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithms = append(
+ m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+ }
+ case extensionSignatureAlgorithmsCert:
+ // RFC 8446, Section 4.2.3
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithmsCert = append(
+ m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg))
+ }
+ case extensionRenegotiationInfo:
+ // RFC 5746, Section 3.2
+ if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) {
+ return false
+ }
+ m.secureRenegotiationSupported = true
+ case extensionExtendedMasterSecret:
+ // RFC 7627
+ m.extendedMasterSecret = true
+ case extensionALPN:
+ // RFC 7301, Section 3.1
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return false
+ }
+ for !protoList.Empty() {
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
+ return false
+ }
+ m.alpnProtocols = append(m.alpnProtocols, string(proto))
+ }
+ case extensionSCT:
+ // RFC 6962, Section 3.3.1
+ m.scts = true
+ case extensionSupportedVersions:
+ // RFC 8446, Section 4.2.1
+ var versList cryptobyte.String
+ if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
+ return false
+ }
+ for !versList.Empty() {
+ var vers uint16
+ if !versList.ReadUint16(&vers) {
+ return false
+ }
+ m.supportedVersions = append(m.supportedVersions, vers)
+ }
+ case extensionCookie:
+ // RFC 8446, Section 4.2.2
+ if !readUint16LengthPrefixed(&extData, &m.cookie) ||
+ len(m.cookie) == 0 {
+ return false
+ }
+ case extensionKeyShare:
+ // RFC 8446, Section 4.2.8
+ var clientShares cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&clientShares) {
+ return false
+ }
+ for !clientShares.Empty() {
+ var ks keyShare
+ if !clientShares.ReadUint16((*uint16)(&ks.group)) ||
+ !readUint16LengthPrefixed(&clientShares, &ks.data) ||
+ len(ks.data) == 0 {
+ return false
+ }
+ m.keyShares = append(m.keyShares, ks)
+ }
+ case extensionEarlyData:
+ // RFC 8446, Section 4.2.10
+ m.earlyData = true
+ case extensionPSKModes:
+ // RFC 8446, Section 4.2.9
+ if !readUint8LengthPrefixed(&extData, &m.pskModes) {
+ return false
+ }
+ case extensionQUICTransportParameters:
+ m.quicTransportParameters = make([]byte, len(extData))
+ if !extData.CopyBytes(m.quicTransportParameters) {
+ return false
+ }
+ case extensionPreSharedKey:
+ // RFC 8446, Section 4.2.11
+ if !extensions.Empty() {
+ return false // pre_shared_key must be the last extension
+ }
+ var identities cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() {
+ return false
+ }
+ for !identities.Empty() {
+ var psk pskIdentity
+ if !readUint16LengthPrefixed(&identities, &psk.label) ||
+ !identities.ReadUint32(&psk.obfuscatedTicketAge) ||
+ len(psk.label) == 0 {
+ return false
+ }
+ m.pskIdentities = append(m.pskIdentities, psk)
+ }
+ var binders cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() {
+ return false
+ }
+ for !binders.Empty() {
+ var binder []byte
+ if !readUint8LengthPrefixed(&binders, &binder) ||
+ len(binder) == 0 {
+ return false
+ }
+ m.pskBinders = append(m.pskBinders, binder)
+ }
+ case extensionEncryptedClientHello:
+ if !extData.ReadBytes(&m.encryptedClientHello, len(extData)) {
+ return false
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (m *clientHelloMsg) originalBytes() []byte {
+ return m.original
+}
+
+func (m *clientHelloMsg) clone() *clientHelloMsg {
+ return &clientHelloMsg{
+ original: slices.Clone(m.original),
+ vers: m.vers,
+ random: slices.Clone(m.random),
+ sessionId: slices.Clone(m.sessionId),
+ cipherSuites: slices.Clone(m.cipherSuites),
+ compressionMethods: slices.Clone(m.compressionMethods),
+ serverName: m.serverName,
+ ocspStapling: m.ocspStapling,
+ supportedCurves: slices.Clone(m.supportedCurves),
+ supportedPoints: slices.Clone(m.supportedPoints),
+ ticketSupported: m.ticketSupported,
+ sessionTicket: slices.Clone(m.sessionTicket),
+ supportedSignatureAlgorithms: slices.Clone(m.supportedSignatureAlgorithms),
+ supportedSignatureAlgorithmsCert: slices.Clone(m.supportedSignatureAlgorithmsCert),
+ secureRenegotiationSupported: m.secureRenegotiationSupported,
+ secureRenegotiation: slices.Clone(m.secureRenegotiation),
+ extendedMasterSecret: m.extendedMasterSecret,
+ alpnProtocols: slices.Clone(m.alpnProtocols),
+ scts: m.scts,
+ supportedVersions: slices.Clone(m.supportedVersions),
+ cookie: slices.Clone(m.cookie),
+ keyShares: slices.Clone(m.keyShares),
+ earlyData: m.earlyData,
+ pskModes: slices.Clone(m.pskModes),
+ pskIdentities: slices.Clone(m.pskIdentities),
+ pskBinders: slices.Clone(m.pskBinders),
+ quicTransportParameters: slices.Clone(m.quicTransportParameters),
+ encryptedClientHello: slices.Clone(m.encryptedClientHello),
+ }
+}
+
+type serverHelloMsg struct {
+ original []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiationSupported bool
+ secureRenegotiation []byte
+ extendedMasterSecret bool
+ alpnProtocol string
+ scts [][]byte
+ supportedVersion uint16
+ serverShare keyShare
+ selectedIdentityPresent bool
+ selectedIdentity uint16
+ supportedPoints []uint8
+ encryptedClientHello []byte
+ serverNameAck bool
+
+ // HelloRetryRequest extensions
+ cookie []byte
+ selectedGroup CurveID
+
+ // [uTLS]
+ nextProtoNeg bool
+ nextProtos []string
+}
+
+func (m *serverHelloMsg) marshal() ([]byte, error) {
+ var exts cryptobyte.Builder
+ if m.ocspStapling {
+ exts.AddUint16(extensionStatusRequest)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if m.ticketSupported {
+ exts.AddUint16(extensionSessionTicket)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if m.secureRenegotiationSupported {
+ exts.AddUint16(extensionRenegotiationInfo)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.secureRenegotiation)
+ })
+ })
+ }
+ if m.extendedMasterSecret {
+ exts.AddUint16(extensionExtendedMasterSecret)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if len(m.alpnProtocol) > 0 {
+ exts.AddUint16(extensionALPN)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes([]byte(m.alpnProtocol))
+ })
+ })
+ })
+ }
+ if len(m.scts) > 0 {
+ exts.AddUint16(extensionSCT)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, sct := range m.scts {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(sct)
+ })
+ }
+ })
+ })
+ }
+ if m.supportedVersion != 0 {
+ exts.AddUint16(extensionSupportedVersions)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(m.supportedVersion)
+ })
+ }
+ if m.serverShare.group != 0 {
+ exts.AddUint16(extensionKeyShare)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(uint16(m.serverShare.group))
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.serverShare.data)
+ })
+ })
+ }
+ if m.selectedIdentityPresent {
+ exts.AddUint16(extensionPreSharedKey)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(m.selectedIdentity)
+ })
+ }
+
+ if len(m.cookie) > 0 {
+ exts.AddUint16(extensionCookie)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.cookie)
+ })
+ })
+ }
+ if m.selectedGroup != 0 {
+ exts.AddUint16(extensionKeyShare)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(uint16(m.selectedGroup))
+ })
+ }
+ if len(m.supportedPoints) > 0 {
+ exts.AddUint16(extensionSupportedPoints)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.supportedPoints)
+ })
+ })
+ }
+ if len(m.encryptedClientHello) > 0 {
+ exts.AddUint16(extensionEncryptedClientHello)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.encryptedClientHello)
+ })
+ }
+ if m.serverNameAck {
+ exts.AddUint16(extensionServerName)
+ exts.AddUint16(0)
+ }
+
+ extBytes, err := exts.Bytes()
+ if err != nil {
+ return nil, err
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeServerHello)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16(m.vers)
+ addBytesWithLength(b, m.random, 32)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.sessionId)
+ })
+ b.AddUint16(m.cipherSuite)
+ b.AddUint8(m.compressionMethod)
+
+ if len(extBytes) > 0 {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(extBytes)
+ })
+ }
+ })
+
+ return b.Bytes()
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+ *m = serverHelloMsg{original: data}
+ s := cryptobyte.String(data)
+
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) ||
+ !readUint8LengthPrefixed(&s, &m.sessionId) ||
+ !s.ReadUint16(&m.cipherSuite) ||
+ !s.ReadUint8(&m.compressionMethod) {
+ return false
+ }
+
+ if s.Empty() {
+ // ServerHello is optionally followed by extension data
+ return true
+ }
+
+ var extensions cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+ return false
+ }
+
+ seenExts := make(map[uint16]bool)
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ if seenExts[extension] {
+ return false
+ }
+ seenExts[extension] = true
+
+ switch extension {
+ case extensionStatusRequest:
+ m.ocspStapling = true
+ case extensionSessionTicket:
+ m.ticketSupported = true
+ // [UTLS] crypto/tls finally supports EMS! Now we don't do anything special here.
+ // case utlsExtensionExtendedMasterSecret:
+ // // No sanity check for this extension: pretending not to know it.
+ // // if length > 0 {
+ // // return false
+ // // }
+ // m.ems = true
+ case extensionRenegotiationInfo:
+ if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) {
+ return false
+ }
+ m.secureRenegotiationSupported = true
+ case extensionExtendedMasterSecret:
+ m.extendedMasterSecret = true
+ case extensionALPN:
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return false
+ }
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) ||
+ proto.Empty() || !protoList.Empty() {
+ return false
+ }
+ m.alpnProtocol = string(proto)
+ case extensionSCT:
+ var sctList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() {
+ return false
+ }
+ for !sctList.Empty() {
+ var sct []byte
+ if !readUint16LengthPrefixed(&sctList, &sct) ||
+ len(sct) == 0 {
+ return false
+ }
+ m.scts = append(m.scts, sct)
+ }
+ case extensionSupportedVersions:
+ if !extData.ReadUint16(&m.supportedVersion) {
+ return false
+ }
+ case extensionCookie:
+ if !readUint16LengthPrefixed(&extData, &m.cookie) ||
+ len(m.cookie) == 0 {
+ return false
+ }
+ case extensionKeyShare:
+ // This extension has different formats in SH and HRR, accept either
+ // and let the handshake logic decide. See RFC 8446, Section 4.2.8.
+ if len(extData) == 2 {
+ if !extData.ReadUint16((*uint16)(&m.selectedGroup)) {
+ return false
+ }
+ } else {
+ if !extData.ReadUint16((*uint16)(&m.serverShare.group)) ||
+ !readUint16LengthPrefixed(&extData, &m.serverShare.data) {
+ return false
+ }
+ }
+ case extensionPreSharedKey:
+ m.selectedIdentityPresent = true
+ if !extData.ReadUint16(&m.selectedIdentity) {
+ return false
+ }
+ case extensionSupportedPoints:
+ // RFC 4492, Section 5.1.2
+ if !readUint8LengthPrefixed(&extData, &m.supportedPoints) ||
+ len(m.supportedPoints) == 0 {
+ return false
+ }
+ case extensionEncryptedClientHello: // encrypted_client_hello
+ m.encryptedClientHello = make([]byte, len(extData))
+ if !extData.CopyBytes(m.encryptedClientHello) {
+ return false
+ }
+ case extensionServerName:
+ if len(extData) != 0 {
+ return false
+ }
+ m.serverNameAck = true
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (m *serverHelloMsg) originalBytes() []byte {
+ return m.original
+}
+
+type encryptedExtensionsMsg struct {
+ alpnProtocol string
+ quicTransportParameters []byte
+ earlyData bool
+ echRetryConfigs []byte
+
+ utls utlsEncryptedExtensionsMsgExtraFields // [uTLS]
+}
+
+func (m *encryptedExtensionsMsg) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeEncryptedExtensions)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if len(m.alpnProtocol) > 0 {
+ b.AddUint16(extensionALPN)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte(m.alpnProtocol))
+ })
+ })
+ })
+ }
+ if m.quicTransportParameters != nil { // marshal zero-length parameters when present
+ // draft-ietf-quic-tls-32, Section 8.2
+ b.AddUint16(extensionQUICTransportParameters)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.quicTransportParameters)
+ })
+ }
+ if m.earlyData {
+ // RFC 8446, Section 4.2.10
+ b.AddUint16(extensionEarlyData)
+ b.AddUint16(0) // empty extension_data
+ }
+ if len(m.echRetryConfigs) > 0 {
+ b.AddUint16(extensionEncryptedClientHello)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.echRetryConfigs)
+ })
+ }
+ })
+ })
+
+ return b.Bytes()
+}
+
+func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
+ *m = encryptedExtensionsMsg{}
+ s := cryptobyte.String(data)
+
+ var extensions cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+ return false
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ switch extension {
+ case extensionALPN:
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return false
+ }
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) ||
+ proto.Empty() || !protoList.Empty() {
+ return false
+ }
+ m.alpnProtocol = string(proto)
+ case extensionQUICTransportParameters:
+ m.quicTransportParameters = make([]byte, len(extData))
+ if !extData.CopyBytes(m.quicTransportParameters) {
+ return false
+ }
+ case extensionEarlyData:
+ // RFC 8446, Section 4.2.10
+ m.earlyData = true
+ case extensionEncryptedClientHello:
+ m.echRetryConfigs = make([]byte, len(extData))
+ if !extData.CopyBytes(m.echRetryConfigs) {
+ return false
+ }
+ default:
+ // [UTLS SECTION START]
+ if !m.utlsUnmarshal(extension, extData) {
+ return false // return false when ERROR
+ }
+ // [UTLS SECTION END]
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+type endOfEarlyDataMsg struct{}
+
+func (m *endOfEarlyDataMsg) marshal() ([]byte, error) {
+ x := make([]byte, 4)
+ x[0] = typeEndOfEarlyData
+ return x, nil
+}
+
+func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type keyUpdateMsg struct {
+ updateRequested bool
+}
+
+func (m *keyUpdateMsg) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeKeyUpdate)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.updateRequested {
+ b.AddUint8(1)
+ } else {
+ b.AddUint8(0)
+ }
+ })
+
+ return b.Bytes()
+}
+
+func (m *keyUpdateMsg) unmarshal(data []byte) bool {
+ s := cryptobyte.String(data)
+
+ var updateRequested uint8
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8(&updateRequested) || !s.Empty() {
+ return false
+ }
+ switch updateRequested {
+ case 0:
+ m.updateRequested = false
+ case 1:
+ m.updateRequested = true
+ default:
+ return false
+ }
+ return true
+}
+
+type newSessionTicketMsgTLS13 struct {
+ lifetime uint32
+ ageAdd uint32
+ nonce []byte
+ label []byte
+ maxEarlyData uint32
+}
+
+func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeNewSessionTicket)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint32(m.lifetime)
+ b.AddUint32(m.ageAdd)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.nonce)
+ })
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.label)
+ })
+
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.maxEarlyData > 0 {
+ b.AddUint16(extensionEarlyData)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint32(m.maxEarlyData)
+ })
+ }
+ })
+ })
+
+ return b.Bytes()
+}
+
+func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool {
+ *m = newSessionTicketMsgTLS13{}
+ s := cryptobyte.String(data)
+
+ var extensions cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint32(&m.lifetime) ||
+ !s.ReadUint32(&m.ageAdd) ||
+ !readUint8LengthPrefixed(&s, &m.nonce) ||
+ !readUint16LengthPrefixed(&s, &m.label) ||
+ !s.ReadUint16LengthPrefixed(&extensions) ||
+ !s.Empty() {
+ return false
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ switch extension {
+ case extensionEarlyData:
+ if !extData.ReadUint32(&m.maxEarlyData) {
+ return false
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+type certificateRequestMsgTLS13 struct {
+ original []byte // [uTLS]
+ ocspStapling bool
+ scts bool
+ supportedSignatureAlgorithms []SignatureScheme
+ supportedSignatureAlgorithmsCert []SignatureScheme
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificateRequest)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ // certificate_request_context (SHALL be zero length unless used for
+ // post-handshake authentication)
+ b.AddUint8(0)
+
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.ocspStapling {
+ b.AddUint16(extensionStatusRequest)
+ b.AddUint16(0) // empty extension_data
+ }
+ if m.scts {
+ // RFC 8446, Section 4.4.2.1 makes no mention of
+ // signed_certificate_timestamp in CertificateRequest, but
+ // "Extensions in the Certificate message from the client MUST
+ // correspond to extensions in the CertificateRequest message
+ // from the server." and it appears in the table in Section 4.2.
+ b.AddUint16(extensionSCT)
+ b.AddUint16(0) // empty extension_data
+ }
+ if len(m.supportedSignatureAlgorithms) > 0 {
+ b.AddUint16(extensionSignatureAlgorithms)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithms {
+ b.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ if len(m.supportedSignatureAlgorithmsCert) > 0 {
+ b.AddUint16(extensionSignatureAlgorithmsCert)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
+ b.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ if len(m.certificateAuthorities) > 0 {
+ b.AddUint16(extensionCertificateAuthorities)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, ca := range m.certificateAuthorities {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(ca)
+ })
+ }
+ })
+ })
+ }
+ })
+ })
+
+ return b.Bytes()
+}
+
+func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool {
+ *m = certificateRequestMsgTLS13{original: data} // [uTLS]
+ s := cryptobyte.String(data)
+
+ var context, extensions cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8LengthPrefixed(&context) || !context.Empty() ||
+ !s.ReadUint16LengthPrefixed(&extensions) ||
+ !s.Empty() {
+ return false
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ switch extension {
+ case extensionStatusRequest:
+ m.ocspStapling = true
+ case extensionSCT:
+ m.scts = true
+ case extensionSignatureAlgorithms:
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithms = append(
+ m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+ }
+ case extensionSignatureAlgorithmsCert:
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithmsCert = append(
+ m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg))
+ }
+ case extensionCertificateAuthorities:
+ var auths cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&auths) || auths.Empty() {
+ return false
+ }
+ for !auths.Empty() {
+ var ca []byte
+ if !readUint16LengthPrefixed(&auths, &ca) || len(ca) == 0 {
+ return false
+ }
+ m.certificateAuthorities = append(m.certificateAuthorities, ca)
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+// [UTLS SECTION BEGINS]
+func (m *certificateRequestMsgTLS13) originalBytes() []byte {
+ return m.original
+}
+
+// [UTLS SECTION ENDS]
+
+type certificateMsg struct {
+ certificates [][]byte
+}
+
+func (m *certificateMsg) marshal() ([]byte, error) {
+ var i int
+ for _, slice := range m.certificates {
+ i += len(slice)
+ }
+
+ length := 3 + 3*len(m.certificates) + i
+ x := make([]byte, 4+length)
+ x[0] = typeCertificate
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ certificateOctets := length - 3
+ x[4] = uint8(certificateOctets >> 16)
+ x[5] = uint8(certificateOctets >> 8)
+ x[6] = uint8(certificateOctets)
+
+ y := x[7:]
+ for _, slice := range m.certificates {
+ y[0] = uint8(len(slice) >> 16)
+ y[1] = uint8(len(slice) >> 8)
+ y[2] = uint8(len(slice))
+ copy(y[3:], slice)
+ y = y[3+len(slice):]
+ }
+
+ return x, nil
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+ if len(data) < 7 {
+ return false
+ }
+
+ certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+ if uint32(len(data)) != certsLen+7 {
+ return false
+ }
+
+ numCerts := 0
+ d := data[7:]
+ for certsLen > 0 {
+ if len(d) < 4 {
+ return false
+ }
+ certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+ if uint32(len(d)) < 3+certLen {
+ return false
+ }
+ d = d[3+certLen:]
+ certsLen -= 3 + certLen
+ numCerts++
+ }
+
+ m.certificates = make([][]byte, numCerts)
+ d = data[7:]
+ for i := 0; i < numCerts; i++ {
+ certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+ m.certificates[i] = d[3 : 3+certLen]
+ d = d[3+certLen:]
+ }
+
+ return true
+}
+
+type certificateMsgTLS13 struct {
+ certificate Certificate
+ ocspStapling bool
+ scts bool
+}
+
+func (m *certificateMsgTLS13) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificate)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8(0) // certificate_request_context
+
+ certificate := m.certificate
+ if !m.ocspStapling {
+ certificate.OCSPStaple = nil
+ }
+ if !m.scts {
+ certificate.SignedCertificateTimestamps = nil
+ }
+ marshalCertificate(b, certificate)
+ })
+
+ return b.Bytes()
+}
+
+func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ for i, cert := range certificate.Certificate {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(cert)
+ })
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if i > 0 {
+ // This library only supports OCSP and SCT for leaf certificates.
+ return
+ }
+ if certificate.OCSPStaple != nil {
+ b.AddUint16(extensionStatusRequest)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8(statusTypeOCSP)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(certificate.OCSPStaple)
+ })
+ })
+ }
+ if certificate.SignedCertificateTimestamps != nil {
+ b.AddUint16(extensionSCT)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, sct := range certificate.SignedCertificateTimestamps {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(sct)
+ })
+ }
+ })
+ })
+ }
+ })
+ }
+ })
+}
+
+func (m *certificateMsgTLS13) unmarshal(data []byte) bool {
+ *m = certificateMsgTLS13{}
+ s := cryptobyte.String(data)
+
+ var context cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8LengthPrefixed(&context) || !context.Empty() ||
+ !unmarshalCertificate(&s, &m.certificate) ||
+ !s.Empty() {
+ return false
+ }
+
+ m.scts = m.certificate.SignedCertificateTimestamps != nil
+ m.ocspStapling = m.certificate.OCSPStaple != nil
+
+ return true
+}
+
+func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool {
+ var certList cryptobyte.String
+ if !s.ReadUint24LengthPrefixed(&certList) {
+ return false
+ }
+ for !certList.Empty() {
+ var cert []byte
+ var extensions cryptobyte.String
+ if !readUint24LengthPrefixed(&certList, &cert) ||
+ !certList.ReadUint16LengthPrefixed(&extensions) {
+ return false
+ }
+ certificate.Certificate = append(certificate.Certificate, cert)
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+ if len(certificate.Certificate) > 1 {
+ // This library only supports OCSP and SCT for leaf certificates.
+ continue
+ }
+
+ switch extension {
+ case extensionStatusRequest:
+ var statusType uint8
+ if !extData.ReadUint8(&statusType) || statusType != statusTypeOCSP ||
+ !readUint24LengthPrefixed(&extData, &certificate.OCSPStaple) ||
+ len(certificate.OCSPStaple) == 0 {
+ return false
+ }
+ case extensionSCT:
+ var sctList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() {
+ return false
+ }
+ for !sctList.Empty() {
+ var sct []byte
+ if !readUint16LengthPrefixed(&sctList, &sct) ||
+ len(sct) == 0 {
+ return false
+ }
+ certificate.SignedCertificateTimestamps = append(
+ certificate.SignedCertificateTimestamps, sct)
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+type serverKeyExchangeMsg struct {
+ key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() ([]byte, error) {
+ length := len(m.key)
+ x := make([]byte, length+4)
+ x[0] = typeServerKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.key)
+
+ return x, nil
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+ if len(data) < 4 {
+ return false
+ }
+ m.key = data[4:]
+ return true
+}
+
+type certificateStatusMsg struct {
+ response []byte
+}
+
+func (m *certificateStatusMsg) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificateStatus)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8(statusTypeOCSP)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.response)
+ })
+ })
+
+ return b.Bytes()
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+ s := cryptobyte.String(data)
+
+ var statusType uint8
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8(&statusType) || statusType != statusTypeOCSP ||
+ !readUint24LengthPrefixed(&s, &m.response) ||
+ len(m.response) == 0 || !s.Empty() {
+ return false
+ }
+ return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) marshal() ([]byte, error) {
+ x := make([]byte, 4)
+ x[0] = typeServerHelloDone
+ return x, nil
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+ ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() ([]byte, error) {
+ length := len(m.ciphertext)
+ x := make([]byte, length+4)
+ x[0] = typeClientKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.ciphertext)
+
+ return x, nil
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+ if len(data) < 4 {
+ return false
+ }
+ l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if l != len(data)-4 {
+ return false
+ }
+ m.ciphertext = data[4:]
+ return true
+}
+
+type finishedMsg struct {
+ verifyData []byte
+}
+
+func (m *finishedMsg) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeFinished)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.verifyData)
+ })
+
+ return b.Bytes()
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+ s := cryptobyte.String(data)
+ return s.Skip(1) &&
+ readUint24LengthPrefixed(&s, &m.verifyData) &&
+ s.Empty()
+}
+
+type certificateRequestMsg struct {
+ // hasSignatureAlgorithm indicates whether this message includes a list of
+ // supported signature algorithms. This change was introduced with TLS 1.2.
+ hasSignatureAlgorithm bool
+
+ certificateTypes []byte
+ supportedSignatureAlgorithms []SignatureScheme
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() ([]byte, error) {
+ // See RFC 4346, Section 7.4.4.
+ length := 1 + len(m.certificateTypes) + 2
+ casLength := 0
+ for _, ca := range m.certificateAuthorities {
+ casLength += 2 + len(ca)
+ }
+ length += casLength
+
+ if m.hasSignatureAlgorithm {
+ length += 2 + 2*len(m.supportedSignatureAlgorithms)
+ }
+
+ x := make([]byte, 4+length)
+ x[0] = typeCertificateRequest
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ x[4] = uint8(len(m.certificateTypes))
+
+ copy(x[5:], m.certificateTypes)
+ y := x[5+len(m.certificateTypes):]
+
+ if m.hasSignatureAlgorithm {
+ n := len(m.supportedSignatureAlgorithms) * 2
+ y[0] = uint8(n >> 8)
+ y[1] = uint8(n)
+ y = y[2:]
+ for _, sigAlgo := range m.supportedSignatureAlgorithms {
+ y[0] = uint8(sigAlgo >> 8)
+ y[1] = uint8(sigAlgo)
+ y = y[2:]
+ }
+ }
+
+ y[0] = uint8(casLength >> 8)
+ y[1] = uint8(casLength)
+ y = y[2:]
+ for _, ca := range m.certificateAuthorities {
+ y[0] = uint8(len(ca) >> 8)
+ y[1] = uint8(len(ca))
+ y = y[2:]
+ copy(y, ca)
+ y = y[len(ca):]
+ }
+
+ return x, nil
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+ if len(data) < 5 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ numCertTypes := int(data[4])
+ data = data[5:]
+ if numCertTypes == 0 || len(data) <= numCertTypes {
+ return false
+ }
+
+ m.certificateTypes = make([]byte, numCertTypes)
+ if copy(m.certificateTypes, data) != numCertTypes {
+ return false
+ }
+
+ data = data[numCertTypes:]
+
+ if m.hasSignatureAlgorithm {
+ if len(data) < 2 {
+ return false
+ }
+ sigAndHashLen := uint16(data[0])<<8 | uint16(data[1])
+ data = data[2:]
+ if sigAndHashLen&1 != 0 {
+ return false
+ }
+ if len(data) < int(sigAndHashLen) {
+ return false
+ }
+ numSigAlgos := sigAndHashLen / 2
+ m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos)
+ for i := range m.supportedSignatureAlgorithms {
+ m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1])
+ data = data[2:]
+ }
+ }
+
+ if len(data) < 2 {
+ return false
+ }
+ casLength := uint16(data[0])<<8 | uint16(data[1])
+ data = data[2:]
+ if len(data) < int(casLength) {
+ return false
+ }
+ cas := make([]byte, casLength)
+ copy(cas, data)
+ data = data[casLength:]
+
+ m.certificateAuthorities = nil
+ for len(cas) > 0 {
+ if len(cas) < 2 {
+ return false
+ }
+ caLen := uint16(cas[0])<<8 | uint16(cas[1])
+ cas = cas[2:]
+
+ if len(cas) < int(caLen) {
+ return false
+ }
+
+ m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+ cas = cas[caLen:]
+ }
+
+ return len(data) == 0
+}
+
+type certificateVerifyMsg struct {
+ hasSignatureAlgorithm bool // format change introduced in TLS 1.2
+ signatureAlgorithm SignatureScheme
+ signature []byte
+}
+
+func (m *certificateVerifyMsg) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificateVerify)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.hasSignatureAlgorithm {
+ b.AddUint16(uint16(m.signatureAlgorithm))
+ }
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.signature)
+ })
+ })
+
+ return b.Bytes()
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+ s := cryptobyte.String(data)
+
+ if !s.Skip(4) { // message type and uint24 length field
+ return false
+ }
+ if m.hasSignatureAlgorithm {
+ if !s.ReadUint16((*uint16)(&m.signatureAlgorithm)) {
+ return false
+ }
+ }
+ return readUint16LengthPrefixed(&s, &m.signature) && s.Empty()
+}
+
+type newSessionTicketMsg struct {
+ ticket []byte
+}
+
+func (m *newSessionTicketMsg) marshal() ([]byte, error) {
+ // See RFC 5077, Section 3.3.
+ ticketLen := len(m.ticket)
+ length := 2 + 4 + ticketLen
+ x := make([]byte, 4+length)
+ x[0] = typeNewSessionTicket
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[8] = uint8(ticketLen >> 8)
+ x[9] = uint8(ticketLen)
+ copy(x[10:], m.ticket)
+
+ return x, nil
+}
+
+func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
+ if len(data) < 10 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ ticketLen := int(data[8])<<8 + int(data[9])
+ if len(data)-10 != ticketLen {
+ return false
+ }
+
+ m.ticket = data[10:]
+
+ return true
+}
+
+type helloRequestMsg struct {
+}
+
+func (*helloRequestMsg) marshal() ([]byte, error) {
+ return []byte{typeHelloRequest, 0, 0, 0}, nil
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type transcriptHash interface {
+ Write([]byte) (int, error)
+}
+
+// transcriptMsg is a helper used to hash messages which are not hashed when
+// they are read from, or written to, the wire. This is typically the case for
+// messages which are either not sent, or need to be hashed out of order from
+// when they are read/written.
+//
+// For most messages, the message is marshalled using their marshal method,
+// since their wire representation is idempotent. For clientHelloMsg and
+// serverHelloMsg, we store the original wire representation of the message and
+// use that for hashing, since unmarshal/marshal are not idempotent due to
+// extension ordering and other malleable fields, which may cause differences
+// between what was received and what we marshal.
+func transcriptMsg(msg handshakeMessage, h transcriptHash) error {
+ if msgWithOrig, ok := msg.(handshakeMessageWithOriginalBytes); ok {
+ if orig := msgWithOrig.originalBytes(); orig != nil {
+ h.Write(msgWithOrig.originalBytes())
+ return nil
+ }
+ }
+
+ data, err := msg.marshal()
+ if err != nil {
+ return err
+ }
+ h.Write(data)
+ return nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/handshake_server.go b/vendor/github.com/refraction-networking/utls/handshake_server.go
new file mode 100644
index 00000000..e38ebaeb
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/handshake_server.go
@@ -0,0 +1,1009 @@
+// 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 tls
+
+import (
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "time"
+
+ "github.com/refraction-networking/utls/internal/byteorder"
+)
+
+// serverHandshakeState contains details of a server handshake in progress.
+// It's discarded once the handshake has completed.
+type serverHandshakeState struct {
+ c *Conn
+ ctx context.Context
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ suite *cipherSuite
+ ecdheOk bool
+ ecSignOk bool
+ rsaDecryptOk bool
+ rsaSignOk bool
+ sessionState *SessionState
+ finishedHash finishedHash
+ masterSecret []byte
+ cert *Certificate
+}
+
+// serverHandshake performs a TLS handshake as a server.
+func (c *Conn) serverHandshake(ctx context.Context) error {
+ clientHello, ech, err := c.readClientHello(ctx)
+ if err != nil {
+ return err
+ }
+
+ if c.vers == VersionTLS13 {
+ hs := serverHandshakeStateTLS13{
+ c: c,
+ ctx: ctx,
+ clientHello: clientHello,
+ echContext: ech,
+ }
+ return hs.handshake()
+ }
+
+ hs := serverHandshakeState{
+ c: c,
+ ctx: ctx,
+ clientHello: clientHello,
+ }
+ return hs.handshake()
+}
+
+func (hs *serverHandshakeState) handshake() error {
+ c := hs.c
+
+ if err := hs.processClientHello(); err != nil {
+ return err
+ }
+
+ // For an overview of TLS handshaking, see RFC 5246, Section 7.3.
+ c.buffering = true
+ if err := hs.checkForResumption(); err != nil {
+ return err
+ }
+ if hs.sessionState != nil {
+ // The client has included a session ticket and so we do an abbreviated handshake.
+ c.didResume = true
+ if err := hs.doResumeHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = false
+ if err := hs.readFinished(nil); err != nil {
+ return err
+ }
+ } else {
+ // The client didn't include a session ticket, or it wasn't
+ // valid so we do a full handshake.
+ if err := hs.pickCipherSuite(); err != nil {
+ return err
+ }
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.clientFinished[:]); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = true
+ c.buffering = true
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(nil); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ }
+
+ c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random)
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+// readClientHello reads a ClientHello message and selects the protocol version.
+func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, *echServerContext, error) {
+ // clientHelloMsg is included in the transcript, but we haven't initialized
+ // it yet. The respective handshake functions will record it themselves.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return nil, nil, err
+ }
+ clientHello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, nil, unexpectedMessageError(clientHello, msg)
+ }
+
+ // ECH processing has to be done before we do any other negotiation based on
+ // the contents of the client hello, since we may swap it out completely.
+ var ech *echServerContext
+ if len(clientHello.encryptedClientHello) != 0 {
+ clientHello, ech, err = c.processECHClientHello(clientHello)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ var configForClient *Config
+ originalConfig := c.config
+ if c.config.GetConfigForClient != nil {
+ chi := clientHelloInfo(ctx, c, clientHello)
+ if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
+ c.sendAlert(alertInternalError)
+ return nil, nil, err
+ } else if configForClient != nil {
+ c.config = configForClient
+ }
+ }
+ c.ticketKeys = originalConfig.ticketKeys(configForClient)
+
+ clientVersions := clientHello.supportedVersions
+ if len(clientHello.supportedVersions) == 0 {
+ clientVersions = supportedVersionsFromMax(clientHello.vers)
+ }
+ c.vers, ok = c.config.mutualVersion(roleServer, clientVersions)
+ if !ok {
+ c.sendAlert(alertProtocolVersion)
+ return nil, nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
+ }
+ c.haveVers = true
+ c.in.version = c.vers
+ c.out.version = c.vers
+
+ // This check reflects some odd specification implied behavior. Client-facing servers
+ // are supposed to reject hellos with outer ECH and inner ECH that offers 1.2, but
+ // backend servers are allowed to accept hellos with inner ECH that offer 1.2, since
+ // they cannot expect client-facing servers to behave properly. Since we act as both
+ // a client-facing and backend server, we only enforce 1.3 being negotiated if we
+ // saw a hello with outer ECH first. The spec probably should've made this an error,
+ // but it didn't, and this matches the boringssl behavior.
+ if c.vers != VersionTLS13 && (ech != nil && !ech.inner) {
+ c.sendAlert(alertIllegalParameter)
+ return nil, nil, errors.New("tls: Encrypted Client Hello cannot be used pre-TLS 1.3")
+ }
+
+ // [UTLS SECTION BEGIN]
+ // Disable unsupported godebug package
+ // if c.config.MinVersion == 0 && c.vers < VersionTLS12 {
+ // tls10server.Value() // ensure godebug is initialized
+ // tls10server.IncNonDefault()
+ // }
+ // [UTLS SECTION END]
+
+ return clientHello, ech, nil
+}
+
+func (hs *serverHandshakeState) processClientHello() error {
+ c := hs.c
+
+ hs.hello = new(serverHelloMsg)
+ hs.hello.vers = c.vers
+
+ foundCompression := false
+ // We only support null compression, so check that the client offered it.
+ for _, compression := range hs.clientHello.compressionMethods {
+ if compression == compressionNone {
+ foundCompression = true
+ break
+ }
+ }
+
+ if !foundCompression {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client does not support uncompressed connections")
+ }
+
+ hs.hello.random = make([]byte, 32)
+ serverRandom := hs.hello.random
+ // Downgrade protection canaries. See RFC 8446, Section 4.1.3.
+ maxVers := c.config.maxSupportedVersion(roleServer)
+ if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary {
+ if c.vers == VersionTLS12 {
+ copy(serverRandom[24:], downgradeCanaryTLS12)
+ } else {
+ copy(serverRandom[24:], downgradeCanaryTLS11)
+ }
+ serverRandom = serverRandom[:24]
+ }
+ _, err := io.ReadFull(c.config.rand(), serverRandom)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ if len(hs.clientHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+
+ hs.hello.extendedMasterSecret = hs.clientHello.extendedMasterSecret
+ hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
+ hs.hello.compressionMethod = compressionNone
+ if len(hs.clientHello.serverName) > 0 {
+ c.serverName = hs.clientHello.serverName
+ }
+
+ selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, false)
+ if err != nil {
+ c.sendAlert(alertNoApplicationProtocol)
+ return err
+ }
+ hs.hello.alpnProtocol = selectedProto
+ c.clientProtocol = selectedProto
+
+ hs.cert, err = c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
+ if err != nil {
+ if err == errNoCertificates {
+ c.sendAlert(alertUnrecognizedName)
+ } else {
+ c.sendAlert(alertInternalError)
+ }
+ return err
+ }
+ if hs.clientHello.scts {
+ hs.hello.scts = hs.cert.SignedCertificateTimestamps
+ }
+
+ hs.ecdheOk = supportsECDHE(c.config, c.vers, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints)
+
+ if hs.ecdheOk && len(hs.clientHello.supportedPoints) > 0 {
+ // Although omitting the ec_point_formats extension is permitted, some
+ // old OpenSSL version will refuse to handshake if not present.
+ //
+ // Per RFC 4492, section 5.1.2, implementations MUST support the
+ // uncompressed point format. See golang.org/issue/31943.
+ hs.hello.supportedPoints = []uint8{pointFormatUncompressed}
+ }
+
+ if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
+ switch priv.Public().(type) {
+ case *ecdsa.PublicKey:
+ hs.ecSignOk = true
+ case ed25519.PublicKey:
+ hs.ecSignOk = true
+ case *rsa.PublicKey:
+ hs.rsaSignOk = true
+ default:
+ c.sendAlert(alertInternalError)
+ return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
+ }
+ }
+ if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
+ switch priv.Public().(type) {
+ case *rsa.PublicKey:
+ hs.rsaDecryptOk = true
+ default:
+ c.sendAlert(alertInternalError)
+ return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
+ }
+ }
+
+ return nil
+}
+
+// negotiateALPN picks a shared ALPN protocol that both sides support in server
+// preference order. If ALPN is not configured or the peer doesn't support it,
+// it returns "" and no error.
+func negotiateALPN(serverProtos, clientProtos []string, quic bool) (string, error) {
+ if len(serverProtos) == 0 || len(clientProtos) == 0 {
+ if quic && len(serverProtos) != 0 {
+ // RFC 9001, Section 8.1
+ return "", fmt.Errorf("tls: client did not request an application protocol")
+ }
+ return "", nil
+ }
+ var http11fallback bool
+ for _, s := range serverProtos {
+ for _, c := range clientProtos {
+ if s == c {
+ return s, nil
+ }
+ if s == "h2" && c == "http/1.1" {
+ http11fallback = true
+ }
+ }
+ }
+ // As a special case, let http/1.1 clients connect to h2 servers as if they
+ // didn't support ALPN. We used not to enforce protocol overlap, so over
+ // time a number of HTTP servers were configured with only "h2", but
+ // expected to accept connections from "http/1.1" clients. See Issue 46310.
+ if http11fallback {
+ return "", nil
+ }
+ return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos)
+}
+
+// supportsECDHE returns whether ECDHE key exchanges can be used with this
+// pre-TLS 1.3 client.
+func supportsECDHE(c *Config, version uint16, supportedCurves []CurveID, supportedPoints []uint8) bool {
+ supportsCurve := false
+ for _, curve := range supportedCurves {
+ if c.supportsCurve(version, curve) {
+ supportsCurve = true
+ break
+ }
+ }
+
+ supportsPointFormat := false
+ for _, pointFormat := range supportedPoints {
+ if pointFormat == pointFormatUncompressed {
+ supportsPointFormat = true
+ break
+ }
+ }
+ // Per RFC 8422, Section 5.1.2, if the Supported Point Formats extension is
+ // missing, uncompressed points are supported. If supportedPoints is empty,
+ // the extension must be missing, as an empty extension body is rejected by
+ // the parser. See https://go.dev/issue/49126.
+ if len(supportedPoints) == 0 {
+ supportsPointFormat = true
+ }
+
+ return supportsCurve && supportsPointFormat
+}
+
+func (hs *serverHandshakeState) pickCipherSuite() error {
+ c := hs.c
+
+ preferenceOrder := cipherSuitesPreferenceOrder
+ if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
+ preferenceOrder = cipherSuitesPreferenceOrderNoAES
+ }
+
+ configCipherSuites := c.config.cipherSuites()
+ preferenceList := make([]uint16, 0, len(configCipherSuites))
+ for _, suiteID := range preferenceOrder {
+ for _, id := range configCipherSuites {
+ if id == suiteID {
+ preferenceList = append(preferenceList, id)
+ break
+ }
+ }
+ }
+
+ hs.suite = selectCipherSuite(preferenceList, hs.clientHello.cipherSuites, hs.cipherSuiteOk)
+ if hs.suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no cipher suite supported by both client and server")
+ }
+ c.cipherSuite = hs.suite.id
+
+ // [UTLS SECTION BEGIN]
+ // Disable unsupported godebug package
+ // if c.config.CipherSuites == nil && !fips140tls.Required() && rsaKexCiphers[hs.suite.id] {
+ // tlsrsakex.Value() // ensure godebug is initialized
+ // tlsrsakex.IncNonDefault()
+ // }
+ // if c.config.CipherSuites == nil && !fips140tls.Required() && tdesCiphers[hs.suite.id] {
+ // tls3des.Value() // ensure godebug is initialized
+ // tls3des.IncNonDefault()
+ // }
+ // [UTLS SECTION END]
+
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == TLS_FALLBACK_SCSV {
+ // The client is doing a fallback connection. See RFC 7507.
+ if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) {
+ c.sendAlert(alertInappropriateFallback)
+ return errors.New("tls: client using inappropriate protocol fallback")
+ }
+ break
+ }
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool {
+ if c.flags&suiteECDHE != 0 {
+ if !hs.ecdheOk {
+ return false
+ }
+ if c.flags&suiteECSign != 0 {
+ if !hs.ecSignOk {
+ return false
+ }
+ } else if !hs.rsaSignOk {
+ return false
+ }
+ } else if !hs.rsaDecryptOk {
+ return false
+ }
+ if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+ return false
+ }
+ return true
+}
+
+// checkForResumption reports whether we should perform resumption on this connection.
+func (hs *serverHandshakeState) checkForResumption() error {
+ c := hs.c
+
+ if c.config.SessionTicketsDisabled {
+ return nil
+ }
+
+ var sessionState *SessionState
+ if c.config.UnwrapSession != nil {
+ ss, err := c.config.UnwrapSession(hs.clientHello.sessionTicket, c.connectionStateLocked())
+ if err != nil {
+ return err
+ }
+ if ss == nil {
+ return nil
+ }
+ sessionState = ss
+ } else {
+ plaintext := c.config.decryptTicket(hs.clientHello.sessionTicket, c.ticketKeys)
+ if plaintext == nil {
+ return nil
+ }
+ ss, err := ParseSessionState(plaintext)
+ if err != nil {
+ return nil
+ }
+ sessionState = ss
+ }
+
+ // TLS 1.2 tickets don't natively have a lifetime, but we want to avoid
+ // re-wrapping the same master secret in different tickets over and over for
+ // too long, weakening forward secrecy.
+ createdAt := time.Unix(int64(sessionState.createdAt), 0)
+ if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+ return nil
+ }
+
+ // Never resume a session for a different TLS version.
+ if c.vers != sessionState.version {
+ return nil
+ }
+
+ cipherSuiteOk := false
+ // Check that the client is still offering the ciphersuite in the session.
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == sessionState.cipherSuite {
+ cipherSuiteOk = true
+ break
+ }
+ }
+ if !cipherSuiteOk {
+ return nil
+ }
+
+ // Check that we also support the ciphersuite from the session.
+ suite := selectCipherSuite([]uint16{sessionState.cipherSuite},
+ c.config.cipherSuites(), hs.cipherSuiteOk)
+ if suite == nil {
+ return nil
+ }
+
+ sessionHasClientCerts := len(sessionState.peerCertificates) != 0
+ needClientCerts := requiresClientCert(c.config.ClientAuth)
+ if needClientCerts && !sessionHasClientCerts {
+ return nil
+ }
+ if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+ return nil
+ }
+ if sessionHasClientCerts && c.config.time().After(sessionState.peerCertificates[0].NotAfter) {
+ return nil
+ }
+ if sessionHasClientCerts && c.config.ClientAuth >= VerifyClientCertIfGiven &&
+ len(sessionState.verifiedChains) == 0 {
+ return nil
+ }
+
+ // RFC 7627, Section 5.3
+ if !sessionState.extMasterSecret && hs.clientHello.extendedMasterSecret {
+ return nil
+ }
+ if sessionState.extMasterSecret && !hs.clientHello.extendedMasterSecret {
+ // Aborting is somewhat harsh, but it's a MUST and it would indicate a
+ // weird downgrade in client capabilities.
+ return errors.New("tls: session supported extended_master_secret but client does not")
+ }
+
+ c.peerCertificates = sessionState.peerCertificates
+ c.ocspResponse = sessionState.ocspResponse
+ c.scts = sessionState.scts
+ c.verifiedChains = sessionState.verifiedChains
+ c.extMasterSecret = sessionState.extMasterSecret
+ hs.sessionState = sessionState
+ hs.suite = suite
+ c.didResume = true
+ return nil
+}
+
+func (hs *serverHandshakeState) doResumeHandshake() error {
+ c := hs.c
+
+ hs.hello.cipherSuite = hs.suite.id
+ c.cipherSuite = hs.suite.id
+ // We echo the client's session ID in the ServerHello to let it know
+ // that we're doing a resumption.
+ hs.hello.sessionId = hs.clientHello.sessionId
+ // We always send a new session ticket, even if it wraps the same master
+ // secret and it's potentially encrypted with the same key, to help the
+ // client avoid cross-connection tracking from a network observer.
+ hs.hello.ticketSupported = true
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+ hs.finishedHash.discardHandshakeBuffer()
+ if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
+ return err
+ }
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ hs.masterSecret = hs.sessionState.secret
+
+ return nil
+}
+
+func (hs *serverHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+ if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+ hs.hello.ocspStapling = true
+ }
+
+ hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
+ hs.hello.cipherSuite = hs.suite.id
+
+ hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
+ if c.config.ClientAuth == NoClientCert {
+ // No need to keep a full record of the handshake if client
+ // certificates won't be used.
+ hs.finishedHash.discardHandshakeBuffer()
+ }
+ if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
+ return err
+ }
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ certMsg := new(certificateMsg)
+ certMsg.certificates = hs.cert.Certificate
+ if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ if hs.hello.ocspStapling {
+ certStatus := new(certificateStatusMsg)
+ certStatus.response = hs.cert.OCSPStaple
+ if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ keyAgreement := hs.suite.ka(c.vers)
+ skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ if skx != nil {
+ if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ {
+ c.curveID = CurveID(byteorder.BEUint16(skx.key[1:]))
+ }
+ if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ var certReq *certificateRequestMsg
+ if c.config.ClientAuth >= RequestClientCert {
+ // Request a client certificate
+ certReq = new(certificateRequestMsg)
+ certReq.certificateTypes = []byte{
+ byte(certTypeRSASign),
+ byte(certTypeECDSASign),
+ }
+ if c.vers >= VersionTLS12 {
+ certReq.hasSignatureAlgorithm = true
+ certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+
+ // An empty list of certificateAuthorities signals to
+ // the client that it may send any certificate in response
+ // to our request. When we know the CAs we trust, then
+ // we can send them down, so that the client can choose
+ // an appropriate certificate to give to us.
+ if c.config.ClientCAs != nil {
+ certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+ }
+ if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ helloDone := new(serverHelloDoneMsg)
+ if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+
+ var pub crypto.PublicKey // public key for client auth, if any
+
+ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+
+ // If we requested a client certificate, then the client must send a
+ // certificate message, even if it's empty.
+ if c.config.ClientAuth >= RequestClientCert {
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+
+ if err := c.processCertsFromClient(Certificate{
+ Certificate: certMsg.certificates,
+ }); err != nil {
+ return err
+ }
+ if len(certMsg.certificates) != 0 {
+ pub = c.peerCertificates[0].PublicKey
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ // Get client key exchange
+ ckx, ok := msg.(*clientKeyExchangeMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(ckx, msg)
+ }
+
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ if hs.hello.extendedMasterSecret {
+ c.extMasterSecret = true
+ hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+ hs.finishedHash.Sum())
+ } else {
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+ hs.clientHello.random, hs.hello.random)
+ }
+ if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ // If we received a client cert in response to our certificate request message,
+ // the client will send us a certificateVerifyMsg immediately after the
+ // clientKeyExchangeMsg. This message is a digest of all preceding
+ // handshake-layer messages that is signed using the private key corresponding
+ // to the client's certificate. This allows us to verify that the client is in
+ // possession of the private key of the certificate.
+ if len(c.peerCertificates) > 0 {
+ // certificateVerifyMsg is included in the transcript, but not until
+ // after we verify the handshake signature, since the state before
+ // this message was sent is used.
+ msg, err = c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ var sigType uint8
+ var sigHash crypto.Hash
+ if c.vers >= VersionTLS12 {
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ }
+
+ signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
+ if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid signature by the client certificate: " + err.Error())
+ }
+
+ if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ hs.finishedHash.discardHandshakeBuffer()
+
+ return nil
+}
+
+func (hs *serverHandshakeState) establishKeys() error {
+ c := hs.c
+
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+
+ var clientCipher, serverCipher any
+ var clientHash, serverHash hash.Hash
+
+ if hs.suite.aead == nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
+ clientHash = hs.suite.mac(clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
+ serverHash = hs.suite.mac(serverMAC)
+ } else {
+ clientCipher = hs.suite.aead(clientKey, clientIV)
+ serverCipher = hs.suite.aead(serverKey, serverIV)
+ }
+
+ c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
+ c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
+
+ return nil
+}
+
+func (hs *serverHandshakeState) readFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.readChangeCipherSpec(); err != nil {
+ return err
+ }
+
+ // finishedMsg is included in the transcript, but not until after we
+ // check the client version, since the state before this message was
+ // sent is used during verification.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ clientFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(clientFinished, msg)
+ }
+
+ verify := hs.finishedHash.clientSum(hs.masterSecret)
+ if len(verify) != len(clientFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client's Finished message is incorrect")
+ }
+
+ if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ copy(out, verify)
+ return nil
+}
+
+func (hs *serverHandshakeState) sendSessionTicket() error {
+ // ticketSupported is set in a resumption handshake if the
+ // ticket from the client was encrypted with an old session
+ // ticket key and thus a refreshed ticket should be sent.
+ if !hs.hello.ticketSupported {
+ return nil
+ }
+
+ c := hs.c
+ m := new(newSessionTicketMsg)
+
+ state := c.sessionState()
+ state.secret = hs.masterSecret
+ if hs.sessionState != nil {
+ // If this is re-wrapping an old key, then keep
+ // the original time it was created.
+ state.createdAt = hs.sessionState.createdAt
+ }
+ if c.config.WrapSession != nil {
+ var err error
+ m.ticket, err = c.config.WrapSession(c.connectionStateLocked(), state)
+ if err != nil {
+ return err
+ }
+ } else {
+ stateBytes, err := state.Bytes()
+ if err != nil {
+ return err
+ }
+ m.ticket, err = c.config.encryptTicket(stateBytes, c.ticketKeys)
+ if err != nil {
+ return err
+ }
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.writeChangeCipherRecord(); err != nil {
+ return err
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+ if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ copy(out, finished.verifyData)
+
+ return nil
+}
+
+// processCertsFromClient takes a chain of client certificates either from a
+// Certificates message and verifies them.
+func (c *Conn) processCertsFromClient(certificate Certificate) error {
+ certificates := certificate.Certificate
+ certs := make([]*x509.Certificate, len(certificates))
+ var err error
+ for i, asn1Data := range certificates {
+ if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse client certificate: " + err.Error())
+ }
+ if certs[i].PublicKeyAlgorithm == x509.RSA {
+ n := certs[i].PublicKey.(*rsa.PublicKey).N.BitLen()
+ if max, ok := checkKeySize(n); !ok {
+ c.sendAlert(alertBadCertificate)
+ return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", max)
+ }
+ }
+ }
+
+ if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
+ if c.vers == VersionTLS13 {
+ c.sendAlert(alertCertificateRequired)
+ } else {
+ c.sendAlert(alertBadCertificate)
+ }
+ return errors.New("tls: client didn't provide a certificate")
+ }
+
+ if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
+ opts := x509.VerifyOptions{
+ Roots: c.config.ClientCAs,
+ CurrentTime: c.config.time(),
+ Intermediates: x509.NewCertPool(),
+ KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+ }
+
+ for _, cert := range certs[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+
+ chains, err := certs[0].Verify(opts)
+ if err != nil {
+ var errCertificateInvalid x509.CertificateInvalidError
+ if errors.As(err, &x509.UnknownAuthorityError{}) {
+ c.sendAlert(alertUnknownCA)
+ } else if errors.As(err, &errCertificateInvalid) && errCertificateInvalid.Reason == x509.Expired {
+ c.sendAlert(alertCertificateExpired)
+ } else {
+ c.sendAlert(alertBadCertificate)
+ }
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+
+ c.verifiedChains, err = fipsAllowedChains(chains)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+ }
+
+ c.peerCertificates = certs
+ c.ocspResponse = certificate.OCSPStaple
+ c.scts = certificate.SignedCertificateTimestamps
+
+ if len(certs) > 0 {
+ switch certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ }
+ }
+
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ return nil
+}
+
+func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
+ supportedVersions := clientHello.supportedVersions
+ if len(clientHello.supportedVersions) == 0 {
+ supportedVersions = supportedVersionsFromMax(clientHello.vers)
+ }
+
+ return &ClientHelloInfo{
+ CipherSuites: clientHello.cipherSuites,
+ ServerName: clientHello.serverName,
+ SupportedCurves: clientHello.supportedCurves,
+ SupportedPoints: clientHello.supportedPoints,
+ SignatureSchemes: clientHello.supportedSignatureAlgorithms,
+ SupportedProtos: clientHello.alpnProtocols,
+ SupportedVersions: supportedVersions,
+ Extensions: clientHello.extensions,
+ Conn: c.conn,
+ config: c.config,
+ ctx: ctx,
+ }
+}
diff --git a/vendor/github.com/refraction-networking/utls/handshake_server_tls13.go b/vendor/github.com/refraction-networking/utls/handshake_server_tls13.go
new file mode 100644
index 00000000..510db6f6
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/handshake_server_tls13.go
@@ -0,0 +1,1148 @@
+// 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 tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/hmac"
+ "crypto/mlkem"
+ "crypto/rsa"
+ "errors"
+ "hash"
+ "io"
+ "slices"
+ "sort"
+ "time"
+
+ "github.com/refraction-networking/utls/internal/byteorder"
+ "github.com/refraction-networking/utls/internal/fips140tls"
+ "github.com/refraction-networking/utls/internal/hkdf"
+ "github.com/refraction-networking/utls/internal/hpke"
+ "github.com/refraction-networking/utls/internal/tls13"
+)
+
+// maxClientPSKIdentities is the number of client PSK identities the server will
+// attempt to validate. It will ignore the rest not to let cheap ClientHello
+// messages cause too much work in session ticket decryption attempts.
+const maxClientPSKIdentities = 5
+
+type echServerContext struct {
+ hpkeContext *hpke.Receipient
+ configID uint8
+ ciphersuite echCipher
+ transcript hash.Hash
+ // inner indicates that the initial client_hello we recieved contained an
+ // encrypted_client_hello extension that indicated it was an "inner" hello.
+ // We don't do any additional processing of the hello in this case, so all
+ // fields above are unset.
+ inner bool
+}
+
+type serverHandshakeStateTLS13 struct {
+ c *Conn
+ ctx context.Context
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ sentDummyCCS bool
+ usingPSK bool
+ earlyData bool
+ suite *cipherSuiteTLS13
+ cert *Certificate
+ sigAlg SignatureScheme
+ earlySecret *tls13.EarlySecret
+ sharedKey []byte
+ handshakeSecret *tls13.HandshakeSecret
+ masterSecret *tls13.MasterSecret
+ trafficSecret []byte // client_application_traffic_secret_0
+ transcript hash.Hash
+ clientFinished []byte
+ echContext *echServerContext
+}
+
+func (hs *serverHandshakeStateTLS13) handshake() error {
+ c := hs.c
+
+ // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
+ if err := hs.processClientHello(); err != nil {
+ return err
+ }
+ if err := hs.checkForResumption(); err != nil {
+ return err
+ }
+ if err := hs.pickCertificate(); err != nil {
+ return err
+ }
+ c.buffering = true
+ if err := hs.sendServerParameters(); err != nil {
+ return err
+ }
+ if err := hs.sendServerCertificate(); err != nil {
+ return err
+ }
+ if err := hs.sendServerFinished(); err != nil {
+ return err
+ }
+ // Note that at this point we could start sending application data without
+ // waiting for the client's second flight, but the application might not
+ // expect the lack of replay protection of the ClientHello parameters.
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ if err := hs.readClientCertificate(); err != nil {
+ return err
+ }
+ if err := hs.readClientFinished(); err != nil {
+ return err
+ }
+
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) processClientHello() error {
+ c := hs.c
+
+ hs.hello = new(serverHelloMsg)
+
+ // TLS 1.3 froze the ServerHello.legacy_version field, and uses
+ // supported_versions instead. See RFC 8446, sections 4.1.3 and 4.2.1.
+ hs.hello.vers = VersionTLS12
+ hs.hello.supportedVersion = c.vers
+
+ if len(hs.clientHello.supportedVersions) == 0 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client used the legacy version field to negotiate TLS 1.3")
+ }
+
+ // Abort if the client is doing a fallback and landing lower than what we
+ // support. See RFC 7507, which however does not specify the interaction
+ // with supported_versions. The only difference is that with
+ // supported_versions a client has a chance to attempt a [TLS 1.2, TLS 1.4]
+ // handshake in case TLS 1.3 is broken but 1.2 is not. Alas, in that case,
+ // it will have to drop the TLS_FALLBACK_SCSV protection if it falls back to
+ // TLS 1.2, because a TLS 1.3 server would abort here. The situation before
+ // supported_versions was not better because there was just no way to do a
+ // TLS 1.4 handshake without risking the server selecting TLS 1.3.
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == TLS_FALLBACK_SCSV {
+ // Use c.vers instead of max(supported_versions) because an attacker
+ // could defeat this by adding an arbitrary high version otherwise.
+ if c.vers < c.config.maxSupportedVersion(roleServer) {
+ c.sendAlert(alertInappropriateFallback)
+ return errors.New("tls: client using inappropriate protocol fallback")
+ }
+ break
+ }
+ }
+
+ if len(hs.clientHello.compressionMethods) != 1 ||
+ hs.clientHello.compressionMethods[0] != compressionNone {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: TLS 1.3 client supports illegal compression methods")
+ }
+
+ hs.hello.random = make([]byte, 32)
+ if _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ if len(hs.clientHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+
+ if hs.clientHello.earlyData && c.quic != nil {
+ if len(hs.clientHello.pskIdentities) == 0 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: early_data without pre_shared_key")
+ }
+ } else if hs.clientHello.earlyData {
+ // See RFC 8446, Section 4.2.10 for the complicated behavior required
+ // here. The scenario is that a different server at our address offered
+ // to accept early data in the past, which we can't handle. For now, all
+ // 0-RTT enabled session tickets need to expire before a Go server can
+ // replace a server or join a pool. That's the same requirement that
+ // applies to mixing or replacing with any TLS 1.2 server.
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: client sent unexpected early data")
+ }
+
+ hs.hello.sessionId = hs.clientHello.sessionId
+ hs.hello.compressionMethod = compressionNone
+
+ preferenceList := defaultCipherSuitesTLS13
+ if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
+ preferenceList = defaultCipherSuitesTLS13NoAES
+ }
+ if fips140tls.Required() {
+ preferenceList = defaultCipherSuitesTLS13FIPS
+ }
+ for _, suiteID := range preferenceList {
+ hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
+ if hs.suite != nil {
+ break
+ }
+ }
+ if hs.suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no cipher suite supported by both client and server")
+ }
+ c.cipherSuite = hs.suite.id
+ hs.hello.cipherSuite = hs.suite.id
+ hs.transcript = hs.suite.hash.New()
+
+ // First, if a post-quantum key exchange is available, use one. See
+ // draft-ietf-tls-key-share-prediction-01, Section 4 for why this must be
+ // first.
+ //
+ // Second, if the client sent a key share for a group we support, use that,
+ // to avoid a HelloRetryRequest round-trip.
+ //
+ // Finally, pick in our fixed preference order.
+ preferredGroups := c.config.curvePreferences(c.vers)
+ preferredGroups = slices.DeleteFunc(preferredGroups, func(group CurveID) bool {
+ return !slices.Contains(hs.clientHello.supportedCurves, group)
+ })
+ if len(preferredGroups) == 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no key exchanges supported by both client and server")
+ }
+ hasKeyShare := func(group CurveID) bool {
+ for _, ks := range hs.clientHello.keyShares {
+ if ks.group == group {
+ return true
+ }
+ }
+ return false
+ }
+ sort.SliceStable(preferredGroups, func(i, j int) bool {
+ return hasKeyShare(preferredGroups[i]) && !hasKeyShare(preferredGroups[j])
+ })
+ sort.SliceStable(preferredGroups, func(i, j int) bool {
+ return isPQKeyExchange(preferredGroups[i]) && !isPQKeyExchange(preferredGroups[j])
+ })
+ selectedGroup := preferredGroups[0]
+
+ var clientKeyShare *keyShare
+ for _, ks := range hs.clientHello.keyShares {
+ if ks.group == selectedGroup {
+ clientKeyShare = &ks
+ break
+ }
+ }
+ if clientKeyShare == nil {
+ ks, err := hs.doHelloRetryRequest(selectedGroup)
+ if err != nil {
+ return err
+ }
+ clientKeyShare = ks
+ }
+ c.curveID = selectedGroup
+
+ ecdhGroup := selectedGroup
+ ecdhData := clientKeyShare.data
+ if selectedGroup == X25519MLKEM768 {
+ ecdhGroup = X25519
+ if len(ecdhData) != mlkem.EncapsulationKeySize768+x25519PublicKeySize {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid X25519MLKEM768 client key share")
+ }
+ ecdhData = ecdhData[mlkem.EncapsulationKeySize768:]
+ }
+ if _, ok := curveForCurveID(ecdhGroup); !ok {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+ key, err := generateECDHEKey(c.config.rand(), ecdhGroup)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()}
+ peerKey, err := key.Curve().NewPublicKey(ecdhData)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid client key share")
+ }
+ hs.sharedKey, err = key.ECDH(peerKey)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid client key share")
+ }
+ if selectedGroup == X25519MLKEM768 {
+ k, err := mlkem.NewEncapsulationKey768(clientKeyShare.data[:mlkem.EncapsulationKeySize768])
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid X25519MLKEM768 client key share")
+ }
+ mlkemSharedSecret, ciphertext := k.Encapsulate()
+ // draft-kwiatkowski-tls-ecdhe-mlkem-02, Section 3.1.3: "For
+ // X25519MLKEM768, the shared secret is the concatenation of the ML-KEM
+ // shared secret and the X25519 shared secret. The shared secret is 64
+ // bytes (32 bytes for each part)."
+ hs.sharedKey = append(mlkemSharedSecret, hs.sharedKey...)
+ // draft-kwiatkowski-tls-ecdhe-mlkem-02, Section 3.1.2: "When the
+ // X25519MLKEM768 group is negotiated, the server's key exchange value
+ // is the concatenation of an ML-KEM ciphertext returned from
+ // encapsulation to the client's encapsulation key, and the server's
+ // ephemeral X25519 share."
+ hs.hello.serverShare.data = append(ciphertext, hs.hello.serverShare.data...)
+ }
+
+ selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil)
+ if err != nil {
+ c.sendAlert(alertNoApplicationProtocol)
+ return err
+ }
+ c.clientProtocol = selectedProto
+
+ if c.quic != nil {
+ // RFC 9001 Section 4.2: Clients MUST NOT offer TLS versions older than 1.3.
+ for _, v := range hs.clientHello.supportedVersions {
+ if v < VersionTLS13 {
+ c.sendAlert(alertProtocolVersion)
+ return errors.New("tls: client offered TLS version older than TLS 1.3")
+ }
+ }
+ // RFC 9001 Section 8.2.
+ if hs.clientHello.quicTransportParameters == nil {
+ c.sendAlert(alertMissingExtension)
+ return errors.New("tls: client did not send a quic_transport_parameters extension")
+ }
+ c.quicSetTransportParameters(hs.clientHello.quicTransportParameters)
+ } else {
+ if hs.clientHello.quicTransportParameters != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: client sent an unexpected quic_transport_parameters extension")
+ }
+ }
+
+ c.serverName = hs.clientHello.serverName
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) checkForResumption() error {
+ c := hs.c
+
+ if c.config.SessionTicketsDisabled {
+ return nil
+ }
+
+ modeOK := false
+ for _, mode := range hs.clientHello.pskModes {
+ if mode == pskModeDHE {
+ modeOK = true
+ break
+ }
+ }
+ if !modeOK {
+ return nil
+ }
+
+ if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid or missing PSK binders")
+ }
+ if len(hs.clientHello.pskIdentities) == 0 {
+ return nil
+ }
+
+ for i, identity := range hs.clientHello.pskIdentities {
+ if i >= maxClientPSKIdentities {
+ break
+ }
+
+ var sessionState *SessionState
+ if c.config.UnwrapSession != nil {
+ var err error
+ sessionState, err = c.config.UnwrapSession(identity.label, c.connectionStateLocked())
+ if err != nil {
+ return err
+ }
+ if sessionState == nil {
+ continue
+ }
+ } else {
+ plaintext := c.config.decryptTicket(identity.label, c.ticketKeys)
+ if plaintext == nil {
+ continue
+ }
+ var err error
+ sessionState, err = ParseSessionState(plaintext)
+ if err != nil {
+ continue
+ }
+ }
+
+ if sessionState.version != VersionTLS13 {
+ continue
+ }
+
+ createdAt := time.Unix(int64(sessionState.createdAt), 0)
+ if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+ continue
+ }
+
+ pskSuite := cipherSuiteTLS13ByID(sessionState.cipherSuite)
+ if pskSuite == nil || pskSuite.hash != hs.suite.hash {
+ continue
+ }
+
+ // PSK connections don't re-establish client certificates, but carry
+ // them over in the session ticket. Ensure the presence of client certs
+ // in the ticket is consistent with the configured requirements.
+ sessionHasClientCerts := len(sessionState.peerCertificates) != 0
+ needClientCerts := requiresClientCert(c.config.ClientAuth)
+ if needClientCerts && !sessionHasClientCerts {
+ continue
+ }
+ if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+ continue
+ }
+ if sessionHasClientCerts && c.config.time().After(sessionState.peerCertificates[0].NotAfter) {
+ continue
+ }
+ if sessionHasClientCerts && c.config.ClientAuth >= VerifyClientCertIfGiven &&
+ len(sessionState.verifiedChains) == 0 {
+ continue
+ }
+
+ if c.quic != nil && c.quic.enableSessionEvents {
+ if err := c.quicResumeSession(sessionState); err != nil {
+ return err
+ }
+ }
+
+ hs.earlySecret = tls13.NewEarlySecret(hs.suite.hash.New, sessionState.secret)
+ binderKey := hs.earlySecret.ResumptionBinderKey()
+ // Clone the transcript in case a HelloRetryRequest was recorded.
+ transcript := cloneHash(hs.transcript, hs.suite.hash)
+ if transcript == nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: internal error: failed to clone hash")
+ }
+ clientHelloBytes, err := hs.clientHello.marshalWithoutBinders()
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ transcript.Write(clientHelloBytes)
+ pskBinder := hs.suite.finishedHash(binderKey, transcript)
+ if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid PSK binder")
+ }
+
+ if c.quic != nil && hs.clientHello.earlyData && i == 0 &&
+ sessionState.EarlyData && sessionState.cipherSuite == hs.suite.id &&
+ sessionState.alpnProtocol == c.clientProtocol {
+ hs.earlyData = true
+
+ transcript := hs.suite.hash.New()
+ if err := transcriptMsg(hs.clientHello, transcript); err != nil {
+ return err
+ }
+ earlyTrafficSecret := hs.earlySecret.ClientEarlyTrafficSecret(transcript)
+ c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret)
+ }
+
+ c.didResume = true
+ c.peerCertificates = sessionState.peerCertificates
+ c.ocspResponse = sessionState.ocspResponse
+ c.scts = sessionState.scts
+ c.verifiedChains = sessionState.verifiedChains
+
+ hs.hello.selectedIdentityPresent = true
+ hs.hello.selectedIdentity = uint16(i)
+ hs.usingPSK = true
+ return nil
+ }
+
+ return nil
+}
+
+// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
+// interfaces implemented by standard library hashes to clone the state of in
+// to a new instance of h. It returns nil if the operation fails.
+func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash {
+ // Recreate the interface to avoid importing encoding.
+ type binaryMarshaler interface {
+ MarshalBinary() (data []byte, err error)
+ UnmarshalBinary(data []byte) error
+ }
+ marshaler, ok := in.(binaryMarshaler)
+ if !ok {
+ return nil
+ }
+ state, err := marshaler.MarshalBinary()
+ if err != nil {
+ return nil
+ }
+ out := h.New()
+ unmarshaler, ok := out.(binaryMarshaler)
+ if !ok {
+ return nil
+ }
+ if err := unmarshaler.UnmarshalBinary(state); err != nil {
+ return nil
+ }
+ return out
+}
+
+func (hs *serverHandshakeStateTLS13) pickCertificate() error {
+ c := hs.c
+
+ // Only one of PSK and certificates are used at a time.
+ if hs.usingPSK {
+ return nil
+ }
+
+ // signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3.
+ if len(hs.clientHello.supportedSignatureAlgorithms) == 0 {
+ return c.sendAlert(alertMissingExtension)
+ }
+
+ certificate, err := c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
+ if err != nil {
+ if err == errNoCertificates {
+ c.sendAlert(alertUnrecognizedName)
+ } else {
+ c.sendAlert(alertInternalError)
+ }
+ return err
+ }
+ hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms)
+ if err != nil {
+ // getCertificate returned a certificate that is unsupported or
+ // incompatible with the client's signature algorithms.
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ hs.cert = certificate
+
+ return nil
+}
+
+// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
+// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
+func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
+ if hs.c.quic != nil {
+ return nil
+ }
+ if hs.sentDummyCCS {
+ return nil
+ }
+ hs.sentDummyCCS = true
+
+ return hs.c.writeChangeCipherRecord()
+}
+
+func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) (*keyShare, error) {
+ c := hs.c
+
+ // The first ClientHello gets double-hashed into the transcript upon a
+ // HelloRetryRequest. See RFC 8446, Section 4.4.1.
+ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
+ return nil, err
+ }
+ chHash := hs.transcript.Sum(nil)
+ hs.transcript.Reset()
+ hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+ hs.transcript.Write(chHash)
+
+ helloRetryRequest := &serverHelloMsg{
+ vers: hs.hello.vers,
+ random: helloRetryRequestRandom,
+ sessionId: hs.hello.sessionId,
+ cipherSuite: hs.hello.cipherSuite,
+ compressionMethod: hs.hello.compressionMethod,
+ supportedVersion: hs.hello.supportedVersion,
+ selectedGroup: selectedGroup,
+ }
+
+ if hs.echContext != nil {
+ // Compute the acceptance message.
+ helloRetryRequest.encryptedClientHello = make([]byte, 8)
+ confTranscript := cloneHash(hs.transcript, hs.suite.hash)
+ if err := transcriptMsg(helloRetryRequest, confTranscript); err != nil {
+ return nil, err
+ }
+ acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New,
+ hkdf.Extract(hs.suite.hash.New, hs.clientHello.random, nil),
+ "hrr ech accept confirmation",
+ confTranscript.Sum(nil),
+ 8,
+ )
+ helloRetryRequest.encryptedClientHello = acceptConfirmation
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil {
+ return nil, err
+ }
+
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return nil, err
+ }
+
+ // clientHelloMsg is not included in the transcript.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return nil, err
+ }
+
+ clientHello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, unexpectedMessageError(clientHello, msg)
+ }
+
+ if hs.echContext != nil {
+ if len(clientHello.encryptedClientHello) == 0 {
+ c.sendAlert(alertMissingExtension)
+ return nil, errors.New("tls: second client hello missing encrypted client hello extension")
+ }
+
+ echType, echCiphersuite, configID, encap, payload, err := parseECHExt(clientHello.encryptedClientHello)
+ if err != nil {
+ c.sendAlert(alertDecodeError)
+ return nil, errors.New("tls: client sent invalid encrypted client hello extension")
+ }
+
+ if echType == outerECHExt && hs.echContext.inner || echType == innerECHExt && !hs.echContext.inner {
+ c.sendAlert(alertDecodeError)
+ return nil, errors.New("tls: unexpected switch in encrypted client hello extension type")
+ }
+
+ if echType == outerECHExt {
+ if echCiphersuite != hs.echContext.ciphersuite || configID != hs.echContext.configID || len(encap) != 0 {
+ c.sendAlert(alertIllegalParameter)
+ return nil, errors.New("tls: second client hello encrypted client hello extension does not match")
+ }
+
+ encodedInner, err := decryptECHPayload(hs.echContext.hpkeContext, clientHello.original, payload)
+ if err != nil {
+ c.sendAlert(alertDecryptError)
+ return nil, errors.New("tls: failed to decrypt second client hello encrypted client hello extension payload")
+ }
+
+ echInner, err := decodeInnerClientHello(clientHello, encodedInner)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return nil, errors.New("tls: client sent invalid encrypted client hello extension")
+ }
+
+ clientHello = echInner
+ }
+ }
+
+ if len(clientHello.keyShares) != 1 {
+ c.sendAlert(alertIllegalParameter)
+ return nil, errors.New("tls: client didn't send one key share in second ClientHello")
+ }
+ ks := &clientHello.keyShares[0]
+
+ if ks.group != selectedGroup {
+ c.sendAlert(alertIllegalParameter)
+ return nil, errors.New("tls: client sent unexpected key share in second ClientHello")
+ }
+
+ if clientHello.earlyData {
+ c.sendAlert(alertIllegalParameter)
+ return nil, errors.New("tls: client indicated early data in second ClientHello")
+ }
+
+ if illegalClientHelloChange(clientHello, hs.clientHello) {
+ c.sendAlert(alertIllegalParameter)
+ return nil, errors.New("tls: client illegally modified second ClientHello")
+ }
+
+ c.didHRR = true
+ hs.clientHello = clientHello
+ return ks, nil
+}
+
+// illegalClientHelloChange reports whether the two ClientHello messages are
+// different, with the exception of the changes allowed before and after a
+// HelloRetryRequest. See RFC 8446, Section 4.1.2.
+func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
+ if len(ch.supportedVersions) != len(ch1.supportedVersions) ||
+ len(ch.cipherSuites) != len(ch1.cipherSuites) ||
+ len(ch.supportedCurves) != len(ch1.supportedCurves) ||
+ len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) ||
+ len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) ||
+ len(ch.alpnProtocols) != len(ch1.alpnProtocols) {
+ return true
+ }
+ for i := range ch.supportedVersions {
+ if ch.supportedVersions[i] != ch1.supportedVersions[i] {
+ return true
+ }
+ }
+ for i := range ch.cipherSuites {
+ if ch.cipherSuites[i] != ch1.cipherSuites[i] {
+ return true
+ }
+ }
+ for i := range ch.supportedCurves {
+ if ch.supportedCurves[i] != ch1.supportedCurves[i] {
+ return true
+ }
+ }
+ for i := range ch.supportedSignatureAlgorithms {
+ if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] {
+ return true
+ }
+ }
+ for i := range ch.supportedSignatureAlgorithmsCert {
+ if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] {
+ return true
+ }
+ }
+ for i := range ch.alpnProtocols {
+ if ch.alpnProtocols[i] != ch1.alpnProtocols[i] {
+ return true
+ }
+ }
+ return ch.vers != ch1.vers ||
+ !bytes.Equal(ch.random, ch1.random) ||
+ !bytes.Equal(ch.sessionId, ch1.sessionId) ||
+ !bytes.Equal(ch.compressionMethods, ch1.compressionMethods) ||
+ ch.serverName != ch1.serverName ||
+ ch.ocspStapling != ch1.ocspStapling ||
+ !bytes.Equal(ch.supportedPoints, ch1.supportedPoints) ||
+ ch.ticketSupported != ch1.ticketSupported ||
+ !bytes.Equal(ch.sessionTicket, ch1.sessionTicket) ||
+ ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported ||
+ !bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) ||
+ ch.scts != ch1.scts ||
+ !bytes.Equal(ch.cookie, ch1.cookie) ||
+ !bytes.Equal(ch.pskModes, ch1.pskModes)
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
+ c := hs.c
+
+ if hs.echContext != nil {
+ copy(hs.hello.random[32-8:], make([]byte, 8))
+ echTranscript := cloneHash(hs.transcript, hs.suite.hash)
+ echTranscript.Write(hs.clientHello.original)
+ if err := transcriptMsg(hs.hello, echTranscript); err != nil {
+ return err
+ }
+ // compute the acceptance message
+ acceptConfirmation := tls13.ExpandLabel(hs.suite.hash.New,
+ hkdf.Extract(hs.suite.hash.New, hs.clientHello.random, nil),
+ "ech accept confirmation",
+ echTranscript.Sum(nil),
+ 8,
+ )
+ copy(hs.hello.random[32-8:], acceptConfirmation)
+ }
+
+ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
+ return err
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
+ return err
+ }
+
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return err
+ }
+
+ earlySecret := hs.earlySecret
+ if earlySecret == nil {
+ earlySecret = tls13.NewEarlySecret(hs.suite.hash.New, nil)
+ }
+ hs.handshakeSecret = earlySecret.HandshakeSecret(hs.sharedKey)
+
+ clientSecret := hs.handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript)
+ c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
+ serverSecret := hs.handshakeSecret.ServerHandshakeTrafficSecret(hs.transcript)
+ c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+
+ if c.quic != nil {
+ if c.hand.Len() != 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ }
+ c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
+ c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
+ }
+
+ err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ encryptedExtensions := new(encryptedExtensionsMsg)
+ encryptedExtensions.alpnProtocol = c.clientProtocol
+
+ if c.quic != nil {
+ p, err := c.quicGetTransportParameters()
+ if err != nil {
+ return err
+ }
+ encryptedExtensions.quicTransportParameters = p
+ encryptedExtensions.earlyData = hs.earlyData
+ }
+
+ // If client sent ECH extension, but we didn't accept it,
+ // send retry configs, if available.
+ if len(hs.c.config.EncryptedClientHelloKeys) > 0 && len(hs.clientHello.encryptedClientHello) > 0 && hs.echContext == nil {
+ encryptedExtensions.echRetryConfigs, err = buildRetryConfigList(hs.c.config.EncryptedClientHelloKeys)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(encryptedExtensions, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) requestClientCert() bool {
+ return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
+ c := hs.c
+
+ // Only one of PSK and certificates are used at a time.
+ if hs.usingPSK {
+ return nil
+ }
+
+ if hs.requestClientCert() {
+ // Request a client certificate
+ certReq := new(certificateRequestMsgTLS13)
+ certReq.ocspStapling = true
+ certReq.scts = true
+ certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ if c.config.ClientCAs != nil {
+ certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil {
+ return err
+ }
+ }
+
+ certMsg := new(certificateMsgTLS13)
+
+ certMsg.certificate = *hs.cert
+ certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0
+ certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0
+
+ if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ certVerifyMsg := new(certificateVerifyMsg)
+ certVerifyMsg.hasSignatureAlgorithm = true
+ certVerifyMsg.signatureAlgorithm = hs.sigAlg
+
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(hs.sigAlg)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+
+ signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
+ if err != nil {
+ public := hs.cert.PrivateKey.(crypto.Signer).Public()
+ if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS &&
+ rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS
+ c.sendAlert(alertHandshakeFailure)
+ } else {
+ c.sendAlert(alertInternalError)
+ }
+ return errors.New("tls: failed to sign handshake: " + err.Error())
+ }
+ certVerifyMsg.signature = sig
+
+ if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
+ c := hs.c
+
+ finished := &finishedMsg{
+ verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
+ return err
+ }
+
+ // Derive secrets that take context through the server Finished.
+
+ hs.masterSecret = hs.handshakeSecret.MasterSecret()
+
+ hs.trafficSecret = hs.masterSecret.ClientApplicationTrafficSecret(hs.transcript)
+ serverSecret := hs.masterSecret.ServerApplicationTrafficSecret(hs.transcript)
+ c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
+
+ if c.quic != nil {
+ if c.hand.Len() != 0 {
+ // TODO: Handle this in setTrafficSecret?
+ c.sendAlert(alertUnexpectedMessage)
+ }
+ c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, serverSecret)
+ }
+
+ err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
+
+ // If we did not request client certificates, at this point we can
+ // precompute the client finished and roll the transcript forward to send
+ // session tickets in our first flight.
+ if !hs.requestClientCert() {
+ if err := hs.sendSessionTickets(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool {
+ if hs.c.config.SessionTicketsDisabled {
+ return false
+ }
+
+ // QUIC tickets are sent by QUICConn.SendSessionTicket, not automatically.
+ if hs.c.quic != nil {
+ return false
+ }
+
+ // Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9.
+ for _, pskMode := range hs.clientHello.pskModes {
+ if pskMode == pskModeDHE {
+ return true
+ }
+ }
+ return false
+}
+
+func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
+ c := hs.c
+
+ hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
+ finishedMsg := &finishedMsg{
+ verifyData: hs.clientFinished,
+ }
+ if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ c.resumptionSecret = hs.masterSecret.ResumptionMasterSecret(hs.transcript)
+
+ if !hs.shouldSendSessionTickets() {
+ return nil
+ }
+ return c.sendSessionTicket(false, nil)
+}
+
+func (c *Conn) sendSessionTicket(earlyData bool, extra [][]byte) error {
+ suite := cipherSuiteTLS13ByID(c.cipherSuite)
+ if suite == nil {
+ return errors.New("tls: internal error: unknown cipher suite")
+ }
+ // ticket_nonce, which must be unique per connection, is always left at
+ // zero because we only ever send one ticket per connection.
+ psk := tls13.ExpandLabel(suite.hash.New, c.resumptionSecret, "resumption",
+ nil, suite.hash.Size())
+
+ m := new(newSessionTicketMsgTLS13)
+
+ state := c.sessionState()
+ state.secret = psk
+ state.EarlyData = earlyData
+ state.Extra = extra
+ if c.config.WrapSession != nil {
+ var err error
+ m.label, err = c.config.WrapSession(c.connectionStateLocked(), state)
+ if err != nil {
+ return err
+ }
+ } else {
+ stateBytes, err := state.Bytes()
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ m.label, err = c.config.encryptTicket(stateBytes, c.ticketKeys)
+ if err != nil {
+ return err
+ }
+ }
+ m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
+
+ // ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
+ // The value is not stored anywhere; we never need to check the ticket age
+ // because 0-RTT is not supported.
+ ageAdd := make([]byte, 4)
+ if _, err := c.config.rand().Read(ageAdd); err != nil {
+ return err
+ }
+ m.ageAdd = byteorder.LEUint32(ageAdd)
+
+ if earlyData {
+ // RFC 9001, Section 4.6.1
+ m.maxEarlyData = 0xffffffff
+ }
+
+ if _, err := c.writeHandshakeRecord(m, nil); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
+ c := hs.c
+
+ if !hs.requestClientCert() {
+ // Make sure the connection is still being verified whether or not
+ // the server requested a client certificate.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+ return nil
+ }
+
+ // If we requested a client certificate, then the client must send a
+ // certificate message. If it's empty, no CertificateVerify is sent.
+
+ msg, err := c.readHandshake(hs.transcript)
+ if err != nil {
+ return err
+ }
+
+ certMsg, ok := msg.(*certificateMsgTLS13)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+
+ if err := c.processCertsFromClient(certMsg.certificate); err != nil {
+ return err
+ }
+
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ if len(certMsg.certificate.Certificate) != 0 {
+ // certificateVerifyMsg is included in the transcript, but not until
+ // after we verify the handshake signature, since the state before
+ // this message was sent is used.
+ msg, err = c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ // See RFC 8446, Section 4.4.3.
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client certificate used with invalid signature algorithm")
+ }
+ signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
+ if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
+ sigHash, signed, certVerify.signature); err != nil {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid signature by the client certificate: " + err.Error())
+ }
+
+ if err := transcriptMsg(certVerify, hs.transcript); err != nil {
+ return err
+ }
+ }
+
+ // If we waited until the client certificates to send session tickets, we
+ // are ready to do it now.
+ if err := hs.sendSessionTickets(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) readClientFinished() error {
+ c := hs.c
+
+ // finishedMsg is not included in the transcript.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ finished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(finished, msg)
+ }
+
+ if !hmac.Equal(hs.clientFinished, finished.verifyData) {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid client finished hash")
+ }
+
+ c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
+
+ return nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/boring/notboring.go b/vendor/github.com/refraction-networking/utls/internal/boring/notboring.go
new file mode 100644
index 00000000..913afd5d
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/boring/notboring.go
@@ -0,0 +1,20 @@
+package boring
+
+import (
+ "crypto/cipher"
+ "errors"
+)
+
+const Enabled bool = false
+
+func NewGCMTLS(_ cipher.Block) (cipher.AEAD, error) {
+ return nil, errors.New("boring not implemented")
+}
+
+func NewGCMTLS13(_ cipher.Block) (cipher.AEAD, error) {
+ return nil, errors.New("boring not implemented")
+}
+
+func Unreachable() {
+ // do nothing
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/byteorder/byteorder.go b/vendor/github.com/refraction-networking/utls/internal/byteorder/byteorder.go
new file mode 100644
index 00000000..01500a87
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/byteorder/byteorder.go
@@ -0,0 +1,149 @@
+// 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.
+
+// Package byteorder provides functions for decoding and encoding
+// little and big endian integer types from/to byte slices.
+package byteorder
+
+func LEUint16(b []byte) uint16 {
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func LEPutUint16(b []byte, v uint16) {
+ _ = b[1] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+}
+
+func LEAppendUint16(b []byte, v uint16) []byte {
+ return append(b,
+ byte(v),
+ byte(v>>8),
+ )
+}
+
+func LEUint32(b []byte) uint32 {
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func LEPutUint32(b []byte, v uint32) {
+ _ = b[3] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+}
+
+func LEAppendUint32(b []byte, v uint32) []byte {
+ return append(b,
+ byte(v),
+ byte(v>>8),
+ byte(v>>16),
+ byte(v>>24),
+ )
+}
+
+func LEUint64(b []byte) uint64 {
+ _ = 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
+}
+
+func LEPutUint64(b []byte, v uint64) {
+ _ = b[7] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+}
+
+func LEAppendUint64(b []byte, v uint64) []byte {
+ return append(b,
+ byte(v),
+ byte(v>>8),
+ byte(v>>16),
+ byte(v>>24),
+ byte(v>>32),
+ byte(v>>40),
+ byte(v>>48),
+ byte(v>>56),
+ )
+}
+
+func BEUint16(b []byte) uint16 {
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint16(b[1]) | uint16(b[0])<<8
+}
+
+func BEPutUint16(b []byte, v uint16) {
+ _ = b[1] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v >> 8)
+ b[1] = byte(v)
+}
+
+func BEAppendUint16(b []byte, v uint16) []byte {
+ return append(b,
+ byte(v>>8),
+ byte(v),
+ )
+}
+
+func BEUint32(b []byte) uint32 {
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func BEPutUint32(b []byte, v uint32) {
+ _ = b[3] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v >> 24)
+ b[1] = byte(v >> 16)
+ b[2] = byte(v >> 8)
+ b[3] = byte(v)
+}
+
+func BEAppendUint32(b []byte, v uint32) []byte {
+ return append(b,
+ byte(v>>24),
+ byte(v>>16),
+ byte(v>>8),
+ byte(v),
+ )
+}
+
+func BEUint64(b []byte) uint64 {
+ _ = 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
+}
+
+func BEPutUint64(b []byte, v uint64) {
+ _ = b[7] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v >> 56)
+ b[1] = byte(v >> 48)
+ b[2] = byte(v >> 40)
+ b[3] = byte(v >> 32)
+ b[4] = byte(v >> 24)
+ b[5] = byte(v >> 16)
+ b[6] = byte(v >> 8)
+ b[7] = byte(v)
+}
+
+func BEAppendUint64(b []byte, v uint64) []byte {
+ return append(b,
+ byte(v>>56),
+ byte(v>>48),
+ byte(v>>40),
+ byte(v>>32),
+ byte(v>>24),
+ byte(v>>16),
+ byte(v>>8),
+ byte(v),
+ )
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/fips140tls/fipstls.go b/vendor/github.com/refraction-networking/utls/internal/fips140tls/fipstls.go
new file mode 100644
index 00000000..df03808d
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/fips140tls/fipstls.go
@@ -0,0 +1,5 @@
+package fips140tls
+
+func Required() bool {
+ return false
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/helper/typeconv.go b/vendor/github.com/refraction-networking/utls/internal/helper/typeconv.go
new file mode 100644
index 00000000..73ec0583
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/helper/typeconv.go
@@ -0,0 +1,23 @@
+package helper
+
+import (
+ "errors"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// Uint8to16 converts a slice of uint8 to a slice of uint16.
+// e.g. []uint8{0x00, 0x01, 0x00, 0x02} -> []uint16{0x0001, 0x0002}
+func Uint8to16(in []uint8) ([]uint16, error) {
+ s := cryptobyte.String(in)
+ var out []uint16
+ for !s.Empty() {
+ var v uint16
+ if s.ReadUint16(&v) {
+ out = append(out, v)
+ } else {
+ return nil, errors.New("ReadUint16 failed")
+ }
+ }
+ return out, nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/hkdf/hkdf.go b/vendor/github.com/refraction-networking/utls/internal/hkdf/hkdf.go
new file mode 100644
index 00000000..184ef7b8
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/hkdf/hkdf.go
@@ -0,0 +1,24 @@
+package hkdf
+
+import (
+ "crypto/hkdf"
+ "hash"
+)
+
+func Extract[H hash.Hash](h func() H, secret, salt []byte) []byte {
+ res, err := hkdf.Extract(h, secret, salt)
+ if err != nil {
+ panic(err)
+ }
+
+ return res
+}
+
+func Expand[H hash.Hash](h func() H, pseudorandomKey []byte, info string, keyLength int) []byte {
+ res, err := hkdf.Expand(h, pseudorandomKey, info, keyLength)
+ if err != nil {
+ panic(err)
+ }
+
+ return res
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/hpke/hpke.go b/vendor/github.com/refraction-networking/utls/internal/hpke/hpke.go
new file mode 100644
index 00000000..68876610
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/hpke/hpke.go
@@ -0,0 +1,333 @@
+// 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.
+
+package hpke
+
+import (
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/ecdh"
+ "crypto/rand"
+ "errors"
+ "math/bits"
+
+ "github.com/refraction-networking/utls/internal/byteorder"
+ "github.com/refraction-networking/utls/internal/hkdf"
+ "golang.org/x/crypto/chacha20poly1305"
+)
+
+// testingOnlyGenerateKey is only used during testing, to provide
+// a fixed test key to use when checking the RFC 9180 vectors.
+var testingOnlyGenerateKey func() (*ecdh.PrivateKey, error)
+
+type hkdfKDF struct {
+ hash crypto.Hash
+}
+
+func (kdf *hkdfKDF) LabeledExtract(sid []byte, salt []byte, label string, inputKey []byte) []byte {
+ labeledIKM := make([]byte, 0, 7+len(sid)+len(label)+len(inputKey))
+ labeledIKM = append(labeledIKM, []byte("HPKE-v1")...)
+ labeledIKM = append(labeledIKM, sid...)
+ labeledIKM = append(labeledIKM, label...)
+ labeledIKM = append(labeledIKM, inputKey...)
+ return hkdf.Extract(kdf.hash.New, labeledIKM, salt)
+}
+
+func (kdf *hkdfKDF) LabeledExpand(suiteID []byte, randomKey []byte, label string, info []byte, length uint16) []byte {
+ labeledInfo := make([]byte, 0, 2+7+len(suiteID)+len(label)+len(info))
+ labeledInfo = byteorder.BEAppendUint16(labeledInfo, length)
+ labeledInfo = append(labeledInfo, []byte("HPKE-v1")...)
+ labeledInfo = append(labeledInfo, suiteID...)
+ labeledInfo = append(labeledInfo, label...)
+ labeledInfo = append(labeledInfo, info...)
+ return hkdf.Expand(kdf.hash.New, randomKey, string(labeledInfo), int(length))
+}
+
+// dhKEM implements the KEM specified in RFC 9180, Section 4.1.
+type dhKEM struct {
+ dh ecdh.Curve
+ kdf hkdfKDF
+
+ suiteID []byte
+ nSecret uint16
+}
+
+type KemID uint16
+
+const DHKEM_X25519_HKDF_SHA256 = 0x0020
+
+var SupportedKEMs = map[uint16]struct {
+ curve ecdh.Curve
+ hash crypto.Hash
+ nSecret uint16
+}{
+ // RFC 9180 Section 7.1
+ DHKEM_X25519_HKDF_SHA256: {ecdh.X25519(), crypto.SHA256, 32},
+}
+
+func newDHKem(kemID uint16) (*dhKEM, error) {
+ suite, ok := SupportedKEMs[kemID]
+ if !ok {
+ return nil, errors.New("unsupported suite ID")
+ }
+ return &dhKEM{
+ dh: suite.curve,
+ kdf: hkdfKDF{suite.hash},
+ suiteID: byteorder.BEAppendUint16([]byte("KEM"), kemID),
+ nSecret: suite.nSecret,
+ }, nil
+}
+
+func (dh *dhKEM) ExtractAndExpand(dhKey, kemContext []byte) []byte {
+ eaePRK := dh.kdf.LabeledExtract(dh.suiteID[:], nil, "eae_prk", dhKey)
+ return dh.kdf.LabeledExpand(dh.suiteID[:], eaePRK, "shared_secret", kemContext, dh.nSecret)
+}
+
+func (dh *dhKEM) Encap(pubRecipient *ecdh.PublicKey) (sharedSecret []byte, encapPub []byte, err error) {
+ var privEph *ecdh.PrivateKey
+ if testingOnlyGenerateKey != nil {
+ privEph, err = testingOnlyGenerateKey()
+ } else {
+ privEph, err = dh.dh.GenerateKey(rand.Reader)
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+ dhVal, err := privEph.ECDH(pubRecipient)
+ if err != nil {
+ return nil, nil, err
+ }
+ encPubEph := privEph.PublicKey().Bytes()
+
+ encPubRecip := pubRecipient.Bytes()
+ kemContext := append(encPubEph, encPubRecip...)
+
+ return dh.ExtractAndExpand(dhVal, kemContext), encPubEph, nil
+}
+
+func (dh *dhKEM) Decap(encPubEph []byte, secRecipient *ecdh.PrivateKey) ([]byte, error) {
+ pubEph, err := dh.dh.NewPublicKey(encPubEph)
+ if err != nil {
+ return nil, err
+ }
+ dhVal, err := secRecipient.ECDH(pubEph)
+ if err != nil {
+ return nil, err
+ }
+ kemContext := append(encPubEph, secRecipient.PublicKey().Bytes()...)
+
+ return dh.ExtractAndExpand(dhVal, kemContext), nil
+}
+
+type context struct {
+ aead cipher.AEAD
+
+ sharedSecret []byte
+
+ suiteID []byte
+
+ key []byte
+ baseNonce []byte
+ exporterSecret []byte
+
+ seqNum uint128
+}
+
+type Sender struct {
+ *context
+}
+
+type Receipient struct {
+ *context
+}
+
+var aesGCMNew = func(key []byte) (cipher.AEAD, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ return cipher.NewGCM(block)
+}
+
+type AEADID uint16
+
+const (
+ AEAD_AES_128_GCM = 0x0001
+ AEAD_AES_256_GCM = 0x0002
+ AEAD_ChaCha20Poly1305 = 0x0003
+)
+
+var SupportedAEADs = map[uint16]struct {
+ keySize int
+ nonceSize int
+ aead func([]byte) (cipher.AEAD, error)
+}{
+ // RFC 9180, Section 7.3
+ AEAD_AES_128_GCM: {keySize: 16, nonceSize: 12, aead: aesGCMNew},
+ AEAD_AES_256_GCM: {keySize: 32, nonceSize: 12, aead: aesGCMNew},
+ AEAD_ChaCha20Poly1305: {keySize: chacha20poly1305.KeySize, nonceSize: chacha20poly1305.NonceSize, aead: chacha20poly1305.New},
+}
+
+type KDFID uint16
+
+const KDF_HKDF_SHA256 = 0x0001
+
+var SupportedKDFs = map[uint16]func() *hkdfKDF{
+ // RFC 9180, Section 7.2
+ KDF_HKDF_SHA256: func() *hkdfKDF { return &hkdfKDF{crypto.SHA256} },
+}
+
+func newContext(sharedSecret []byte, kemID, kdfID, aeadID uint16, info []byte) (*context, error) {
+ sid := suiteID(kemID, kdfID, aeadID)
+
+ kdfInit, ok := SupportedKDFs[kdfID]
+ if !ok {
+ return nil, errors.New("unsupported KDF id")
+ }
+ kdf := kdfInit()
+
+ aeadInfo, ok := SupportedAEADs[aeadID]
+ if !ok {
+ return nil, errors.New("unsupported AEAD id")
+ }
+
+ pskIDHash := kdf.LabeledExtract(sid, nil, "psk_id_hash", nil)
+ infoHash := kdf.LabeledExtract(sid, nil, "info_hash", info)
+ ksContext := append([]byte{0}, pskIDHash...)
+ ksContext = append(ksContext, infoHash...)
+
+ secret := kdf.LabeledExtract(sid, sharedSecret, "secret", nil)
+
+ key := kdf.LabeledExpand(sid, secret, "key", ksContext, uint16(aeadInfo.keySize) /* Nk - key size for AEAD */)
+ baseNonce := kdf.LabeledExpand(sid, secret, "base_nonce", ksContext, uint16(aeadInfo.nonceSize) /* Nn - nonce size for AEAD */)
+ exporterSecret := kdf.LabeledExpand(sid, secret, "exp", ksContext, uint16(kdf.hash.Size()) /* Nh - hash output size of the kdf*/)
+
+ aead, err := aeadInfo.aead(key)
+ if err != nil {
+ return nil, err
+ }
+
+ return &context{
+ aead: aead,
+ sharedSecret: sharedSecret,
+ suiteID: sid,
+ key: key,
+ baseNonce: baseNonce,
+ exporterSecret: exporterSecret,
+ }, nil
+}
+
+func SetupSender(kemID, kdfID, aeadID uint16, pub *ecdh.PublicKey, info []byte) ([]byte, *Sender, error) {
+ kem, err := newDHKem(kemID)
+ if err != nil {
+ return nil, nil, err
+ }
+ sharedSecret, encapsulatedKey, err := kem.Encap(pub)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ context, err := newContext(sharedSecret, kemID, kdfID, aeadID, info)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return encapsulatedKey, &Sender{context}, nil
+}
+
+func SetupReceipient(kemID, kdfID, aeadID uint16, priv *ecdh.PrivateKey, info, encPubEph []byte) (*Receipient, error) {
+ kem, err := newDHKem(kemID)
+ if err != nil {
+ return nil, err
+ }
+ sharedSecret, err := kem.Decap(encPubEph, priv)
+ if err != nil {
+ return nil, err
+ }
+
+ context, err := newContext(sharedSecret, kemID, kdfID, aeadID, info)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Receipient{context}, nil
+}
+
+func (ctx *context) nextNonce() []byte {
+ nonce := ctx.seqNum.bytes()[16-ctx.aead.NonceSize():]
+ for i := range ctx.baseNonce {
+ nonce[i] ^= ctx.baseNonce[i]
+ }
+ return nonce
+}
+
+func (ctx *context) incrementNonce() {
+ // Message limit is, according to the RFC, 2^95+1, which
+ // is somewhat confusing, but we do as we're told.
+ if ctx.seqNum.bitLen() >= (ctx.aead.NonceSize()*8)-1 {
+ panic("message limit reached")
+ }
+ ctx.seqNum = ctx.seqNum.addOne()
+}
+
+func (s *Sender) Seal(aad, plaintext []byte) ([]byte, error) {
+ ciphertext := s.aead.Seal(nil, s.nextNonce(), plaintext, aad)
+ s.incrementNonce()
+ return ciphertext, nil
+}
+
+func (r *Receipient) Open(aad, ciphertext []byte) ([]byte, error) {
+ plaintext, err := r.aead.Open(nil, r.nextNonce(), ciphertext, aad)
+ if err != nil {
+ return nil, err
+ }
+ r.incrementNonce()
+ return plaintext, nil
+}
+
+func suiteID(kemID, kdfID, aeadID uint16) []byte {
+ suiteID := make([]byte, 0, 4+2+2+2)
+ suiteID = append(suiteID, []byte("HPKE")...)
+ suiteID = byteorder.BEAppendUint16(suiteID, kemID)
+ suiteID = byteorder.BEAppendUint16(suiteID, kdfID)
+ suiteID = byteorder.BEAppendUint16(suiteID, aeadID)
+ return suiteID
+}
+
+func ParseHPKEPublicKey(kemID uint16, bytes []byte) (*ecdh.PublicKey, error) {
+ kemInfo, ok := SupportedKEMs[kemID]
+ if !ok {
+ return nil, errors.New("unsupported KEM id")
+ }
+ return kemInfo.curve.NewPublicKey(bytes)
+}
+
+func ParseHPKEPrivateKey(kemID uint16, bytes []byte) (*ecdh.PrivateKey, error) {
+ kemInfo, ok := SupportedKEMs[kemID]
+ if !ok {
+ return nil, errors.New("unsupported KEM id")
+ }
+ return kemInfo.curve.NewPrivateKey(bytes)
+}
+
+type uint128 struct {
+ hi, lo uint64
+}
+
+func (u uint128) addOne() uint128 {
+ lo, carry := bits.Add64(u.lo, 1, 0)
+ return uint128{u.hi + carry, lo}
+}
+
+func (u uint128) bitLen() int {
+ return bits.Len64(u.hi) + bits.Len64(u.lo)
+}
+
+func (u uint128) bytes() []byte {
+ b := make([]byte, 16)
+ byteorder.BEPutUint64(b[0:], u.hi)
+ byteorder.BEPutUint64(b[8:], u.lo)
+ return b
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/quicvarint/protocol/protocol.go b/vendor/github.com/refraction-networking/utls/internal/quicvarint/protocol/protocol.go
new file mode 100644
index 00000000..3cbc3423
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/quicvarint/protocol/protocol.go
@@ -0,0 +1,157 @@
+// Copyright 2024 The quic-go Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file of
+// the quic-go repository.
+
+package protocol
+
+import (
+ "fmt"
+ "time"
+)
+
+// The PacketType is the Long Header Type
+type PacketType uint8
+
+const (
+ // PacketTypeInitial is the packet type of an Initial packet
+ PacketTypeInitial PacketType = 1 + iota
+ // PacketTypeRetry is the packet type of a Retry packet
+ PacketTypeRetry
+ // PacketTypeHandshake is the packet type of a Handshake packet
+ PacketTypeHandshake
+ // PacketType0RTT is the packet type of a 0-RTT packet
+ PacketType0RTT
+)
+
+func (t PacketType) String() string {
+ switch t {
+ case PacketTypeInitial:
+ return "Initial"
+ case PacketTypeRetry:
+ return "Retry"
+ case PacketTypeHandshake:
+ return "Handshake"
+ case PacketType0RTT:
+ return "0-RTT Protected"
+ default:
+ return fmt.Sprintf("unknown packet type: %d", t)
+ }
+}
+
+type ECN uint8
+
+const (
+ ECNUnsupported ECN = iota
+ ECNNon // 00
+ ECT1 // 01
+ ECT0 // 10
+ ECNCE // 11
+)
+
+func ParseECNHeaderBits(bits byte) ECN {
+ switch bits {
+ case 0:
+ return ECNNon
+ case 0b00000010:
+ return ECT0
+ case 0b00000001:
+ return ECT1
+ case 0b00000011:
+ return ECNCE
+ default:
+ panic("invalid ECN bits")
+ }
+}
+
+func (e ECN) ToHeaderBits() byte {
+ //nolint:exhaustive // There are only 4 values.
+ switch e {
+ case ECNNon:
+ return 0
+ case ECT0:
+ return 0b00000010
+ case ECT1:
+ return 0b00000001
+ case ECNCE:
+ return 0b00000011
+ default:
+ panic("ECN unsupported")
+ }
+}
+
+func (e ECN) String() string {
+ switch e {
+ case ECNUnsupported:
+ return "ECN unsupported"
+ case ECNNon:
+ return "Not-ECT"
+ case ECT1:
+ return "ECT(1)"
+ case ECT0:
+ return "ECT(0)"
+ case ECNCE:
+ return "CE"
+ default:
+ return fmt.Sprintf("invalid ECN value: %d", e)
+ }
+}
+
+// A ByteCount in QUIC
+type ByteCount int64
+
+// MaxByteCount is the maximum value of a ByteCount
+const MaxByteCount = ByteCount(1<<62 - 1)
+
+// InvalidByteCount is an invalid byte count
+const InvalidByteCount ByteCount = -1
+
+// A StatelessResetToken is a stateless reset token.
+type StatelessResetToken [16]byte
+
+// MaxPacketBufferSize maximum packet size of any QUIC packet, based on
+// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
+// UDP adds an additional 8 bytes. This is a total overhead of 48 bytes.
+// Ethernet's max packet size is 1500 bytes, 1500 - 48 = 1452.
+const MaxPacketBufferSize = 1452
+
+// MaxLargePacketBufferSize is used when using GSO
+const MaxLargePacketBufferSize = 20 * 1024
+
+// MinInitialPacketSize is the minimum size an Initial packet is required to have.
+const MinInitialPacketSize = 1200
+
+// MinUnknownVersionPacketSize is the minimum size a packet with an unknown version
+// needs to have in order to trigger a Version Negotiation packet.
+const MinUnknownVersionPacketSize = MinInitialPacketSize
+
+// MinStatelessResetSize is the minimum size of a stateless reset packet that we send
+const MinStatelessResetSize = 1 /* first byte */ + 20 /* max. conn ID length */ + 4 /* max. packet number length */ + 1 /* min. payload length */ + 16 /* token */
+
+// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet.
+const MinConnectionIDLenInitial = 8
+
+// DefaultAckDelayExponent is the default ack delay exponent
+const DefaultAckDelayExponent = 3
+
+// DefaultActiveConnectionIDLimit is the default active connection ID limit
+const DefaultActiveConnectionIDLimit = 2
+
+// MaxAckDelayExponent is the maximum ack delay exponent
+const MaxAckDelayExponent = 20
+
+// DefaultMaxAckDelay is the default max_ack_delay
+const DefaultMaxAckDelay = 25 * time.Millisecond
+
+// MaxMaxAckDelay is the maximum max_ack_delay
+const MaxMaxAckDelay = (1<<14 - 1) * time.Millisecond
+
+// MaxConnIDLen is the maximum length of the connection ID
+const MaxConnIDLen = 20
+
+// InvalidPacketLimitAES is the maximum number of packets that we can fail to decrypt when using
+// AEAD_AES_128_GCM or AEAD_AES_265_GCM.
+const InvalidPacketLimitAES = 1 << 52
+
+// InvalidPacketLimitChaCha is the maximum number of packets that we can fail to decrypt when using AEAD_CHACHA20_POLY1305.
+const InvalidPacketLimitChaCha = 1 << 36
diff --git a/vendor/github.com/refraction-networking/utls/internal/quicvarint/varint.go b/vendor/github.com/refraction-networking/utls/internal/quicvarint/varint.go
new file mode 100644
index 00000000..e4a1063d
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/quicvarint/varint.go
@@ -0,0 +1,146 @@
+// Copyright 2024 The quic-go Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file of
+// the quic-go repository.
+
+package quicvarint
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/refraction-networking/utls/internal/quicvarint/protocol"
+)
+
+// taken from the QUIC draft
+const (
+ // Min is the minimum value allowed for a QUIC varint.
+ Min = 0
+
+ // Max is the maximum allowed value for a QUIC varint (2^62-1).
+ Max = maxVarInt8
+
+ maxVarInt1 = 63
+ maxVarInt2 = 16383
+ maxVarInt4 = 1073741823
+ maxVarInt8 = 4611686018427387903
+)
+
+// Read reads a number in the QUIC varint format from r.
+func Read(r io.ByteReader) (uint64, error) {
+ firstByte, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ // the first two bits of the first byte encode the length
+ len := 1 << ((firstByte & 0xc0) >> 6)
+ b1 := firstByte & (0xff - 0xc0)
+ if len == 1 {
+ return uint64(b1), nil
+ }
+ b2, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if len == 2 {
+ return uint64(b2) + uint64(b1)<<8, nil
+ }
+ b3, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b4, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if len == 4 {
+ return uint64(b4) + uint64(b3)<<8 + uint64(b2)<<16 + uint64(b1)<<24, nil
+ }
+ b5, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b6, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b7, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ b8, err := r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil
+}
+
+// Append appends i in the QUIC varint format.
+func Append(b []byte, i uint64) []byte {
+ if i <= maxVarInt1 {
+ return append(b, uint8(i))
+ }
+ if i <= maxVarInt2 {
+ return append(b, []byte{uint8(i>>8) | 0x40, uint8(i)}...)
+ }
+ if i <= maxVarInt4 {
+ return append(b, []byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)}...)
+ }
+ if i <= maxVarInt8 {
+ return append(b, []byte{
+ uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32),
+ uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i),
+ }...)
+ }
+ panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
+}
+
+// AppendWithLen append i in the QUIC varint format with the desired length.
+func AppendWithLen(b []byte, i uint64, length protocol.ByteCount) []byte {
+ if length != 1 && length != 2 && length != 4 && length != 8 {
+ panic("invalid varint length")
+ }
+ l := Len(i)
+ if l == length {
+ return Append(b, i)
+ }
+ if l > length {
+ panic(fmt.Sprintf("cannot encode %d in %d bytes", i, length))
+ }
+ if length == 2 {
+ b = append(b, 0b01000000)
+ } else if length == 4 {
+ b = append(b, 0b10000000)
+ } else if length == 8 {
+ b = append(b, 0b11000000)
+ }
+ for j := protocol.ByteCount(1); j < length-l; j++ {
+ b = append(b, 0)
+ }
+ for j := protocol.ByteCount(0); j < l; j++ {
+ b = append(b, uint8(i>>(8*(l-1-j))))
+ }
+ return b
+}
+
+// Len determines the number of bytes that will be needed to write the number i.
+func Len(i uint64) protocol.ByteCount {
+ if i <= maxVarInt1 {
+ return 1
+ }
+ if i <= maxVarInt2 {
+ return 2
+ }
+ if i <= maxVarInt4 {
+ return 4
+ }
+ if i <= maxVarInt8 {
+ return 8
+ }
+ // Don't use a fmt.Sprintf here to format the error message.
+ // The function would then exceed the inlining budget.
+ panic(struct {
+ message string
+ num uint64
+ }{"value doesn't fit into 62 bits: ", i})
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/tls12/tls12.go b/vendor/github.com/refraction-networking/utls/internal/tls12/tls12.go
new file mode 100644
index 00000000..b456ed11
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/tls12/tls12.go
@@ -0,0 +1,69 @@
+// 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.
+
+package tls12
+
+import (
+ "crypto/hmac"
+ "hash"
+)
+
+// PRF implements the TLS 1.2 pseudo-random function, as defined in RFC 5246,
+// Section 5 and allowed by SP 800-135, Revision 1, Section 4.2.2.
+func PRF(hash func() hash.Hash, secret []byte, label string, seed []byte, keyLen int) []byte {
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ result := make([]byte, keyLen)
+ pHash(hash, result, secret, labelAndSeed)
+ return result
+}
+
+// pHash implements the P_hash function, as defined in RFC 5246, Section 5.
+func pHash(hash func() hash.Hash, result, secret, seed []byte) {
+ h := hmac.New(hash, secret)
+ h.Write(seed)
+ a := h.Sum(nil)
+
+ for len(result) > 0 {
+ h.Reset()
+ h.Write(a)
+ h.Write(seed)
+ b := h.Sum(nil)
+ n := copy(result, b)
+ result = result[n:]
+
+ h.Reset()
+ h.Write(a)
+ a = h.Sum(nil)
+ }
+}
+
+const masterSecretLength = 48
+const extendedMasterSecretLabel = "extended master secret"
+
+// MasterSecret implements the TLS 1.2 extended master secret derivation, as
+// defined in RFC 7627 and allowed by SP 800-135, Revision 1, Section 4.2.2.
+func MasterSecret(hash func() hash.Hash, preMasterSecret, transcript []byte) []byte {
+ // [uTLS SECTION BEGIN]
+ // "The TLS 1.2 KDF is an approved KDF when the following conditions are
+ // satisfied: [...] (3) P_HASH uses either SHA-256, SHA-384 or SHA-512."
+ // h := hash()
+ // switch any(h).(type) {
+ // case *sha256.Digest:
+ // if h.Size() != 32 {
+ // fips140.RecordNonApproved()
+ // }
+ // case *sha512.Digest:
+ // if h.Size() != 46 && h.Size() != 64 {
+ // fips140.RecordNonApproved()
+ // }
+ // default:
+ // fips140.RecordNonApproved()
+ // }
+ // [uTLS SECTION END]
+
+ return PRF(hash, preMasterSecret, extendedMasterSecretLabel, transcript, masterSecretLength)
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/tls13/tls13.go b/vendor/github.com/refraction-networking/utls/internal/tls13/tls13.go
new file mode 100644
index 00000000..6bd5d4df
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/tls13/tls13.go
@@ -0,0 +1,179 @@
+// 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.
+
+// Package tls13 implements the TLS 1.3 Key Schedule as specified in RFC 8446,
+// Section 7.1 and allowed by FIPS 140-3 IG 2.4.B Resolution 7.
+package tls13
+
+import (
+ fips140 "hash"
+
+ "github.com/refraction-networking/utls/internal/byteorder"
+ "github.com/refraction-networking/utls/internal/hkdf"
+)
+
+// We don't set the service indicator in this package but we delegate that to
+// the underlying functions because the TLS 1.3 KDF does not have a standard of
+// its own.
+
+// ExpandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
+func ExpandLabel[H fips140.Hash](hash func() H, secret []byte, label string, context []byte, length int) []byte {
+ if len("tls13 ")+len(label) > 255 || len(context) > 255 {
+ // It should be impossible for this to panic: labels are fixed strings,
+ // and context is either a fixed-length computed hash, or parsed from a
+ // field which has the same length limitation.
+ //
+ // Another reasonable approach might be to return a randomized slice if
+ // we encounter an error, which would break the connection, but avoid
+ // panicking. This would perhaps be safer but significantly more
+ // confusing to users.
+ panic("tls13: label or context too long")
+ }
+ hkdfLabel := make([]byte, 0, 2+1+len("tls13 ")+len(label)+1+len(context))
+ hkdfLabel = byteorder.BEAppendUint16(hkdfLabel, uint16(length))
+ hkdfLabel = append(hkdfLabel, byte(len("tls13 ")+len(label)))
+ hkdfLabel = append(hkdfLabel, "tls13 "...)
+ hkdfLabel = append(hkdfLabel, label...)
+ hkdfLabel = append(hkdfLabel, byte(len(context)))
+ hkdfLabel = append(hkdfLabel, context...)
+ return hkdf.Expand(hash, secret, string(hkdfLabel), length)
+}
+
+func extract[H fips140.Hash](hash func() H, newSecret, currentSecret []byte) []byte {
+ if newSecret == nil {
+ newSecret = make([]byte, hash().Size())
+ }
+ return hkdf.Extract(hash, newSecret, currentSecret)
+}
+
+func deriveSecret[H fips140.Hash](hash func() H, secret []byte, label string, transcript fips140.Hash) []byte {
+ if transcript == nil {
+ transcript = hash()
+ }
+ return ExpandLabel(hash, secret, label, transcript.Sum(nil), transcript.Size())
+}
+
+const (
+ resumptionBinderLabel = "res binder"
+ clientEarlyTrafficLabel = "c e traffic"
+ clientHandshakeTrafficLabel = "c hs traffic"
+ serverHandshakeTrafficLabel = "s hs traffic"
+ clientApplicationTrafficLabel = "c ap traffic"
+ serverApplicationTrafficLabel = "s ap traffic"
+ earlyExporterLabel = "e exp master"
+ exporterLabel = "exp master"
+ resumptionLabel = "res master"
+)
+
+type EarlySecret struct {
+ secret []byte
+ hash func() fips140.Hash
+}
+
+func NewEarlySecret[H fips140.Hash](hash func() H, psk []byte) *EarlySecret {
+ return &EarlySecret{
+ secret: extract(hash, psk, nil),
+ hash: func() fips140.Hash { return hash() },
+ }
+}
+
+func (s *EarlySecret) ResumptionBinderKey() []byte {
+ return deriveSecret(s.hash, s.secret, resumptionBinderLabel, nil)
+}
+
+// ClientEarlyTrafficSecret derives the client_early_traffic_secret from the
+// early secret and the transcript up to the ClientHello.
+func (s *EarlySecret) ClientEarlyTrafficSecret(transcript fips140.Hash) []byte {
+ return deriveSecret(s.hash, s.secret, clientEarlyTrafficLabel, transcript)
+}
+
+type HandshakeSecret struct {
+ secret []byte
+ hash func() fips140.Hash
+}
+
+func (s *EarlySecret) HandshakeSecret(sharedSecret []byte) *HandshakeSecret {
+ derived := deriveSecret(s.hash, s.secret, "derived", nil)
+ return &HandshakeSecret{
+ secret: extract(s.hash, sharedSecret, derived),
+ hash: s.hash,
+ }
+}
+
+// ClientHandshakeTrafficSecret derives the client_handshake_traffic_secret from
+// the handshake secret and the transcript up to the ServerHello.
+func (s *HandshakeSecret) ClientHandshakeTrafficSecret(transcript fips140.Hash) []byte {
+ return deriveSecret(s.hash, s.secret, clientHandshakeTrafficLabel, transcript)
+}
+
+// ServerHandshakeTrafficSecret derives the server_handshake_traffic_secret from
+// the handshake secret and the transcript up to the ServerHello.
+func (s *HandshakeSecret) ServerHandshakeTrafficSecret(transcript fips140.Hash) []byte {
+ return deriveSecret(s.hash, s.secret, serverHandshakeTrafficLabel, transcript)
+}
+
+type MasterSecret struct {
+ secret []byte
+ hash func() fips140.Hash
+}
+
+func (s *HandshakeSecret) MasterSecret() *MasterSecret {
+ derived := deriveSecret(s.hash, s.secret, "derived", nil)
+ return &MasterSecret{
+ secret: extract(s.hash, nil, derived),
+ hash: s.hash,
+ }
+}
+
+// ClientApplicationTrafficSecret derives the client_application_traffic_secret_0
+// from the master secret and the transcript up to the server Finished.
+func (s *MasterSecret) ClientApplicationTrafficSecret(transcript fips140.Hash) []byte {
+ return deriveSecret(s.hash, s.secret, clientApplicationTrafficLabel, transcript)
+}
+
+// ServerApplicationTrafficSecret derives the server_application_traffic_secret_0
+// from the master secret and the transcript up to the server Finished.
+func (s *MasterSecret) ServerApplicationTrafficSecret(transcript fips140.Hash) []byte {
+ return deriveSecret(s.hash, s.secret, serverApplicationTrafficLabel, transcript)
+}
+
+// ResumptionMasterSecret derives the resumption_master_secret from the master secret
+// and the transcript up to the client Finished.
+func (s *MasterSecret) ResumptionMasterSecret(transcript fips140.Hash) []byte {
+ return deriveSecret(s.hash, s.secret, resumptionLabel, transcript)
+}
+
+type ExporterMasterSecret struct {
+ secret []byte
+ hash func() fips140.Hash
+}
+
+// ExporterMasterSecret derives the exporter_master_secret from the master secret
+// and the transcript up to the server Finished.
+func (s *MasterSecret) ExporterMasterSecret(transcript fips140.Hash) *ExporterMasterSecret {
+ return &ExporterMasterSecret{
+ secret: deriveSecret(s.hash, s.secret, exporterLabel, transcript),
+ hash: s.hash,
+ }
+}
+
+// EarlyExporterMasterSecret derives the exporter_master_secret from the early secret
+// and the transcript up to the ClientHello.
+func (s *EarlySecret) EarlyExporterMasterSecret(transcript fips140.Hash) *ExporterMasterSecret {
+ return &ExporterMasterSecret{
+ secret: deriveSecret(s.hash, s.secret, earlyExporterLabel, transcript),
+ hash: s.hash,
+ }
+}
+
+func (s *ExporterMasterSecret) Exporter(label string, context []byte, length int) []byte {
+ secret := deriveSecret(s.hash, s.secret, label, nil)
+ h := s.hash()
+ h.Write(context)
+ return ExpandLabel(s.hash, secret, "exporter", h.Sum(nil), length)
+}
+
+func TestingOnlyExporterSecret(s *ExporterMasterSecret) []byte {
+ return s.secret
+}
diff --git a/vendor/github.com/refraction-networking/utls/internal/tls13/u_tls13.go b/vendor/github.com/refraction-networking/utls/internal/tls13/u_tls13.go
new file mode 100644
index 00000000..9e5a6827
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/internal/tls13/u_tls13.go
@@ -0,0 +1,31 @@
+package tls13
+
+import fips140 "hash"
+
+func NewEarlySecretFromSecret[H fips140.Hash](hash func() H, secret []byte) *EarlySecret {
+ return &EarlySecret{
+ secret: secret,
+ hash: func() fips140.Hash { return hash() },
+ }
+}
+
+func (s *EarlySecret) Secret() []byte {
+ if s != nil {
+ return s.secret
+ }
+ return nil
+}
+
+func NewMasterSecretFromSecret[H fips140.Hash](hash func() H, secret []byte) *MasterSecret {
+ return &MasterSecret{
+ secret: secret,
+ hash: func() fips140.Hash { return hash() },
+ }
+}
+
+func (s *MasterSecret) Secret() []byte {
+ if s != nil {
+ return s.secret
+ }
+ return nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/key_agreement.go b/vendor/github.com/refraction-networking/utls/key_agreement.go
new file mode 100644
index 00000000..3e96242b
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/key_agreement.go
@@ -0,0 +1,366 @@
+// 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 tls
+
+import (
+ "crypto"
+ "crypto/ecdh"
+ "crypto/md5"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+)
+
+// A keyAgreement implements the client and server side of a TLS 1.0–1.2 key
+// agreement protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+ // On the server side, the first two methods are called in order.
+
+ // In the case that the key agreement protocol doesn't use a
+ // ServerKeyExchange message, generateServerKeyExchange can return nil,
+ // nil.
+ generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
+ processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
+
+ // On the client side, the next two methods are called in order.
+
+ // This method may not be called if the server doesn't send a
+ // ServerKeyExchange message.
+ processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+ generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
+}
+
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct{}
+
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ return nil, nil
+}
+
+func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) < 2 {
+ return nil, errClientKeyExchange
+ }
+ ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+ if ciphertextLen != len(ckx.ciphertext)-2 {
+ return nil, errClientKeyExchange
+ }
+ ciphertext := ckx.ciphertext[2:]
+
+ priv, ok := cert.PrivateKey.(crypto.Decrypter)
+ if !ok {
+ return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
+ }
+ // Perform constant time RSA PKCS #1 v1.5 decryption
+ preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
+ if err != nil {
+ return nil, err
+ }
+ // We don't check the version number in the premaster secret. For one,
+ // by checking it, we would leak information about the validity of the
+ // encrypted pre-master secret. Secondly, it provides only a small
+ // benefit against a downgrade attack and some implementations send the
+ // wrong version anyway. See the discussion at the end of section
+ // 7.4.7.1 of RFC 4346.
+ return preMasterSecret, nil
+}
+
+func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ return errors.New("tls: unexpected ServerKeyExchange")
+}
+
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ preMasterSecret := make([]byte, 48)
+ preMasterSecret[0] = byte(clientHello.vers >> 8)
+ preMasterSecret[1] = byte(clientHello.vers)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
+ }
+ encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
+ if err != nil {
+ return nil, nil, err
+ }
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, len(encrypted)+2)
+ ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+ ckx.ciphertext[1] = byte(len(encrypted))
+ copy(ckx.ciphertext[2:], encrypted)
+ return preMasterSecret, ckx, nil
+}
+
+// sha1Hash calculates a SHA1 hash over the given byte slices.
+func sha1Hash(slices [][]byte) []byte {
+ hsha1 := sha1.New()
+ for _, slice := range slices {
+ hsha1.Write(slice)
+ }
+ return hsha1.Sum(nil)
+}
+
+// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
+// concatenation of an MD5 and SHA1 hash.
+func md5SHA1Hash(slices [][]byte) []byte {
+ md5sha1 := make([]byte, md5.Size+sha1.Size)
+ hmd5 := md5.New()
+ for _, slice := range slices {
+ hmd5.Write(slice)
+ }
+ copy(md5sha1, hmd5.Sum(nil))
+ copy(md5sha1[md5.Size:], sha1Hash(slices))
+ return md5sha1
+}
+
+// hashForServerKeyExchange hashes the given slices and returns their digest
+// using the given hash function (for TLS 1.2) or using a default based on
+// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't
+// do pre-hashing, it returns the concatenation of the slices.
+func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte {
+ if sigType == signatureEd25519 {
+ var signed []byte
+ for _, slice := range slices {
+ signed = append(signed, slice...)
+ }
+ return signed
+ }
+ if version >= VersionTLS12 {
+ h := hashFunc.New()
+ for _, slice := range slices {
+ h.Write(slice)
+ }
+ digest := h.Sum(nil)
+ return digest
+ }
+ if sigType == signatureECDSA {
+ return sha1Hash(slices)
+ }
+ return md5SHA1Hash(slices)
+}
+
+// ecdheKeyAgreement implements a TLS key agreement where the server
+// generates an ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH. The signature may
+// be ECDSA, Ed25519 or RSA.
+type ecdheKeyAgreement struct {
+ version uint16
+ isRSA bool
+ key *ecdh.PrivateKey
+
+ // ckx and preMasterSecret are generated in processServerKeyExchange
+ // and returned in generateClientKeyExchange.
+ ckx *clientKeyExchangeMsg
+ preMasterSecret []byte
+}
+
+func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ var curveID CurveID
+ for _, c := range clientHello.supportedCurves {
+ if config.supportsCurve(ka.version, c) {
+ curveID = c
+ break
+ }
+ }
+
+ if curveID == 0 {
+ return nil, errors.New("tls: no supported elliptic curves offered")
+ }
+ if _, ok := curveForCurveID(curveID); !ok {
+ return nil, errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+
+ key, err := generateECDHEKey(config.rand(), curveID)
+ if err != nil {
+ return nil, err
+ }
+ ka.key = key
+
+ // See RFC 4492, Section 5.4.
+ ecdhePublic := key.PublicKey().Bytes()
+ serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
+ serverECDHEParams[0] = 3 // named curve
+ serverECDHEParams[1] = byte(curveID >> 8)
+ serverECDHEParams[2] = byte(curveID)
+ serverECDHEParams[3] = byte(len(ecdhePublic))
+ copy(serverECDHEParams[4:], ecdhePublic)
+
+ priv, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey)
+ }
+
+ var signatureAlgorithm SignatureScheme
+ var sigType uint8
+ var sigHash crypto.Hash
+ if ka.version >= VersionTLS12 {
+ signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms)
+ if err != nil {
+ return nil, err
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public())
+ if err != nil {
+ return nil, err
+ }
+ }
+ if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+ return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
+ }
+
+ signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams)
+
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ sig, err := priv.Sign(config.rand(), signed, signOpts)
+ if err != nil {
+ return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
+ }
+
+ skx := new(serverKeyExchangeMsg)
+ sigAndHashLen := 0
+ if ka.version >= VersionTLS12 {
+ sigAndHashLen = 2
+ }
+ skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig))
+ copy(skx.key, serverECDHEParams)
+ k := skx.key[len(serverECDHEParams):]
+ if ka.version >= VersionTLS12 {
+ k[0] = byte(signatureAlgorithm >> 8)
+ k[1] = byte(signatureAlgorithm)
+ k = k[2:]
+ }
+ k[0] = byte(len(sig) >> 8)
+ k[1] = byte(len(sig))
+ copy(k[2:], sig)
+
+ return skx, nil
+}
+
+func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
+ return nil, errClientKeyExchange
+ }
+
+ peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:])
+ if err != nil {
+ return nil, errClientKeyExchange
+ }
+ preMasterSecret, err := ka.key.ECDH(peerKey)
+ if err != nil {
+ return nil, errClientKeyExchange
+ }
+
+ return preMasterSecret, nil
+}
+
+func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ if len(skx.key) < 4 {
+ return errServerKeyExchange
+ }
+ if skx.key[0] != 3 { // named curve
+ return errors.New("tls: server selected unsupported curve")
+ }
+ curveID := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
+
+ publicLen := int(skx.key[3])
+ if publicLen+4 > len(skx.key) {
+ return errServerKeyExchange
+ }
+ serverECDHEParams := skx.key[:4+publicLen]
+ publicKey := serverECDHEParams[4:]
+
+ sig := skx.key[4+publicLen:]
+ if len(sig) < 2 {
+ return errServerKeyExchange
+ }
+
+ if _, ok := curveForCurveID(curveID); !ok {
+ return errors.New("tls: server selected unsupported curve")
+ }
+
+ key, err := generateECDHEKey(config.rand(), curveID)
+ if err != nil {
+ return err
+ }
+ ka.key = key
+
+ peerKey, err := key.Curve().NewPublicKey(publicKey)
+ if err != nil {
+ return errServerKeyExchange
+ }
+ ka.preMasterSecret, err = key.ECDH(peerKey)
+ if err != nil {
+ return errServerKeyExchange
+ }
+
+ ourPublicKey := key.PublicKey().Bytes()
+ ka.ckx = new(clientKeyExchangeMsg)
+ ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey))
+ ka.ckx.ciphertext[0] = byte(len(ourPublicKey))
+ copy(ka.ckx.ciphertext[1:], ourPublicKey)
+
+ var sigType uint8
+ var sigHash crypto.Hash
+ if ka.version >= VersionTLS12 {
+ signatureAlgorithm := SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
+ sig = sig[2:]
+ if len(sig) < 2 {
+ return errServerKeyExchange
+ }
+
+ if !isSupportedSignatureAlgorithm(signatureAlgorithm, clientHello.supportedSignatureAlgorithms) {
+ return errors.New("tls: certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
+ if err != nil {
+ return err
+ }
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey)
+ if err != nil {
+ return err
+ }
+ }
+ if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+ return errServerKeyExchange
+ }
+
+ sigLen := int(sig[0])<<8 | int(sig[1])
+ if sigLen+2 != len(sig) {
+ return errServerKeyExchange
+ }
+ sig = sig[2:]
+
+ signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams)
+ if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil {
+ return errors.New("tls: invalid signature by the server certificate: " + err.Error())
+ }
+ return nil
+}
+
+func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ if ka.ckx == nil {
+ return nil, nil, errors.New("tls: missing ServerKeyExchange message")
+ }
+
+ return ka.preMasterSecret, ka.ckx, nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/key_schedule.go b/vendor/github.com/refraction-networking/utls/key_schedule.go
new file mode 100644
index 00000000..0afa04bd
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/key_schedule.go
@@ -0,0 +1,101 @@
+// 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 tls
+
+import (
+ "crypto/ecdh"
+ "crypto/hmac"
+ "crypto/mlkem"
+ "errors"
+ "hash"
+ "io"
+
+ "github.com/refraction-networking/utls/internal/tls13"
+)
+
+// This file contains the functions necessary to compute the TLS 1.3 key
+// schedule. See RFC 8446, Section 7.
+
+// nextTrafficSecret generates the next traffic secret, given the current one,
+// according to RFC 8446, Section 7.2.
+func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte {
+ return tls13.ExpandLabel(c.hash.New, trafficSecret, "traffic upd", nil, c.hash.Size())
+}
+
+// trafficKey generates traffic keys according to RFC 8446, Section 7.3.
+func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
+ key = tls13.ExpandLabel(c.hash.New, trafficSecret, "key", nil, c.keyLen)
+ iv = tls13.ExpandLabel(c.hash.New, trafficSecret, "iv", nil, aeadNonceLength)
+ return
+}
+
+// finishedHash generates the Finished verify_data or PskBinderEntry according
+// to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey
+// selection.
+func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte {
+ finishedKey := tls13.ExpandLabel(c.hash.New, baseKey, "finished", nil, c.hash.Size())
+ verifyData := hmac.New(c.hash.New, finishedKey)
+ verifyData.Write(transcript.Sum(nil))
+ return verifyData.Sum(nil)
+}
+
+// exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to
+// RFC 8446, Section 7.5.
+func (c *cipherSuiteTLS13) exportKeyingMaterial(s *tls13.MasterSecret, transcript hash.Hash) func(string, []byte, int) ([]byte, error) {
+ expMasterSecret := s.ExporterMasterSecret(transcript)
+ return func(label string, context []byte, length int) ([]byte, error) {
+ return expMasterSecret.Exporter(label, context, length), nil
+ }
+}
+
+type keySharePrivateKeys struct {
+ curveID CurveID
+ ecdhe *ecdh.PrivateKey
+ mlkem *mlkem.DecapsulationKey768
+ mlkemEcdhe *ecdh.PrivateKey // [uTLS] seperate ecdhe key for pq keyshare in line with Chrome, instead of reusing ecdhe key like stdlib
+}
+
+const x25519PublicKeySize = 32
+
+// generateECDHEKey returns a PrivateKey that implements Diffie-Hellman
+// according to RFC 8446, Section 4.2.8.2.
+func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) {
+ curve, ok := curveForCurveID(curveID)
+ if !ok {
+ return nil, errors.New("tls: internal error: unsupported curve")
+ }
+
+ return curve.GenerateKey(rand)
+}
+
+func curveForCurveID(id CurveID) (ecdh.Curve, bool) {
+ switch id {
+ case X25519:
+ return ecdh.X25519(), true
+ case CurveP256:
+ return ecdh.P256(), true
+ case CurveP384:
+ return ecdh.P384(), true
+ case CurveP521:
+ return ecdh.P521(), true
+ default:
+ return nil, false
+ }
+}
+
+func curveIDForCurve(curve ecdh.Curve) (CurveID, bool) {
+ switch curve {
+ case ecdh.X25519():
+ return X25519, true
+ case ecdh.P256():
+ return CurveP256, true
+ case ecdh.P384():
+ return CurveP384, true
+ case ecdh.P521():
+ return CurveP521, true
+ default:
+ return 0, false
+ }
+}
diff --git a/vendor/github.com/refraction-networking/utls/logo.png b/vendor/github.com/refraction-networking/utls/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..2ebbe4db30e0374850c4653a5b3b3c5ff06cbf49
GIT binary patch
literal 23577
zcmd43XH-*Nv@X080)!r#^d?o2DvC5ApkR<@11VAj6zS5XCe&91RGRdn(xnMV69^z6
zDAIeE-UOuA+?Ds-d&m88&UeSS&9IO
zB7uXC43Z4oL8iwc!5^~6w>54+1meGpx||qrhr;=mp(_N5^AkTXuPkK`aFg5(qkWTn
z7D2+m%@Aa_Eeb)r5atH@zSrp5giq|8=Of{heQJK8#Bcqmv!D>l&(~{LqS;{+V{&=V
zjY;qKe(1a&ercIj#Hy=IhYo#b*fo2Rlb-px&?>23hC;2+ud>>59bu7-a-EPL?@dx@
zebOEbO*4@Z_!C0~s$RYIKFeMCskP8sS#u&@JS68T-R_p1e|@*scdB8-LDzPg&FM&0
z0VCQjhAEai@SFXtJih91QWRsQ)J}pKjCSKb%t{_2fgt9RoN%6%?DRub{&u(MvFLK2
zIx3FSx&lI1UBTI*QM8VCoe%em!5q!El6lxK!c2Ln$qF;5h;!;AUk>PkHGEM
zUr%3ngDyoOT6v%|@2l;ljV0;YqkC#paE`&4OS{pvU3I4~9)&SMP#`{+1mAV$u26SL
z=$UEZTjk%pC0mt6Ia6xRe^a=@P#|z`5m@!;7JF*g%A>ls%GtannaQRbOVws)3(R3G
z#1b}D@jJW-8F7aYmh(valS9quYS)I7PH%Du5=p5Oq=E@Yr*y={pIwSy7I;egb!%HJ
zj17Wr-V5i(CHwDXsz>)>HvUGgJl;dvKh$k_ir3?VAj%J$O7KNBm5w8;y0>%vI9Y%H
z!5K10f-OHe~W*imxajwf|d%pr-V
z(y#|B9MT)(m1JeO-}Zd_6|EY`!$!=*!jZQjnYe(ft4^Dt-=xcp3+TupQ*M-JoC9tzU72Dy9DyqGZq=a`A=|m@~OG}iF55QnvLr(gFHG28lZx+*Cb2Z
zg9!zC0ZghDJSXVWi)@H0`D5ZLBd*av@cGZbV0pnKBq;X3-XT0`Qz+(V+=cHl;vc|SmMA>ww;Bn!R+?uw1LE^CLCyWY{ASFx6F}~pXO|ULO`3k
z$iv$%0nu@veti-Z2bHUovJ(mgG@`X~2s;6+MnPs}m~)pazDCbYe)@Ik!ZnZrZ$*M%
zzL_JOu?L($|g)^$2;AYem9VK
z#f%jRFR>dUd`ofun`9af=`gMny!
zqLvs>=gLov87IgrCi~T~aOAd=Jjaj8-7ghKEj!ccZP9Z_JcK?+;^uW6^GR_pjm7AQ
zR>T;YpzU(L*_gtHQ^(5oFkV1IOipuRJ@MPC>tOPk4BJqr2AC%a)ZGs7DpPJ)QZ_s5
z@-aSC5GOPnpCwLuoJEO!ZLRiH40zpKCK*XkKbqBY((PS&bl|Wr{c|?2@Aeg|N(%81497Q!rPVTF`oSem}8+-j)qVKI12NE;)>F8lQi
z*AhK3&W<^^->`65*f$8DpsK=unltatD(`yf-VX;e`9S>AMDfYH0j2$@#pFwhD=6nh
zl1PD^dy}O_+s9_xi7ltahY?bR_$7|EmJKPc?3>%9D1>_Phm&^|?-7<%FzbfWP9Zrl
zYKXs&hv9x@3uV#;LT|3#8t-OS<@H()HFI$d-Iu5muENGe7;8ukty)S~zf0fHYhFp!
zI@3Q}%qCW+;|giT8s=7f)2;sIjI$8n%ZNKt95EUXXv>-Sikql;L=nBSf6iI^
zCW!2c|>xS1^O|!FrJzcQ@G+b{SH~rZt(P+<{
z6m3pTE1ah`dr(Eu^dVDr`n-NE^yNb#!hnK=7a1{V{!jNz_>kW`5TjvwlY@R@y{w`@V
z-Y8ma(f=^HlZy3iqj-~cT-EoTGllE(7kEn8hA7Y!XcblzT(htcu>!YQf(z2YF@HD5
zF4B_)W4ENJ)gM9XnRy5#Jcf!S?C!6D;CSLe&%*?7%`QZ|o5%2gQ)QkC9wga~agm%K
zd1|iIJ`PlqCyYUDbIE7xgzjNx1cc2e#rd;(>Fm!`DlM9aH*jpU>SYLqCA2!;S!u$@EmUg~&pzX_;x(S>88fe6n$dB|{tLxVW5(0Abk04}b@7ajS)4pm
zjKN)Tg8`L_0uh)ca9j5DCri@u#w7)%rqCJ9XdfP+*u`_I#(ozA2m5_-WC|UkYh6e#
zX>Lhdc{@b^NC{C%dsf}|h;gVl{k3yI^e_IjvwJ!oG^9{I2O^Dua*!9fNjZ0T45;=ekw|BD0jf1mFq3dgbF
zJnu+0a-{RG1n1oqQhHEWuDV*o+mERq
z67-|TB#@9o5BG_ye0wSS){;QAY`doZ(;DL8u2sJ^bxS&V?pE}|Kc-nq2kz(Z{YVwq
zw{m}iL4hjU5!gdCWD~I!cbsW%d-yPV_5meAp9bhj!!UE(7kup_0&T6FaPfYv&)^s=
zOEgLY!w;Fe@nxjW{R}3-$H5zywZvpef&Rj33fX{j=SFlN+k_%^VkIm#Z~g@uh~U8k
zHwuFELdiV%Pbpe*$Xr>$SqcrKkv4RyDg{;>zVevmP)eer#KedANvo>z;bVG6+?ifx
zZ!jy!k3AoZZK3pyRzFfA$wHD48>Om3(~JcQ0sbQ>;4$BHlce4O#W&)U7$mH7XAyD#
z!HjY`F@Zpe<_lpmrw4W=Jb~ahlxSpn>o6WUk$2emIhUBB0&MUCZMJ)PEU&Jasempq
z{~G!G=-D}`leL1oAx=k$66F%x>9ur(CfC|uauAkcRf2gme>o?;tN-tWVd@2~+HyDa
zbawjbs(SR^G;ht7IvMf{qL_`(gs#hzJ0Svwx}W2B2BQ_)O
zXmjI8LRb>!NzA0fyN}@X*|Z%Y5A>LP4%ihDa4v@skv#zMcE^&SJmDm
zTX&e*N>spSfST_ne%dZD%dRoV=_~a#eXH*&3-OX1bq~VwB^aeeO=4-vZW^L<^+20s
zm1UCW)-uqO2}>+)*HJQ@#Sm2MlFVSzJII7Mf=$0F1e$Yq;*Jl*PI?^u>-ua?*DrZf
z803*b*fBON#^fD_zdiBkNxxaAyax>G=$RJF
zHMU~`I}Oa*|8uJ9tSjZr#NC#PE$
zx&w-vtz8n=%E5N<2=!0tUk#$c#{lHtrGN)bVn>pOD&8LL{R0GO<3-iMI2;Y&z)Ye?
zkcpCxSXUOmn2tDw8w_U_9g$MaL(4d{a``J4!9s+zB@z;rZqAet?YpPxS)pn^g9YZzk_aWk^<`~loOGG8U$ON3QB~*7128T1N1Q$
zc!0odNz2?)t3(chY$!zT`yvLDk=c!79km=_Bw<$$JDg5piX@$H{+k#kHIz>?j$Ws*q2D)Ayp>AZN#i4d2Eipm;dWyU@H#3geeKGsZ+w|BAFIv>IeT
zNz#q>>*F!SxNI7lLHcu9tbAZ(ojh%G&Kg()iM^
z(r;;}e(ZYxUk7yIQk=N60|It&xyQ5KT*;d>N}j=%@!zd}C+E+)K+gWeUZ&v`d;hnU
zpWbVNyhuDE<f``&|0Z8mQXs2}mpbmQ}`!Q~(XBGmz=uZ4jn!D`dL=3RRMD
zc4J)HPEf9HW4;NxKf3Z$^XFKt3}Potn*uKR*fp;Um08g?wf~#c>_v+jUi8da%17Gx
z?Q4E&l}GILCQFm&zfypzIjHI7O@dwuBh+
z^Qe;Z(!tGVO6@&uQ^)VsUN`LD^my8jDtcwe7?%0jV%ln@tbKUv(=VpKuryw1k)%t1W9Q
zqTHf6y-(^Sl6=5r<;X(@YiB!X0?W-k%Qmu3DX4r9GWGL53j2dR@Yjb8Zbaag=Ob}J
zxq|~AQ?I41{jVjnW4Y-$4ZmL->sR^GKZAz|i0iz4_sAg*Nh8NCCyAv1Q&d7RI_d8(D
z#lmdq$!KYtRBCT*oLK2UjfyWEUqC`kKMFOS4TW^o{F?CI`cG-IIFqAx4X$6bK%x+k
zjMweiXA%T+W9AHfoH-wcet&c7Y0QTnw$Eti?%ZSOiNLZQMz
z#on-!Ut3KF444nGc{7BX%j*K`0+reC^rKt95TXDCv?~Bq`JACuA_P>FcL|szDvjd+
zhw+FWi_zNewWFRXwiig`KIzykKD7rnfkgG<^GxCaYyLix5ZQWEs_6c`Yx7FXPvOKV
z!f2OAFCF4`Jt<^xaJpjtQs=ovD3~ZrX+!`f5!7ZiV|&_2xc^s6BCPSri47Dx{Tn5jeD*i_
zfyZM4SNfN75zxPQfXl}KwNJxAK&}Gd46?qf#QAW_6|~xW%`rRW_Io(7$z4R9;QBx^
z=hwtT0J_wykC8(N*a|zGJ#V9Li!q9*0c8|LWnEVbOv|@s<|F>}AY%+(v@<1hC55n}
zqd5p0gn_;*s5tH4
z;vj4i8P+2^URPKy#_H;a0KH+YfT-Ui0732OcQHm`rP#C>9P_^2q>h1S6v3w5geud!
z-J<&vjjjU}HJcY=uZ!s(2DOfMKq@qF75;laa)dacwER?my2h7{b5`JZpVJqt`h61#
zluvkeOp5k%9?DztK#zodON94v>;T9eE8mYz8*0iMBJ?dY}v*c=o+|K~>L{Z|2;=V2D%-
zK_TsrJFo9Pyk1QF{WkU1X*}LB(sJJd4b0!iNk)!2#EG(UD?2`!xL>%teQHgwlUnHl
zWf73j-?!r22380_6NJs`;Oem;a;U|J$AaE}4ks{O3*oze(_)=TbrG
zfie2epZ&j<`2XJ_$XEbwH)3O}9vV=zzRx30F)S}H5+G@6-Jl~xDz2cR;g|7XY3BJE
zf+-Z**$mHRLt`%*-h*SgF8iVoF!dQchw{|@khjO58B8XK!09!_aH6}Q3d%f32Jg%X
zZ;`238!f3OkA=|FpS?q^Ae9#saOB58eAKe|2V{+A$%Po$h0AoQD!f@(G%#IVB-!3b
zZ+Aa)8`YdX_~74`$qVheykfAiffU|rgm-X-0pPYg4h!$*&&bTYZt|;86WZlR>am#}
zMh5iW3DHjE*Ry{lSatC>;xfj24VZ>F(al)04)kjkoZtHClo-+^wM1FoL2&rnO2n5a
zpIBaJIkThcr&T|^xwt3
zsi}Qwbbt(X+pviNg-9^)r}08n%LWD-6#Xq%(5T!CblPq9321x_dpN$Yztd2)9ACe8
zw(+MbO}?^ity(i9GKjatIMm7{RapGmIlVWgN?@V?%LN$8XBMogqTk!!uhY^tVH8@1
z5&Ka#;s-Y!&ds%Rb>aHF*QGB$vD4>oYf9dA5L6Kn3jviIQz=|+
z%&cx@J5ph;N+T)$LoHv5;|a>SZ}c008YW3ScXp8W+Qt-=y0f0$kk9Y>chwDEB9hOz
zrTLKdzo|MdEbEK{I~@0FcQ8TH#P>Ek4<>q6bJ|Gq`Bg@ay1e->=k4>2=XkNadQ4n`
z!?8J7(*274fPL>BO1HGC4eMWvJ-r8`DJnX5s82I%=hd#%o0PBSy_gu!N$Su$kSuxQ
zO;_8`FN%%?Qml$0(50SMfB0SXi3^!uG3UAHc*m0`aSEBnr8u7@aj2j9Iuzw0KI|_km`%U0Ynkm)#JL=d9uo$t`-vWi&%{h0NKZ}xH_!k9KUVzmGBB$k5fRUnpkIykSg
z)!j9nfvkg-%sY+(B&Jn*K6N{_Y}Uc8n#CcKIjGf5;%;Djd1)9I;?tBk5(%HT^wMK%
z#=8i5lMM!AU!u+?ZilPC#xK-ZBjNVHOyQQBpc}d)x$_I9Z)A*HWPD=$M}b&sF-j6v
zDcX3h@Ru8t#U(Ij90ls`HPga%Sjm0f+L+sGZ`V}ozF@yM3C8rS_q{b`y>NQfepXmo
z)ldqy6hQB-eFpn)eoMXZQ{6#Eq*HAkBuIX>R?OqWa3MW$tq>ssQP+`+dxiS>go
zLYhlc^4r{PZEC#~Y__O_-Y%uvvc)8(D3P26ch`X5RiD&(uO-ecFg^XFBHZ36{Kv1o
z2V7qId=p?hR~}>eZj1As{gWHp57eb(Zq3?JMT!fu)-?vt6lvOz&{_Sr%
zROwE>LEaz6G$Lx2#9(9>!Nnz-_S^ebPzv}b|#jWSvEH9}J2idsqO9kwY
z-J57QUKb{5G*Kr6myOYJS0BENd&lYjcwUfeN;Q-9T)BJH#MU#>#<{3AKYm-U!@I@V
zLzfl&eg6#MCq9D#4v;<_XxT8j6P`~RxM8Rp(1pu#I+%GaLq4=LMn)K4Ps#c
zaZ3!L38*t|YPsu^3aqbzMl~049_ednDC^{W0eyJS?dC+<*&Et?4$2yiOkPa=OxX2a
zP8rl#5Kr}JP`KlfouOyUr&EC8^=(QFRY&@0&{O0xQfGfyp`TvS8f1?l;$#&Ze@@10
zHY=?AhC0tM+Xc6$1|EbbA%dn3)Ba>w6wlmyFtt4vx#R7vUSVDSvMN{(&gcTzAY=KG
zSJ|(PT`oZARlANhzgZ8)4zM{SK3^(kof}RuS7^;g$MoF~ER`B`_4&k&`1LGOygVe_
z(yGyI35_>})B3aQ_S%`q9t)RsK+Ky;4HF&>BVT;t%&4-g8`|(@a2Epx8v(|zs>(9(Ukq*{a
zhU2s;$JW2?V}b}9DhjyTCh62zHaqzr?`}lmmXxmfu_7keMIjq8_T=FkUOgH9RG-?)
z2&YjBJgr--`B-*w@@Y)AvhfN6F)*)o-tx$jaD!PC;1yC9WxEJr@EY9D$d>UUhbT+TamifKyfgFV#WQneV0{kebQ!5_L;tzkp*
zKsX~_3>h&SdAoTHucTSR?@gLvvS1mLohqrU!jbEx{}h3vv`dmyynbqZ!zZ48;(8ri
z@0>S@N8j}4niL>z>YWC>ND%gc(HG!_w47IMxC~0*+##!yWlDe9WIQ0|ids546Zj49
z-L1V`2FCUIJ+=(|ktiv}`X8Fn>jP4M=MPA6?PblItV&0}jP)PCn@Kgg4;PW)Ghf_6
z+8i_8$tg!q-&WrL6t$sy(W9|AcF(;mU|gR}g!h17_~5SUGDpr^)MTPtx)lK}Nqo-I
z%B#Dm)6DajXLT~9Jrw)Ip8JcjcUapq+iH5XpfC9+N^mpp)v_9PV+I$T*oDTTglp6>
z%H%YCW1UL)l8on!@GrLR*$iqyt?@P&@d?#iwHg#2ET+Y^r>_^|V69GF`)9x0qMyYL
zGdBkcIZx>YKCVb@qeuMN_mh_kU+VFk_$-wBXS8(Hv2s>2LJlGGIB?U^y-eQnVfVp{
zCBtUkjLeEF3lv(Rrnre7Ufh;(1RuIq5D{S<;ICrL_r=P-z>yN(@*Ba{ASgI|`rPgx
zR74mbTFteR!Dg1}VU9E!A3WpGV}13>>-yDrcMEfos7Id1!pR*FKMl-#I&|PWdvjEw
z&FtE6f)M3vL1cu&$gLl1*co(f4i5g|>8&?*^;dPc0#{fgMUlf6UUo^ub<%5Oxwlm7
zxcn`RMXmZf=sIDRSXk)4E%l|QU=Q6TvV@uwMwG!?m;Y$`8v9Kved~Sm^R=2W<>kk8
z%`~vW;ZC22!Ps`x<4VU*bX{%C2rbr0dCR47&W=C*6~$*CXQ(72P@8@^S3@V{azdNc
zcpQ@7uL1{&?{Z<65ewPJh4Yu6dF3WanL(lRH}=+geq7}g6{4^kV;VoIdfiiJ=_`gd
ze?>dKo5A=*TJZw=@0)~CgJcP)wsi4Wr&B2L0mab4U2ss{d_Ab|-g+81OAYq`0z9%|
zlpKCm^?^anb#2rj;Bz5$$p=(-cv^+U$`kk2T|a5X@$s5ciK5HDc&8C=y|F4?j2~v?
z-Pa4&C7>~C7~rHlc$^z0+V~Be|1A!puf_hA_fKom-#7RF
z)81V2D92KyMbc2(?d~Ox8YRZ1icy7yq1A)<%1?y|#@Y5BXSUyvaXAoK%=Q{hYT9JG
zR8!`(!`yRn*f!$J9}mHV2#u)$qwvXs%qi+3zg^)FSd}+2;dOgs^Ov-_kJ4HZ7HCo@
z{#AOBqCuRjVy>N+iz1r6e#Fk~bn1%B^k2Z;X{U%|tpU6*uae7h-U!M`b#6OwoEoRs
zozpc+Rhf5|R%%;8UZNy%#vmnq9o?vRQ)2V19TL_Py7TpYgg2A8ruO2O?SG6!&_Qi!51W|6s(ansP@@z^EKXl)c$SFRR
zZGu!)KA~hZy-9?|L+=ENt@d9)y7^A&e3bUuneZl6XD2&Pt+$HmzU88cWM!*^#q{%>
zn;V|2@v&n>{A3)y`p7OO%Rq${I}?h1_sQO#b?|=V+a8XL^}F1Rw3O&Oc##igCJCs$8NRpBXRJW#!I!IW%OQw}z
zfzGm{(v?Og2$v`U-RoO3zI~~k-Hg?1KzLLWow)ATURS6zVwsNJ0z}ls_;%?_HaGtCM!yD-kovF)|h7w|*zpDT!9l{JWJ6
zh2R`6E7~-1`+3^6KUdIyHB`UCNY$Z|r;5M5ks8_A)S8z(0Qz}U#9Gm@7G%QouCj5L
zYlo6E2btowlpn{qh`&GjUr`FvM8Q1
z?hV({c|>2z`}VNY^f+HPrF!o{`etz4dopb6yohi9&gIdFO%c^*Hq0+Vu7aG6)G~3R9onE~FY9o0(4$COr&)QGbanZUW
zw2(WmN~Pw6-*ZRcUQv*YU7omRtBX7DwI)mF!P&q#py{%Z#B*F#Iufy%efar!6!WX~
z+xPaX@AaR?$7VunTqTTlH%DQ$B53?(#=7fo=C+=MYl;}K(G(q)zLqfEw&an$5p*XM
z%ZSl=`Z`mEv})llHFuN!lu}4d5%Zj%*ZUg3n%|VaOQ#fvBTMsdQnWoKW~_({!p9|n744U|_nkx;gZ>3UhG)Y;n85c};FBbkoSb8439ueV%|
zfV9Ie?flm)(?+Euh_JHOC(8SX2>}n3czE7?{Ptt=Hs{8`wMls0J0DJ-v225khgzKC
zQHM)h<_557lEONPV|-!)%H)&XCyJ(}5ffDGPs6{5v)Y(@gqz*ooWZ6`$(O-iS%q
z7oU44XLK@q^=l+lJyd!!!hl_RCp1tJr4axwVf-)
zC%HLaP3E3W5pWBW8w7mbjx4!d{w-K>UMPY&GVINm!S}ZkKFoP1G%2k;1VL)1fA~~G
z26e#D8TjvfBW9mbg{#aG^M~y0lXhF)*8&+k`~Q~Xzw(Fp4nNA}HTQaBWtu5jGW}4z
z9B^TaU(9Q;#J>N+XYPT5s7WpsIV#@oS;*}uHR-l?+CR6c1lF5hA*gIXKeQ?FRb*@U
zr?+#%pr)k}JJZ7+!}(kcbby;m^&8y}n6{5@X_QiVTbv0h{n77o*<)bxWmA;bNWnt}
z`41NV=slB(xn#Qifk(-w^ED-cnHE~lImK_Ju_3V8;Y^dy)dDFobfdqR_W1VG&e!J=
znJ9gmAIe_JtMY8Z$d33Dl!sii?YtzHK*(b8IE3A-k*g~jI-iab?5cUTJ
zHJk+Dc>5!tqVh_AnyFL2r(r{zTkzd@2si7b15B!s0UDEQDaW
zF6`WT_kIs4L!NirV1%2fF3poZTD-AolpVJg=!
zFY(rED=l+~L_f|kCwdE)zWL&$(+%39Q;u7Csspw-0_OaWQA`pLa6|?*R3@B}d}Nd&
z&-fG{jBN_V8uFQI)ZCHNel`J
z6%uYu3uie)%hv6vH3m4?byJsZ5&qI$?F;xF;NxAluv9z~h)+ml0X$r1d7<%*8yEB&
zE_$O9bR=>RIIf8sJCsZc)IW2S;|)={Iw-FWhL5U^j%&azZyeOxwq6%G|1r$Nj~PKZ
z2b`+Z6c-(lHjA26kMv$*Yjc*IHnY?HmI4h|0`XTJ&wG=G^N<}K1Bo6`1BnjRMXCsd
zlOeUMT3@|q1LT3jnC|#l)Ssh^NT%RZcsLJYhiq*eC%qQ&D3sUvylzo2Khl0%-QDYS
zuF}SfNfs#+ouX4b#DD;7pR}VfKrr*cEZPy)^$LBc_5f4k>>gnu+#OV|73!gG
zz)88_i&q@*(H@SHd$$c!6GdCxs}LJoX%87(bD};@a~SrIST^i(tquXVplc9S;egJ{
z2c?6!9KvefDhR=uJjKYH9Xm};%V4ohTrt1UK+)EI8!~8`Sl`-6m&fLM(S3&Dzbc_nI5`<7DZkyCKJkxB2Y8nGeD9
zT~TAX(^2!fK;e$dZNgDqoZZ3vt6UA<2dngwa#c&9E7ZZt%VJBaD;C(;PBXb?7_lzo
zjn2Sx`*cw$1f{`#l)c@KT-YXhq)i%ld3|5ZrkoKGwHsaQPS;M33r!^=chdh%CF~e2
zzg~B`eyHa2W$;(lRUJxL)-#2Y%USF%?*J|4EDi3BDB1~3KIQTz)ifvADc2^PF}zfh
z6DoF-T%s58eT{$O^v7kWK62Yf=`<}kawD_sM@_keSLC8;H{Qu<^=Nd=e_g}JZ-8Ht
zFN;m~ksUCK3pRboW5towP58&X$zZy=eOURFe$qfICwrToO#D$M8U>ivyC|zL_mREb
z2jIt1o#6s$EI;z$1)D{Az)5`IW9Rg8aopftA)*90@72!9Qe!)
z{#+R25Z6X|9XJrot(~PTo<=B3;M%6Pn|9Hx&drGYi~wy$ct_JXc7k(NFop2B(rRO$
zyKN-u3deSUQ~@>MVNMYF{~2&vYj<^tr)*0!!-ZMW^~-f2d`N(MeeYAZM=$)=6pbrfdJf?
zvJ7fL=?cYUDp{CS?cfhi-~IRe9av>O|f;9hUf!qP^F(kx{Xk7*z=ch{T;g(LG!U2|N5=kAr)DRMO
zrGJCw+Iv*(=evWLrYu@GNgG!{?UNWO3rGc-o5Khejd2!FzUe5h2CjhCzJzy7a<=Z{K6@lK fBI7-A%Y_^^egFNP&Q8CVxb)G;4WFHo*cmU6s4seT@4O+&KbQ<_F>geV{0
zCA0ZXBK?I2NVsTe?2@CQPC2{9^hZrd6*7?GNe-h?v;I?=MF%IcTL&$R@Ot93vfPK;
z@zSyK)STMCg=mm46IFUsX@;qXWn-
z==MWr(=PhwYJ&L_FjEZz4_MDJh7~Z99qI1>`~WK|it*P~F}N`Pqxx25e)HU({^sRn
zX4a^|NR2aJG+RCcS-tD&*1lg(9T`^C5D1WYQS8-2pL;*HOM^sUlzZ+Hs)xo-NX54=*R7v$8GA=k1&sX=lBjB*>KSX&sQKMBellN6xHEJm
zL%t~axZhsfP`#)!H~Uj1vqO!_JMSD)X6xt&
ztc{CHuFfVVTJTiOB^=
zGkf|wt|R95UY}(2q|6?j{K|TG2YF5T!b4>4LY*;^HA?ff%*ed~I*-0C-x+(dvbkO4
zTD}G^Cd&WtPr#h|9Vy^x%6~iO77g~jCHiiD$?;XYEg!^SuNimws_jFmdq4UxIv2jZ
zY5KeJ6L&EHU&nlAzd%XdRmu_Yw+r}E#E5n77K{5YHYVJlb}wU!2`pfTudzv*#PL|%
z9RcQvgret#L0z76Eb+GFfz`t=Syz7B=s#W1qAa?k78v?e>B>WMOQ#m)bW_~Sv#Eoa
zfUCvS4`@iHDq_#R!tBD-+&Qk0carCpoW03-7Q&iTyNXH>9~{r&jN0LM
zI)(It&Nmq|HMQc+i-1P^A0@gY5w}6AcJ~<0pBnyN=nEHry~(gB&~{Q03&dlAh|)K5
zxh>2sbKgj{=!uI4p?JR=C?l5gcy1<_s>dwv_s<7ipVj6#rX1Fo{_FJY*iJ9tQ2Asw
zsEB3Pd15WSJZ3V_-c4yt!(3xy6c`|FvKlUb1uO7g?IiZ2sS+IH4MuwEcck*+Q}G*D{toz@Eo<)3s?Y-p9us`!
z#RfB|HQwQy5h+f?zjTDnFL+J+Jw2kGzP8+kE67qzE!THzs3Fq^DDM10L&ZFY4FT_7KL93aE!uVHMLwC
z8oK+7ekps3%KVn8pPI_$_C!_&8T-^vzc}+(!={Y;x(W@<4?w7w(}^dck2F8K-n&bA
z)ps{7z@u!ND)f)lQ60d7>JnKpv_+8A%^)UZtyKu~0pKL6Y_>eebGZX)^%lFBZt;BUwwZ$a9-Oc<^5<8G+G*z(IzZ;}Ht39C}UH0yyom!B`R$BT=VzmTe
zrBb}Q-g&*Ci;ksc>7k6w_wJ1KudUt1#UVWG{n{>H_m9IKX#f)2*s=t3$L2)JK%!$R
zmEKS$`o$be@+#(!2W`Z+mmGu%Liu~x;TYkdOFrP3M>dpdSFtC!z<48FR89mTi6o+c
zOpgVkhLjNf@{oNk80_JoZ-(43SRpO!KLh
zK~<<{H0Q?YnOoZc_D3*wWcZWo{Tjp6YC|>zjw(n+^t9pyDQ<=wCm?4N0Q+(diGZOq
z{-OcN(rcr+@AfbMA{5+6O28(TcEB%-7d`#gBBP-_fmbq|7r12?i2b}0Y8j)_toN4(A5U9fm(8HInLK~AF|T1Po
zc@3@N?iTZN_qw8A847Sr0g335(`r
zK#G)B2)LRNHXY!QabG&;xc)zHOHG!nS=o1(x(=4hp2}*^0;6Z?DOvIJ9npq82O+vL
zYa;LkqST|cIM~bUT*tdJQcasZcN66?Q30oFl@z7+!ib-(bJKT>bOW{}`IQkk?I0C}
zWEx9)ga;!cdam2Re|>CRV8oHvMySpb^Mn-i6BZ2!l@n%!ZijQ~=CyqIx#^zdA1gnj
zrIB!B8j_r7Eh;!a6?`>Fayqn~7T(y#fm!frU$0*K7HPoK4M7}H#PeDz7jCqI?A8L=h3O6itEnFF`7oPYsW0(B=YY-sRWnN;`38$5$uZ)&NLw
zbYLGn)>qqPiU59N$t2#Ac+)>;M`5P*bC;~%@lCsd8D~pgCO_La%bak@myH;OH33j1
zTaHJWC69SOT-WmcoZBXTow
z8)?o{=D-E!#~*8!_sOm~k>a?>aUSCP{YEI(C#YM|vu1}CPR7pPq~`Rxf417H)lreu
zfq7)lju`9U5uwhA@UA=i{J!CAy$PD7Bdw!y`URq7g0QX1v$U{I6Nf9Rq07LDcPX$VfbPYam6`b@1%l%poX6^R!?2#rIyUpa}E&2)DCTk*-*i=sNr@aUMqxJ<&1aq
zd>PzpY#@44hWe6#oDecX5s4&WY9-<(kpk;GE~~su a5NSp~Gx7bk`F(D$s_&l_Fpk*uNn`
zgxWsMhQ-Zz^lP*+3Y_jc9H+#0R}eWVttWRu06K;P_f}fq7AoNuYn9DEZ+Inpd3mYz
zaL(iKc1P$htG>!1W|@T!p~I&JoR-z=ZH0pFDMCYg$-Ysomx^cgtHKOD3;#4~h?M
zJ_n}9LjB*>srtF451MIb#f03%GncHwMpH5n1DX5iEpIp5$>MR$BMXjwzPikDEFWZUVtal*I=h^Z~`VN!4{T-3imnnljq?aflN*
zYH9tmhJJV-sd+{3q@8T&e){^YlZ_91hu9R68?4u2J_3iG7*gP+BxFEId$}NzI#kS&
z0l^-WscDB9l&y|(BmC*#_jmw;w*r@1-|(U{!2h_p2wurS(0+&)(fU5N^Z1s6F*R&b&
z7z)O&EL*uRypg6(=f+vA?o!hyrL+*a2A`yXQ1@HCkD80=5#bx-5&_$Qmvd37N3tY?
zXe!1z1BLvNH44$eL?(~X$^Z6^vv%fJSG5fZFCupAE)g_GqeLuOuO*#H8)&tDl7#T$
zs`&RP$vYDO90QNanx)KCSfPvvK68CO;BESRf9bp76`OCwNU*XOD~zOoM|6B;5QIDI
zq)IrWf$b+!|G_X->YEV?utKU1-k(Qm{k{Th%c64-h_x1ecA@o#;YGIyY8rNf&sWUM
zdyOzUQ_hQvCett!JiNW*RiMf)bv#o=g9=}h%Ek_j=k;k-I=nj4Mo^9)!4&uc7Dx<*
zF#72)5eVKjLZn@n-v#Yl-bctVTmFuE;-3A1I#4C98GkogFpfCn?tpat^CGE=gBrk1
zm0&b2302H7L8Q1N0n=^L@XU8D9Hs<3MF@y+1Aagyc=-F|v(0Bh_iJ7(fDRTp3yy5{D#8@DDE{MfZuXQ1RB_@iX|*LXiOwdHK^rNQjiB?cdF;d2X3L;cN4$S+IcwDPPW0KC
z5ZeY6VP@j6eET?kUf!w!`x_u$(BkBlZ*nAaAD~NvH$ZeI+{OM4#y&Zs8w$q$E`653
zi)RL*;0(#nm~`z>WNSC5^-fUTIsq>n>72u#wr5+kSlZ|{a#pQ2-os?m(6IN|**n>E
z-wRln`>^4-Tn!U>f=tj2xQ1%6ba6(n-wSL?yxkj-!*)|fnN`Sb_$v(C1YS{dQ~+PD
z7Rv^3bZlkM~i`4q&-~
za|?nN7-A7hG(<4gujHQr*97}nAJoj!SwhwC>%a-NF$A}8Fj&is@;Oa;ZPA8aAI}~$
zvekuNi$XZw{k8~L(i>Sq#Cj{;E^peY=*t}`DoaSN*_6Zm0^^MlqS#-%pP@1c5jV~J
zA{;M!%EymH1DINwR#DYH%ZxxJn@H-u1{utY}S$t=6On&_6HZ=`Tj{?<=
z45NFl(7JK-i#TU$2KRCv`^goS-4aR(@XrN{c(i4=)!1E@erKJxgXg;MPe**X>FY%u
zilu_vccQ5Q8b|4Gw_rX2JDY$#xn^*zoM)>(tb66wyA{OQb6;cfwZEYOA?TJ&1AT)t
zJ9PY_^Tn`+_w$b?Md+=%Z$@Jdc#6r#iaFW-As!u23{Raqdv@==(&T>AaNcq^+9yHJ
zs`R4WaMtYpJ6k+To1y}g&%Tb9Oc%$^Q;=Sv#Lx4u{@r`)v`)ta@qzxLo>o%cHM#!O
z`pviV%oW!n)t#c46&>T-C`C>6b0X?#g2-eoB_yxC<9F>?p5X1Z$0}wz3H(#8y7Qxh
zW>U8|I3RlJBt>VRcrWD0(Ij^=WjeYu2%_LI9_|9|CSEq8
z`>~Acc=={>`Vqoyh7bg^#L_EY^f|t0JA=YjhjCX{ie`fD9wrc52*lC{cCGA*NR@*U
z(AYl6DYupHlt8;x{x3vhXETas@{=@%MwzBp8fpcpHRC~e2P
zL+qjP=WB)6NX7N#jJRv837>AufT<^w5HS=p@&anhv7)r9R`bq!I==!I^4{;hj
zC+YM0oI1IhBXEfrrv52UsE^lYUsL+}Vb+YQ2tzfmb9m_eRJ|;`x1x8U`Mhsnlql^T
zGymb}QkQV8Lodd9D>e8@Bu!V-^y6OE?~&2at?M+q2Ef)i1eYhP<57vWr$he4LWG3)
zKT|DKQ`>>U)
zO{`L0l5P?>6mH+==v1;J3c3|fQ!BRm717Yf#&l0f6*?o@bCAELln5zO$E*G3u4lD{
zhsIS(PU$qRq;lf?Qp*&m?l-A-wRhb{(%)HO$4tCF={D!SF4t8P>0S59rbrW?q>Uzj
zQ@(`qZ3u98^Xe7GTslmLj*5~e%L?|aEC7?f&k#6&bkADan!w*}3w%=8GX!jm
zmV`{@Z3IRkm;`1(d8%GfQAQSu-SGGMO%)lmdy3_+efx}0X1qP%yc)?0DeTObPh2&~OmM)BcANp!)UZrArM@R?U$
zo0Tbc&io|oB^NWKFbD71rCKP39a9E`1t%m|m4CgS?}63OgbwA(LN`J~B#eMklm;;2
z;}WeF*8+JCLr5DRky%UD`87^a{z1+cGgAhG2xY1L|CjDV~>T1L7HTtc$6b~C&oMUPXfZ5h?IYJ%Ox
zML|txfG>-w`fE1sAV^`$htAwSrLQ2K@A9GtbJjmdmoq!~VJVIL-AlHq7AB8ALQ%Nl
zTewPNv|VvH`%b9!mJxrLqSMvSX}wch+i@zVq^R_qI&c{iuGxv*WqeUA=P1@^gDC|g
zWtWK2fAc-I-dr8q=x^Arrnl_T@!-w$0qYC(D2&_7*KaP_ELm_67(^3m>Q{1^y0B~(
zUf)5e-ogy7xtsV(Ms6C>e$Zn;Al?ueA)f#;`g~unAWF;ArvZMO}mc#)?E-W@%z7nj25lIo;<&>
zFK(vsMcd$+zK|#GaJ7vzmhl4bXdd8-AhfV3*2KzFdHG|^&A;T+D^piqH0Q~r(AAv3
zcJ{C8$Y6UDy1W%r%0Uvb3dAY)aD#+QNh1)~K84Wb=+E3DmVOUwBW8z>b1te>*oA#y
zR*o@eHptRge5^VT0qbdn8@ysl064yi!;eGEbK?{)Ep-Xqc7G7ODQ=hYkwf!N)qB6a
zUIlkoLM$rln4T{z7tCQ;z>{rrEr0dTZw_|748BaT<;<$8j1ngNoS>X=G~s
zJIf0p?X@6s(sPXpFQY}k?6G)wVC8X0ZY$}Zu(A4rxsb8*6S|xN&Lt18aYMo5!mQ%h
z*kY98EhJ!y5Y<%+>7&&^$_z+FbXp%&nlM;=KP<*KWE9n=s}ArVGk
zW$eg&06*gf(wSC?h=sJ-o37Wma*fffufsw1dCV|r^ZEPn8-EO|2Ze78?vmV-zfcgo
zkJmJ84msj3+hOtu-k4Gq9+q5pcmFnv`TI=66Fzf_GfT_`
z(Y%mYX2R&4!%-u@c{V{Bs~r%>PeOVQj<-;qb)zl`Sw_DEw#qJ
zx|5S_TW;5MOP8&i`Yz|@0xAOUR%ihK9T)@n=L;b`WD;U^6q#8vi*z{OZux~h)zh)Q
zV5V!(_;5)mqAY=Vd$jdV!SVI5S_C8OeS7MkbeD%Pfu+|#I?#2VM*`S!Cy2#0;in||
zNk3jPpW$X~oYpGO^VycPDVei(^CUKd+1EH3X+c0yqkLg1O7$`F*UU;5fywC^gwM{L
zwt9t^Qu~fh8P0TT&9X=L%s(7B`_f0wa45Ipcuk<&T>ix`e!YDvAN9JUL00sA+UI!4
z2ZS~y6j!}6kmAru3ybKN!$z^hVpx*CPHVYBjy4io4e@;SZ}LJ7S969_r#zqgEU4F~
ze9LHkBOLN*Q>VYL);HqbRwW>W^FQ}n6f{HND^C*Gf*}wM356@`y&aZ~l!2A?+$7oA
z&-4E6vvzZDTloJix7abXU|8*=!j&r$LkN&NAE-V(0P!fiKD}NV__=}BZ-NDfDmxc&*UAI1z$n?k(~eEzdxu;E
zhz=|ti*{w3Z1qGc~OkU^=r_rz=qITa1^%5W>{UMm+he@LKM-S2)_R#m%@J-wlKs036w``%=zF;5B)$o3Ca5DH@Zku
zv(-h?7v?UtRcyDn=68~Xt2kD&uq@0!q%6veKQB2g3z$%zc_r0_se7u)Tf#D-z7Abu
ztK=KpSCxQ9CW7oGP(_%rLl%CUI55oK^RSba;&(!t0^WdUwS{&3c#*GkA!qhw9s?$p
zSYa6oh8xpv>Oi(I$X$SiQx~C}nbngZ0#N@4R-ytFSZ6}LfBF!_GT`=3CW=s$|LLSH
znxFOC%(%u%jToyLdTqi2Z_0Rtmnbd9-vt_ry9NbjqzVlt{4J*kc~@-j;iU-O2T|o4
zv2r(BM%=!*a8bz$`?bWy3VV{P=MAnT*l0S)JHbuf-%e#*ez69i5wg#{kR;2ozwJL7(KBt<9+
z(lf&?frseij{Vn$?Vdvp{5&f)RWy`Z!(XQxn&Pc24)XeU1Gh`D9r>_iNQi*=YFFL<
zp)f+rJ@{)t9gS6})w&Z~_3izz@-x}W1Ing+#Fp+4-X!97Q4GF*c7CSJvgs8#HZBXh
z4>i2;vBFwmUswK*;aj?_%W!{Tj*q`BZ
z<^YyE7^Q05@Y`rh58>w^W3jAsA*vt@%vo3=bxF$n_zz`w?u7HPI5MP75>xEyk@ghC
za48`flhe~io#_|2>S}wU)gK?GIC$)w`T?Ak7(>$P`jU2`pkE40trxx;99+4b_5-1n
zHnw{Tnz($Ij{xlsLvLQ*{j*{BllNnBeDC$&uR1Hj3Lk?=5QVP
z7wqXki|-za!d2jYO@&>SE(MQ3<7@spEzKNk7B1%}$%VO2>+^#g(A2klAgA`7O_{f+
z>O=AUpzZ?ka{|E?FHbVdxa~SOu7dh0p;!^ib^M2@W5LBumv4em;IMG5f%BmyQd6Fd
z@qTWjr$6Gj#sj#&C-1l!5~?ns7NYkZL;49q`|#i@XXE&~>kveMZtmi3{#`7woQr}o
zWt^V&z9X%T+4UlVgg~((yl%&TEerA-m2&5rf+ZG3VkVv(--E&|?4uD{fl{WEL6BN#
zt>=BN_y`Kb*Ah5iDl2+d`J*6z#Ut(ckJ7y*?Z4BYO-Cp8ff};r%A8VIfdLhTvgHM8
z`z?wcEo@{bGix7w4-U#O0c;}$SWNbFhiJz$H{{%0tOBGTimQC*VjO(+xNNHZ))HNYm+CdBz8Ng})q`b(2iNE6Pj)C5VR!?akeCn>A@+
z{c*q}pt!dxHEhe2{Xzj3_4UCz8G%Sc@iLRyqZahJHUsupzQ)Q+4V?naiavx68t>AZcHe`oY_Aakzjur
zL^|cnhY?|BuSHn05nWeZ4}T1KYY$MnJfF6BQpRR`7_Mg5dhmmh##GUNzrKo=nca_T
zN-^)xy3R{zA4Dgz*D^U4Pi)uM+rmHGGWf)g!cf)vs|x)i)~H4Q1^L00souyqlyM!M
z=w=$+IYrzk<@DKB7tOyDJ5dEL!3=YdS7LCabC;IWv9B(*j65HS~*=O0vVqfSEni(n#@2NarR$};to#q-P)oKm?`!2tvgr3wrMrGTyYh=}s|
z&|0Kg9?n!DV$q7BjBt$uj6vwJl~N;GjX(=UCdj)KX&xlJVsh8&huj+bp5U(<+Vn~Ua>Yy1Ww8pMKlE2SAb?|^z~=|Y
zPIyNe3~i@OFJw;L)+1xew*O>IE<2R|;HTHO3XsMH9|bCaYJC0$iGXMVa{M=)t3dw}
z)ix;x#I&6$Sk~tjbOJg9U$oMW{21sMrYXSZ?|wlxQt@n;fvAoFeh=hSEzCcjQ&1k&
zJuoKPyQNS1$B0&d($k=8cR@Ci`_us{e*5j!!0M3B5DYED7~YF)PhMa;@HURUKV(ZD
zfSg7UI2>+o4Tp2~JJ_n$=d
zy35qd7DhckgU_D?;Q8M(*MVid0kjDndtiG4amQ+I=H%fUS`$bIx1$|eSl6h=G?#(4
z!~}fR_nNoDq#4O0H*H8Bv9X{PfYcgvaz2U@JId0V_M#Mob$;~JYke!-`lpP3?B$
zi||_UO6Jr?(@Fn%Sz5;AvNVA72R?}_O=vMCIv43T;n>rFW#M{Hg1bTH)a}oEEYE4+
zbozsz&O5dI)=T5RLcoGNEwLS$wxbW0H6u(lD}Ca}oh~xD^y2fsfX}}hpMMID4L*Ou
zH2&t;!(;Wo$h)uwcqB+`3i0_TCTt^@JOT6hQ-FRkLGc@sSb4uu8RAtSSAkpwaurBi
z-05Pk!#dvp^>GeVW6*Uac~vd2WXqsu|HOKvU5O`=%m7%Q&67kayRlp)N@|jpM5m4?S!o^o1#Va#e>FTSu11O
z{yYl2-sy(3|FR2VG*vd=ZLFfqJ_4vIJ9;XX#%~AsgQ0IxU0t1(Hoi2bp}u%f#BYS<
z4l2&GENii0ycfgj!QnE^pxcJe-}oi+<{Zuw;Y(D)FM1TgTeUbp<}77Q*;a!{rmBYe
zq9PTDbUah^gND?xTR6M&4zqU|vK}cJiZys`79uB_E|<>9Q5^eQ2IlJl0!F)W?7C3x
z_c-X07*}VJ9t+|#P@P~HFc+v#9lNDt2t=DP@1HZeVI_?vkCLHy?pfcF8I#M3fN_SwkG8pQ^EO0BtH|NxQBD96
zOEuv24lTJ6v>1^tie*Y==HS=|Tztoi2Hm)r0F(Rl!93v0u%m^Ff@)6n3q7h$Bd0&`
z$!=7829H+bdrikvY0`&u5qFdt*#?_&>;Wzb)os9sh8UHMV+SH4YQ_An$5CBra64Pw
z-0P|3w|*D&!&ZpweqcZ|?Q0FX`5_Q7)Ie2d7+&a^J^kOtpqD=BV@|!=_jXk8Zvlw@
zIQHmf(%WAXTPm%`v1hw-oXY3A9Yxhte0wMR;ay#`ez`MpM_%nq+X-7a{rYXIP|XHS
zq>}hJ&{j8%{Jp{kCGlp=uxfp>-lJa?}}-W_h*1q@ZAGfn&Fi
zi%sS{v9~*_xf7IfbWJY<+64b_7*Gz&Bn2xZE?nz{qU}N
zsyfRBNXUj(AX20%Th6Y$<7~5&4qlgKp#xN8qKe#WNDabe5{~^^tEH}4zxdZMRM)6T
ziVKkN$bJmbQWYszkt$Ry6={!1PgU)YNR}b8M@uCz0LT7kJnM`9zCv|<&63`2GN*3;
z>v^Iuz_m19#zcKKi}QT_kQC$Cqg=>i%Zd**OL}YO)a}$3_W6;j_5${Q4Mm7uKu!~g
z3;17@xTLnQPiS{`o_yt&>k+vY^dsPO3l?7sYzz{>8-ePujPT-@chbg}=A$xKRfnrc
z3Zh9W;#CnVXa|aFKt<{iIisShRAioRy!XGCU6CyH{=Z$ax&IGeeVk_9GDb!K0000<
KMNUMnLSTYDWz>lP
literal 0
HcmV?d00001
diff --git a/vendor/github.com/refraction-networking/utls/prf.go b/vendor/github.com/refraction-networking/utls/prf.go
new file mode 100644
index 00000000..2c638ba8
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/prf.go
@@ -0,0 +1,297 @@
+// 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 tls
+
+import (
+ "crypto"
+ "crypto/hmac"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "errors"
+ "fmt"
+ "hash"
+
+ "github.com/refraction-networking/utls/internal/tls12"
+)
+
+type prfFunc func(secret []byte, label string, seed []byte, keyLen int) []byte
+
+// Split a premaster secret in two as specified in RFC 4346, Section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+ s1 = secret[0 : (len(secret)+1)/2]
+ s2 = secret[len(secret)/2:]
+ return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, Section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+ h := hmac.New(hash, secret)
+ h.Write(seed)
+ a := h.Sum(nil)
+
+ j := 0
+ for j < len(result) {
+ h.Reset()
+ h.Write(a)
+ h.Write(seed)
+ b := h.Sum(nil)
+ copy(result[j:], b)
+ j += len(b)
+
+ h.Reset()
+ h.Write(a)
+ a = h.Sum(nil)
+ }
+}
+
+// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, Section 5.
+func prf10(secret []byte, label string, seed []byte, keyLen int) []byte {
+ result := make([]byte, keyLen)
+ hashSHA1 := sha1.New
+ hashMD5 := md5.New
+
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ s1, s2 := splitPreMasterSecret(secret)
+ pHash(result, s1, labelAndSeed, hashMD5)
+ result2 := make([]byte, len(result))
+ pHash(result2, s2, labelAndSeed, hashSHA1)
+
+ for i, b := range result2 {
+ result[i] ^= b
+ }
+
+ return result
+}
+
+// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, Section 5.
+func prf12(hashFunc func() hash.Hash) prfFunc {
+ return func(secret []byte, label string, seed []byte, keyLen int) []byte {
+ return tls12.PRF(hashFunc, secret, label, seed, keyLen)
+ }
+}
+
+const (
+ masterSecretLength = 48 // Length of a master secret in TLS 1.1.
+ finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+const masterSecretLabel = "master secret"
+const extendedMasterSecretLabel = "extended master secret"
+const keyExpansionLabel = "key expansion"
+const clientFinishedLabel = "client finished"
+const serverFinishedLabel = "server finished"
+
+func prfAndHashForVersion(version uint16, suite *cipherSuite) (prfFunc, crypto.Hash) {
+ switch version {
+ case VersionTLS10, VersionTLS11:
+ return prf10, crypto.Hash(0)
+ case VersionTLS12:
+ if suite.flags&suiteSHA384 != 0 {
+ return prf12(sha512.New384), crypto.SHA384
+ }
+ return prf12(sha256.New), crypto.SHA256
+ default:
+ panic("unknown version")
+ }
+}
+
+func prfForVersion(version uint16, suite *cipherSuite) prfFunc {
+ prf, _ := prfAndHashForVersion(version, suite)
+ return prf
+}
+
+// masterFromPreMasterSecret generates the master secret from the pre-master
+// secret. See RFC 5246, Section 8.1.
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+ seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
+ seed = append(seed, clientRandom...)
+ seed = append(seed, serverRandom...)
+
+ return prfForVersion(version, suite)(preMasterSecret, masterSecretLabel, seed, masterSecretLength)
+}
+
+// extMasterFromPreMasterSecret generates the extended master secret from the
+// pre-master secret. See RFC 7627.
+func extMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, transcript []byte) []byte {
+ prf, hash := prfAndHashForVersion(version, suite)
+ if version == VersionTLS12 {
+ // Use the FIPS 140-3 module only for TLS 1.2 with EMS, which is the
+ // only TLS 1.0-1.2 approved mode per IG D.Q.
+ return tls12.MasterSecret(hash.New, preMasterSecret, transcript)
+ }
+ return prf(preMasterSecret, extendedMasterSecretLabel, transcript, masterSecretLength)
+}
+
+// keysFromMasterSecret generates the connection keys from the master
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, Section 6.3.
+func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+ seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
+ seed = append(seed, serverRandom...)
+ seed = append(seed, clientRandom...)
+
+ n := 2*macLen + 2*keyLen + 2*ivLen
+ keyMaterial := prfForVersion(version, suite)(masterSecret, keyExpansionLabel, seed, n)
+ clientMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ serverMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ clientKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ serverKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ clientIV = keyMaterial[:ivLen]
+ keyMaterial = keyMaterial[ivLen:]
+ serverIV = keyMaterial[:ivLen]
+ return
+}
+
+func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+ var buffer []byte
+ if version >= VersionTLS12 {
+ buffer = []byte{}
+ }
+
+ prf, hash := prfAndHashForVersion(version, cipherSuite)
+ if hash != 0 {
+ return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
+ }
+
+ return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+ client hash.Hash
+ server hash.Hash
+
+ // Prior to TLS 1.2, an additional MD5 hash is required.
+ clientMD5 hash.Hash
+ serverMD5 hash.Hash
+
+ // In TLS 1.2, a full buffer is sadly required.
+ buffer []byte
+
+ version uint16
+ prf prfFunc
+}
+
+func (h *finishedHash) Write(msg []byte) (n int, err error) {
+ h.client.Write(msg)
+ h.server.Write(msg)
+
+ if h.version < VersionTLS12 {
+ h.clientMD5.Write(msg)
+ h.serverMD5.Write(msg)
+ }
+
+ if h.buffer != nil {
+ h.buffer = append(h.buffer, msg...)
+ }
+
+ return len(msg), nil
+}
+
+func (h finishedHash) Sum() []byte {
+ if h.version >= VersionTLS12 {
+ return h.client.Sum(nil)
+ }
+
+ out := make([]byte, 0, md5.Size+sha1.Size)
+ out = h.clientMD5.Sum(out)
+ return h.client.Sum(out)
+}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(masterSecret []byte) []byte {
+ return h.prf(masterSecret, clientFinishedLabel, h.Sum(), finishedVerifyLength)
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(masterSecret []byte) []byte {
+ return h.prf(masterSecret, serverFinishedLabel, h.Sum(), finishedVerifyLength)
+}
+
+// hashForClientCertificate returns the handshake messages so far, pre-hashed if
+// necessary, suitable for signing by a TLS client certificate.
+func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash) []byte {
+ if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil {
+ panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer")
+ }
+
+ if sigType == signatureEd25519 {
+ return h.buffer
+ }
+
+ if h.version >= VersionTLS12 {
+ hash := hashAlg.New()
+ hash.Write(h.buffer)
+ return hash.Sum(nil)
+ }
+
+ if sigType == signatureECDSA {
+ return h.server.Sum(nil)
+ }
+
+ return h.Sum()
+}
+
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+ h.buffer = nil
+}
+
+// noEKMBecauseRenegotiation is used as a value of
+// ConnectionState.ekm when renegotiation is enabled and thus
+// we wish to fail all key-material export requests.
+func noEKMBecauseRenegotiation(label string, context []byte, length int) ([]byte, error) {
+ return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
+}
+
+// noEKMBecauseNoEMS is used as a value of ConnectionState.ekm when Extended
+// Master Secret is not negotiated and thus we wish to fail all key-material
+// export requests.
+func noEKMBecauseNoEMS(label string, context []byte, length int) ([]byte, error) {
+ return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when neither TLS 1.3 nor Extended Master Secret are negotiated; override with GODEBUG=tlsunsafeekm=1")
+}
+
+// ekmFromMasterSecret generates exported keying material as defined in RFC 5705.
+func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
+ return func(label string, context []byte, length int) ([]byte, error) {
+ switch label {
+ case "client finished", "server finished", "master secret", "key expansion":
+ // These values are reserved and may not be used.
+ return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label)
+ }
+
+ seedLen := len(serverRandom) + len(clientRandom)
+ if context != nil {
+ seedLen += 2 + len(context)
+ }
+ seed := make([]byte, 0, seedLen)
+
+ seed = append(seed, clientRandom...)
+ seed = append(seed, serverRandom...)
+
+ if context != nil {
+ if len(context) >= 1<<16 {
+ return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long")
+ }
+ seed = append(seed, byte(len(context)>>8), byte(len(context)))
+ seed = append(seed, context...)
+ }
+
+ return prfForVersion(version, suite)(masterSecret, label, seed, length), nil
+ }
+}
diff --git a/vendor/github.com/refraction-networking/utls/quic.go b/vendor/github.com/refraction-networking/utls/quic.go
new file mode 100644
index 00000000..ba8a235d
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/quic.go
@@ -0,0 +1,500 @@
+// Copyright 2023 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 tls
+
+import (
+ "context"
+ "errors"
+ "fmt"
+)
+
+// QUICEncryptionLevel represents a QUIC encryption level used to transmit
+// handshake messages.
+type QUICEncryptionLevel int
+
+const (
+ QUICEncryptionLevelInitial = QUICEncryptionLevel(iota)
+ QUICEncryptionLevelEarly
+ QUICEncryptionLevelHandshake
+ QUICEncryptionLevelApplication
+)
+
+func (l QUICEncryptionLevel) String() string {
+ switch l {
+ case QUICEncryptionLevelInitial:
+ return "Initial"
+ case QUICEncryptionLevelEarly:
+ return "Early"
+ case QUICEncryptionLevelHandshake:
+ return "Handshake"
+ case QUICEncryptionLevelApplication:
+ return "Application"
+ default:
+ return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l))
+ }
+}
+
+// A QUICConn represents a connection which uses a QUIC implementation as the underlying
+// transport as described in RFC 9001.
+//
+// Methods of QUICConn are not safe for concurrent use.
+type QUICConn struct {
+ conn *Conn
+
+ sessionTicketSent bool
+}
+
+// A QUICConfig configures a [QUICConn].
+type QUICConfig struct {
+ TLSConfig *Config
+
+ // EnableSessionEvents may be set to true to enable the
+ // [QUICStoreSession] and [QUICResumeSession] events for client connections.
+ // When this event is enabled, sessions are not automatically
+ // stored in the client session cache.
+ // The application should use [QUICConn.StoreSession] to store sessions.
+ EnableSessionEvents bool
+}
+
+// A QUICEventKind is a type of operation on a QUIC connection.
+type QUICEventKind int
+
+const (
+ // QUICNoEvent indicates that there are no events available.
+ QUICNoEvent QUICEventKind = iota
+
+ // QUICSetReadSecret and QUICSetWriteSecret provide the read and write
+ // secrets for a given encryption level.
+ // QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set.
+ //
+ // Secrets for the Initial encryption level are derived from the initial
+ // destination connection ID, and are not provided by the QUICConn.
+ QUICSetReadSecret
+ QUICSetWriteSecret
+
+ // QUICWriteData provides data to send to the peer in CRYPTO frames.
+ // QUICEvent.Data is set.
+ QUICWriteData
+
+ // QUICTransportParameters provides the peer's QUIC transport parameters.
+ // QUICEvent.Data is set.
+ QUICTransportParameters
+
+ // QUICTransportParametersRequired indicates that the caller must provide
+ // QUIC transport parameters to send to the peer. The caller should set
+ // the transport parameters with QUICConn.SetTransportParameters and call
+ // QUICConn.NextEvent again.
+ //
+ // If transport parameters are set before calling QUICConn.Start, the
+ // connection will never generate a QUICTransportParametersRequired event.
+ QUICTransportParametersRequired
+
+ // QUICRejectedEarlyData indicates that the server rejected 0-RTT data even
+ // if we offered it. It's returned before QUICEncryptionLevelApplication
+ // keys are returned.
+ // This event only occurs on client connections.
+ QUICRejectedEarlyData
+
+ // QUICHandshakeDone indicates that the TLS handshake has completed.
+ QUICHandshakeDone
+
+ // QUICResumeSession indicates that a client is attempting to resume a previous session.
+ // [QUICEvent.SessionState] is set.
+ //
+ // For client connections, this event occurs when the session ticket is selected.
+ // For server connections, this event occurs when receiving the client's session ticket.
+ //
+ // The application may set [QUICEvent.SessionState.EarlyData] to false before the
+ // next call to [QUICConn.NextEvent] to decline 0-RTT even if the session supports it.
+ QUICResumeSession
+
+ // QUICStoreSession indicates that the server has provided state permitting
+ // the client to resume the session.
+ // [QUICEvent.SessionState] is set.
+ // The application should use [QUICConn.StoreSession] session to store the [SessionState].
+ // The application may modify the [SessionState] before storing it.
+ // This event only occurs on client connections.
+ QUICStoreSession
+)
+
+// A QUICEvent is an event occurring on a QUIC connection.
+//
+// The type of event is specified by the Kind field.
+// The contents of the other fields are kind-specific.
+type QUICEvent struct {
+ Kind QUICEventKind
+
+ // Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
+ Level QUICEncryptionLevel
+
+ // Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
+ // The contents are owned by crypto/tls, and are valid until the next NextEvent call.
+ Data []byte
+
+ // Set for QUICSetReadSecret and QUICSetWriteSecret.
+ Suite uint16
+
+ // Set for QUICResumeSession and QUICStoreSession.
+ SessionState *SessionState
+}
+
+type quicState struct {
+ events []QUICEvent
+ nextEvent int
+
+ // eventArr is a statically allocated event array, large enough to handle
+ // the usual maximum number of events resulting from a single call: transport
+ // parameters, Initial data, Early read secret, Handshake write and read
+ // secrets, Handshake data, Application write secret, Application data.
+ eventArr [8]QUICEvent
+
+ started bool
+ signalc chan struct{} // handshake data is available to be read
+ blockedc chan struct{} // handshake is waiting for data, closed when done
+ cancelc <-chan struct{} // handshake has been canceled
+ cancel context.CancelFunc
+
+ waitingForDrain bool
+
+ // readbuf is shared between HandleData and the handshake goroutine.
+ // HandshakeCryptoData passes ownership to the handshake goroutine by
+ // reading from signalc, and reclaims ownership by reading from blockedc.
+ readbuf []byte
+
+ transportParams []byte // to send to the peer
+
+ enableSessionEvents bool
+}
+
+// QUICClient returns a new TLS client side connection using QUICTransport as the
+// underlying transport. The config cannot be nil.
+//
+// The config's MinVersion must be at least TLS 1.3.
+func QUICClient(config *QUICConfig) *QUICConn {
+ return newQUICConn(Client(nil, config.TLSConfig), config)
+}
+
+// QUICServer returns a new TLS server side connection using QUICTransport as the
+// underlying transport. The config cannot be nil.
+//
+// The config's MinVersion must be at least TLS 1.3.
+func QUICServer(config *QUICConfig) *QUICConn {
+ return newQUICConn(Server(nil, config.TLSConfig), config)
+}
+
+func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
+ conn.quic = &quicState{
+ signalc: make(chan struct{}),
+ blockedc: make(chan struct{}),
+ enableSessionEvents: config.EnableSessionEvents,
+ }
+ conn.quic.events = conn.quic.eventArr[:0]
+ return &QUICConn{
+ conn: conn,
+ }
+}
+
+// Start starts the client or server handshake protocol.
+// It may produce connection events, which may be read with [QUICConn.NextEvent].
+//
+// Start must be called at most once.
+func (q *QUICConn) Start(ctx context.Context) error {
+ if q.conn.quic.started {
+ return quicError(errors.New("tls: Start called more than once"))
+ }
+ q.conn.quic.started = true
+ if q.conn.config.MinVersion < VersionTLS13 {
+ return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.3"))
+ }
+ go q.conn.HandshakeContext(ctx)
+ if _, ok := <-q.conn.quic.blockedc; !ok {
+ return q.conn.handshakeErr
+ }
+ return nil
+}
+
+// NextEvent returns the next event occurring on the connection.
+// It returns an event with a Kind of [QUICNoEvent] when no events are available.
+func (q *QUICConn) NextEvent() QUICEvent {
+ qs := q.conn.quic
+ if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
+ // Write over some of the previous event's data,
+ // to catch callers erroniously retaining it.
+ qs.events[last].Data[0] = 0
+ }
+ if qs.nextEvent >= len(qs.events) && qs.waitingForDrain {
+ qs.waitingForDrain = false
+ <-qs.signalc
+ <-qs.blockedc
+ }
+ if qs.nextEvent >= len(qs.events) {
+ qs.events = qs.events[:0]
+ qs.nextEvent = 0
+ return QUICEvent{Kind: QUICNoEvent}
+ }
+ e := qs.events[qs.nextEvent]
+ qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
+ qs.nextEvent++
+ return e
+}
+
+// Close closes the connection and stops any in-progress handshake.
+func (q *QUICConn) Close() error {
+ if q.conn.quic.cancel == nil {
+ return nil // never started
+ }
+ q.conn.quic.cancel()
+ for range q.conn.quic.blockedc {
+ // Wait for the handshake goroutine to return.
+ }
+ return q.conn.handshakeErr
+}
+
+// HandleData handles handshake bytes received from the peer.
+// It may produce connection events, which may be read with [QUICConn.NextEvent].
+func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
+ c := q.conn
+ if c.in.level != level {
+ return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
+ }
+ c.quic.readbuf = data
+ <-c.quic.signalc
+ _, ok := <-c.quic.blockedc
+ if ok {
+ // The handshake goroutine is waiting for more data.
+ return nil
+ }
+ // The handshake goroutine has exited.
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ c.hand.Write(c.quic.readbuf)
+ c.quic.readbuf = nil
+ for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
+ b := q.conn.hand.Bytes()
+ n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
+ if n > maxHandshake {
+ q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
+ break
+ }
+ if len(b) < 4+n {
+ return nil
+ }
+ if err := q.conn.handlePostHandshakeMessage(); err != nil {
+ q.conn.handshakeErr = err
+ }
+ }
+ if q.conn.handshakeErr != nil {
+ return quicError(q.conn.handshakeErr)
+ }
+ return nil
+}
+
+type QUICSessionTicketOptions struct {
+ // EarlyData specifies whether the ticket may be used for 0-RTT.
+ EarlyData bool
+ Extra [][]byte
+}
+
+// SendSessionTicket sends a session ticket to the client.
+// It produces connection events, which may be read with [QUICConn.NextEvent].
+// Currently, it can only be called once.
+func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
+ c := q.conn
+ if !c.isHandshakeComplete.Load() {
+ return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
+ }
+ if c.isClient {
+ return quicError(errors.New("tls: SendSessionTicket called on the client"))
+ }
+ if q.sessionTicketSent {
+ return quicError(errors.New("tls: SendSessionTicket called multiple times"))
+ }
+ q.sessionTicketSent = true
+ return quicError(c.sendSessionTicket(opts.EarlyData, opts.Extra))
+}
+
+// StoreSession stores a session previously received in a QUICStoreSession event
+// in the ClientSessionCache.
+// The application may process additional events or modify the SessionState
+// before storing the session.
+func (q *QUICConn) StoreSession(session *SessionState) error {
+ c := q.conn
+ if !c.isClient {
+ return quicError(errors.New("tls: StoreSessionTicket called on the server"))
+ }
+ cacheKey := c.clientSessionCacheKey()
+ if cacheKey == "" {
+ return nil
+ }
+ cs := &ClientSessionState{session: session}
+ c.config.ClientSessionCache.Put(cacheKey, cs)
+ return nil
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (q *QUICConn) ConnectionState() ConnectionState {
+ return q.conn.ConnectionState()
+}
+
+// SetTransportParameters sets the transport parameters to send to the peer.
+//
+// Server connections may delay setting the transport parameters until after
+// receiving the client's transport parameters. See [QUICTransportParametersRequired].
+func (q *QUICConn) SetTransportParameters(params []byte) {
+ if params == nil {
+ params = []byte{}
+ }
+ q.conn.quic.transportParams = params
+ if q.conn.quic.started {
+ <-q.conn.quic.signalc
+ <-q.conn.quic.blockedc
+ }
+}
+
+// quicError ensures err is an AlertError.
+// If err is not already, quicError wraps it with alertInternalError.
+func quicError(err error) error {
+ if err == nil {
+ return nil
+ }
+ var ae AlertError
+ if errors.As(err, &ae) {
+ return err
+ }
+ var a alert
+ if !errors.As(err, &a) {
+ a = alertInternalError
+ }
+ // Return an error wrapping the original error and an AlertError.
+ // Truncate the text of the alert to 0 characters.
+ return fmt.Errorf("%w%.0w", err, AlertError(a))
+}
+
+func (c *Conn) quicReadHandshakeBytes(n int) error {
+ for c.hand.Len() < n {
+ if err := c.quicWaitForSignal(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICSetReadSecret,
+ Level: level,
+ Suite: suite,
+ Data: secret,
+ })
+}
+
+func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICSetWriteSecret,
+ Level: level,
+ Suite: suite,
+ Data: secret,
+ })
+}
+
+func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
+ var last *QUICEvent
+ if len(c.quic.events) > 0 {
+ last = &c.quic.events[len(c.quic.events)-1]
+ }
+ if last == nil || last.Kind != QUICWriteData || last.Level != level {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICWriteData,
+ Level: level,
+ })
+ last = &c.quic.events[len(c.quic.events)-1]
+ }
+ last.Data = append(last.Data, data...)
+}
+
+func (c *Conn) quicResumeSession(session *SessionState) error {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICResumeSession,
+ SessionState: session,
+ })
+ c.quic.waitingForDrain = true
+ for c.quic.waitingForDrain {
+ if err := c.quicWaitForSignal(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *Conn) quicStoreSession(session *SessionState) {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICStoreSession,
+ SessionState: session,
+ })
+}
+
+func (c *Conn) quicSetTransportParameters(params []byte) {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICTransportParameters,
+ Data: params,
+ })
+}
+
+func (c *Conn) quicGetTransportParameters() ([]byte, error) {
+ if c.quic.transportParams == nil {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICTransportParametersRequired,
+ })
+ }
+ for c.quic.transportParams == nil {
+ if err := c.quicWaitForSignal(); err != nil {
+ return nil, err
+ }
+ }
+ return c.quic.transportParams, nil
+}
+
+func (c *Conn) quicHandshakeComplete() {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICHandshakeDone,
+ })
+}
+
+func (c *Conn) quicRejectedEarlyData() {
+ c.quic.events = append(c.quic.events, QUICEvent{
+ Kind: QUICRejectedEarlyData,
+ })
+}
+
+// quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
+// and waits for a signal that the handshake should proceed.
+//
+// The handshake may become blocked waiting for handshake bytes
+// or for the user to provide transport parameters.
+func (c *Conn) quicWaitForSignal() error {
+ // Drop the handshake mutex while blocked to allow the user
+ // to call ConnectionState before the handshake completes.
+ c.handshakeMutex.Unlock()
+ defer c.handshakeMutex.Lock()
+ // Send on blockedc to notify the QUICConn that the handshake is blocked.
+ // Exported methods of QUICConn wait for the handshake to become blocked
+ // before returning to the user.
+ select {
+ case c.quic.blockedc <- struct{}{}:
+ case <-c.quic.cancelc:
+ return c.sendAlertLocked(alertCloseNotify)
+ }
+ // The QUICConn reads from signalc to notify us that the handshake may
+ // be able to proceed. (The QUICConn reads, because we close signalc to
+ // indicate that the handshake has completed.)
+ select {
+ case c.quic.signalc <- struct{}{}:
+ c.hand.Write(c.quic.readbuf)
+ c.quic.readbuf = nil
+ case <-c.quic.cancelc:
+ return c.sendAlertLocked(alertCloseNotify)
+ }
+ return nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/ticket.go b/vendor/github.com/refraction-networking/utls/ticket.go
new file mode 100644
index 00000000..4bd263e4
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/ticket.go
@@ -0,0 +1,441 @@
+// Copyright 2012 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 tls
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/sha256"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "io"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// A SessionState is a resumable session.
+type SessionState struct {
+ // Encoded as a SessionState (in the language of RFC 8446, Section 3).
+ //
+ // enum { server(1), client(2) } SessionStateType;
+ //
+ // opaque Certificate<1..2^24-1>;
+ //
+ // Certificate CertificateChain<0..2^24-1>;
+ //
+ // opaque Extra<0..2^24-1>;
+ //
+ // struct {
+ // uint16 version;
+ // SessionStateType type;
+ // uint16 cipher_suite;
+ // uint64 created_at;
+ // opaque secret<1..2^8-1>;
+ // Extra extra<0..2^24-1>;
+ // uint8 ext_master_secret = { 0, 1 };
+ // uint8 early_data = { 0, 1 };
+ // CertificateEntry certificate_list<0..2^24-1>;
+ // CertificateChain verified_chains<0..2^24-1>; /* excluding leaf */
+ // select (SessionState.early_data) {
+ // case 0: Empty;
+ // case 1: opaque alpn<1..2^8-1>;
+ // };
+ // select (SessionState.type) {
+ // case server: Empty;
+ // case client: struct {
+ // select (SessionState.version) {
+ // case VersionTLS10..VersionTLS12: Empty;
+ // case VersionTLS13: struct {
+ // uint64 use_by;
+ // uint32 age_add;
+ // };
+ // };
+ // };
+ // };
+ // } SessionState;
+ //
+
+ // Extra is ignored by crypto/tls, but is encoded by [SessionState.Bytes]
+ // and parsed by [ParseSessionState].
+ //
+ // This allows [Config.UnwrapSession]/[Config.WrapSession] and
+ // [ClientSessionCache] implementations to store and retrieve additional
+ // data alongside this session.
+ //
+ // To allow different layers in a protocol stack to share this field,
+ // applications must only append to it, not replace it, and must use entries
+ // that can be recognized even if out of order (for example, by starting
+ // with an id and version prefix).
+ Extra [][]byte
+
+ // EarlyData indicates whether the ticket can be used for 0-RTT in a QUIC
+ // connection. The application may set this to false if it is true to
+ // decline to offer 0-RTT even if supported.
+ EarlyData bool
+
+ version uint16
+ isClient bool
+ cipherSuite uint16
+ // createdAt is the generation time of the secret on the sever (which for
+ // TLS 1.0–1.2 might be earlier than the current session) and the time at
+ // which the ticket was received on the client.
+ createdAt uint64 // seconds since UNIX epoch
+ secret []byte // master secret for TLS 1.2, or the PSK for TLS 1.3
+ extMasterSecret bool
+ peerCertificates []*x509.Certificate
+ activeCertHandles []*activeCert
+ ocspResponse []byte
+ scts [][]byte
+ verifiedChains [][]*x509.Certificate
+ alpnProtocol string // only set if EarlyData is true
+
+ // Client-side TLS 1.3-only fields.
+ useBy uint64 // seconds since UNIX epoch
+ ageAdd uint32
+ ticket []byte
+}
+
+// Bytes encodes the session, including any private fields, so that it can be
+// parsed by [ParseSessionState]. The encoding contains secret values critical
+// to the security of future and possibly past sessions.
+//
+// The specific encoding should be considered opaque and may change incompatibly
+// between Go versions.
+func (s *SessionState) Bytes() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint16(s.version)
+ if s.isClient {
+ b.AddUint8(2) // client
+ } else {
+ b.AddUint8(1) // server
+ }
+ b.AddUint16(s.cipherSuite)
+ addUint64(&b, s.createdAt)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(s.secret)
+ })
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, extra := range s.Extra {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(extra)
+ })
+ }
+ })
+ if s.extMasterSecret {
+ b.AddUint8(1)
+ } else {
+ b.AddUint8(0)
+ }
+ if s.EarlyData {
+ b.AddUint8(1)
+ } else {
+ b.AddUint8(0)
+ }
+ marshalCertificate(&b, Certificate{
+ Certificate: certificatesToBytesSlice(s.peerCertificates),
+ OCSPStaple: s.ocspResponse,
+ SignedCertificateTimestamps: s.scts,
+ })
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, chain := range s.verifiedChains {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ // We elide the first certificate because it's always the leaf.
+ if len(chain) == 0 {
+ b.SetError(errors.New("tls: internal error: empty verified chain"))
+ return
+ }
+ for _, cert := range chain[1:] {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(cert.Raw)
+ })
+ }
+ })
+ }
+ })
+ if s.EarlyData {
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte(s.alpnProtocol))
+ })
+ }
+ if s.isClient {
+ if s.version >= VersionTLS13 {
+ addUint64(&b, s.useBy)
+ b.AddUint32(s.ageAdd)
+ }
+ }
+ return b.Bytes()
+}
+
+func certificatesToBytesSlice(certs []*x509.Certificate) [][]byte {
+ s := make([][]byte, 0, len(certs))
+ for _, c := range certs {
+ s = append(s, c.Raw)
+ }
+ return s
+}
+
+// ParseSessionState parses a [SessionState] encoded by [SessionState.Bytes].
+func ParseSessionState(data []byte) (*SessionState, error) {
+ ss := &SessionState{}
+ s := cryptobyte.String(data)
+ var typ, extMasterSecret, earlyData uint8
+ var cert Certificate
+ var extra cryptobyte.String
+ if !s.ReadUint16(&ss.version) ||
+ !s.ReadUint8(&typ) ||
+ (typ != 1 && typ != 2) ||
+ !s.ReadUint16(&ss.cipherSuite) ||
+ !readUint64(&s, &ss.createdAt) ||
+ !readUint8LengthPrefixed(&s, &ss.secret) ||
+ !s.ReadUint24LengthPrefixed(&extra) ||
+ !s.ReadUint8(&extMasterSecret) ||
+ !s.ReadUint8(&earlyData) ||
+ len(ss.secret) == 0 ||
+ !unmarshalCertificate(&s, &cert) {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ for !extra.Empty() {
+ var e []byte
+ if !readUint24LengthPrefixed(&extra, &e) {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ ss.Extra = append(ss.Extra, e)
+ }
+ switch extMasterSecret {
+ case 0:
+ ss.extMasterSecret = false
+ case 1:
+ ss.extMasterSecret = true
+ default:
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ switch earlyData {
+ case 0:
+ ss.EarlyData = false
+ case 1:
+ ss.EarlyData = true
+ default:
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ for _, cert := range cert.Certificate {
+ c, err := globalCertCache.newCert(cert)
+ if err != nil {
+ return nil, err
+ }
+ ss.activeCertHandles = append(ss.activeCertHandles, c)
+ ss.peerCertificates = append(ss.peerCertificates, c.cert)
+ }
+ ss.ocspResponse = cert.OCSPStaple
+ ss.scts = cert.SignedCertificateTimestamps
+ var chainList cryptobyte.String
+ if !s.ReadUint24LengthPrefixed(&chainList) {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ for !chainList.Empty() {
+ var certList cryptobyte.String
+ if !chainList.ReadUint24LengthPrefixed(&certList) {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ var chain []*x509.Certificate
+ if len(ss.peerCertificates) == 0 {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ chain = append(chain, ss.peerCertificates[0])
+ for !certList.Empty() {
+ var cert []byte
+ if !readUint24LengthPrefixed(&certList, &cert) {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ c, err := globalCertCache.newCert(cert)
+ if err != nil {
+ return nil, err
+ }
+ ss.activeCertHandles = append(ss.activeCertHandles, c)
+ chain = append(chain, c.cert)
+ }
+ ss.verifiedChains = append(ss.verifiedChains, chain)
+ }
+ if ss.EarlyData {
+ var alpn []byte
+ if !readUint8LengthPrefixed(&s, &alpn) {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ ss.alpnProtocol = string(alpn)
+ }
+ if isClient := typ == 2; !isClient {
+ if !s.Empty() {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ return ss, nil
+ }
+ ss.isClient = true
+ if len(ss.peerCertificates) == 0 {
+ return nil, errors.New("tls: no server certificates in client session")
+ }
+ if ss.version < VersionTLS13 {
+ if !s.Empty() {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ return ss, nil
+ }
+ if !s.ReadUint64(&ss.useBy) || !s.ReadUint32(&ss.ageAdd) || !s.Empty() {
+ return nil, errors.New("tls: invalid session encoding")
+ }
+ return ss, nil
+}
+
+// sessionState returns a partially filled-out [SessionState] with information
+// from the current connection.
+func (c *Conn) sessionState() *SessionState {
+ return &SessionState{
+ version: c.vers,
+ cipherSuite: c.cipherSuite,
+ createdAt: uint64(c.config.time().Unix()),
+ alpnProtocol: c.clientProtocol,
+ peerCertificates: c.peerCertificates,
+ activeCertHandles: c.activeCertHandles,
+ ocspResponse: c.ocspResponse,
+ scts: c.scts,
+ isClient: c.isClient,
+ extMasterSecret: c.extMasterSecret,
+ verifiedChains: c.verifiedChains,
+ }
+}
+
+// EncryptTicket encrypts a ticket with the [Config]'s configured (or default)
+// session ticket keys. It can be used as a [Config.WrapSession] implementation.
+func (c *Config) EncryptTicket(cs ConnectionState, ss *SessionState) ([]byte, error) {
+ ticketKeys := c.ticketKeys(nil)
+ stateBytes, err := ss.Bytes()
+ if err != nil {
+ return nil, err
+ }
+ return c.encryptTicket(stateBytes, ticketKeys)
+}
+
+func (c *Config) encryptTicket(state []byte, ticketKeys []ticketKey) ([]byte, error) {
+ if len(ticketKeys) == 0 {
+ return nil, errors.New("tls: internal error: session ticket keys unavailable")
+ }
+
+ encrypted := make([]byte, aes.BlockSize+len(state)+sha256.Size)
+ iv := encrypted[:aes.BlockSize]
+ ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+ authenticated := encrypted[:len(encrypted)-sha256.Size]
+ macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+ if _, err := io.ReadFull(c.rand(), iv); err != nil {
+ return nil, err
+ }
+ key := ticketKeys[0]
+ block, err := aes.NewCipher(key.aesKey[:])
+ if err != nil {
+ return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
+ }
+ cipher.NewCTR(block, iv).XORKeyStream(ciphertext, state)
+
+ mac := hmac.New(sha256.New, key.hmacKey[:])
+ mac.Write(authenticated)
+ mac.Sum(macBytes[:0])
+
+ return encrypted, nil
+}
+
+// DecryptTicket decrypts a ticket encrypted by [Config.EncryptTicket]. It can
+// be used as a [Config.UnwrapSession] implementation.
+//
+// If the ticket can't be decrypted or parsed, DecryptTicket returns (nil, nil).
+func (c *Config) DecryptTicket(identity []byte, cs ConnectionState) (*SessionState, error) {
+ ticketKeys := c.ticketKeys(nil)
+ stateBytes := c.decryptTicket(identity, ticketKeys)
+ if stateBytes == nil {
+ return nil, nil
+ }
+ s, err := ParseSessionState(stateBytes)
+ if err != nil {
+ return nil, nil // drop unparsable tickets on the floor
+ }
+ return s, nil
+}
+
+func (c *Config) decryptTicket(encrypted []byte, ticketKeys []ticketKey) []byte {
+ if len(encrypted) < aes.BlockSize+sha256.Size {
+ return nil
+ }
+
+ iv := encrypted[:aes.BlockSize]
+ ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+ authenticated := encrypted[:len(encrypted)-sha256.Size]
+ macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+ for _, key := range ticketKeys {
+ mac := hmac.New(sha256.New, key.hmacKey[:])
+ mac.Write(authenticated)
+ expected := mac.Sum(nil)
+
+ if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
+ continue
+ }
+
+ block, err := aes.NewCipher(key.aesKey[:])
+ if err != nil {
+ return nil
+ }
+ plaintext := make([]byte, len(ciphertext))
+ cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
+
+ return plaintext
+ }
+
+ return nil
+}
+
+// ClientSessionState contains the state needed by a client to
+// resume a previous TLS session.
+type ClientSessionState struct {
+ session *SessionState
+}
+
+// ResumptionState returns the session ticket sent by the server (also known as
+// the session's identity) and the state necessary to resume this session.
+//
+// It can be called by [ClientSessionCache.Put] to serialize (with
+// [SessionState.Bytes]) and store the session.
+func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionState, err error) {
+ if cs == nil || cs.session == nil {
+ return nil, nil, nil
+ }
+ return cs.session.ticket, cs.session, nil
+}
+
+// NewResumptionState returns a state value that can be returned by
+// [ClientSessionCache.Get] to resume a previous session.
+//
+// state needs to be returned by [ParseSessionState], and the ticket and session
+// state must have been returned by [ClientSessionState.ResumptionState].
+func NewResumptionState(ticket []byte, state *SessionState) (*ClientSessionState, error) {
+ state.ticket = ticket
+ return &ClientSessionState{
+ session: state,
+ }, nil
+}
+
+// // DecryptTicketWith decrypts an encrypted session ticket
+// // using a TicketKeys (ie []TicketKey) struct
+// //
+// // usedOldKey will be true if the key used for decryption is
+// // not the first in the []TicketKey slice
+// //
+// // [uTLS] changed to be made public and take a TicketKeys and use a fake conn receiver
+// func DecryptTicketWith(encrypted []byte, tks TicketKeys) (plaintext []byte, usedOldKey bool) {
+// // create fake conn
+// c := &Conn{
+// ticketKeys: tks.ToPrivate(),
+// }
+
+// return c.decryptTicket(encrypted)
+// }
diff --git a/vendor/github.com/refraction-networking/utls/tls.go b/vendor/github.com/refraction-networking/utls/tls.go
new file mode 100644
index 00000000..d76e0008
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/tls.go
@@ -0,0 +1,373 @@
+// 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 tls partially implements TLS 1.2, as specified in RFC 5246,
+// and TLS 1.3, as specified in RFC 8446.
+package tls
+
+// BUG(agl): The crypto/tls package only implements some countermeasures
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "net"
+ "os"
+ "strings"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func Server(conn net.Conn, config *Config) *Conn {
+ c := &Conn{
+ conn: conn,
+ config: config,
+ }
+ c.handshakeFn = c.serverHandshake
+ return c
+}
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// The config cannot be nil: users must set either ServerName or
+// InsecureSkipVerify in the config.
+func Client(conn net.Conn, config *Config) *Conn {
+ c := &Conn{
+ conn: conn,
+ config: config,
+ isClient: true,
+ }
+ c.handshakeFn = c.clientHandshake
+ return c
+}
+
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+ net.Listener
+ config *Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection is of type *Conn.
+func (l *listener) Accept() (net.Conn, error) {
+ c, err := l.Listener.Accept()
+ if err != nil {
+ return nil, err
+ }
+ return Server(c, l.config), nil
+}
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with [Server].
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func NewListener(inner net.Listener, config *Config) net.Listener {
+ l := new(listener)
+ l.Listener = inner
+ l.config = config
+ return l
+}
+
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func Listen(network, laddr string, config *Config) (net.Listener, error) {
+ // If this condition changes, consider updating http.Server.ServeTLS too.
+ if config == nil || len(config.Certificates) == 0 &&
+ config.GetCertificate == nil && config.GetConfigForClient == nil {
+ return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config")
+ }
+ l, err := net.Listen(network, laddr)
+ if err != nil {
+ return nil, err
+ }
+ return NewListener(l, config), nil
+}
+
+type timeoutError struct{}
+
+func (timeoutError) Error() string { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of [Config] for the defaults.
+//
+// DialWithDialer uses context.Background internally; to specify the context,
+// use [Dialer.DialContext] with NetDialer set to the desired dialer.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+ return dial(context.Background(), dialer, network, addr, config)
+}
+
+func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+ if netDialer.Timeout != 0 {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
+ defer cancel()
+ }
+
+ if !netDialer.Deadline.IsZero() {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline)
+ defer cancel()
+ }
+
+ rawConn, err := netDialer.DialContext(ctx, network, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ colonPos := strings.LastIndex(addr, ":")
+ if colonPos == -1 {
+ colonPos = len(addr)
+ }
+ hostname := addr[:colonPos]
+
+ if config == nil {
+ config = defaultConfig()
+ }
+ // If no ServerName is set, infer the ServerName
+ // from the hostname we're connecting to.
+ if config.ServerName == "" {
+ // Make a copy to avoid polluting argument or default.
+ c := config.Clone()
+ c.ServerName = hostname
+ config = c
+ }
+
+ conn := Client(rawConn, config)
+ if err := conn.HandshakeContext(ctx); err != nil {
+ rawConn.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+ return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// Dialer dials TLS connections given a configuration and a Dialer for the
+// underlying connection.
+type Dialer struct {
+ // NetDialer is the optional dialer to use for the TLS connections'
+ // underlying TCP connections.
+ // A nil NetDialer is equivalent to the net.Dialer zero value.
+ NetDialer *net.Dialer
+
+ // Config is the TLS configuration to use for new connections.
+ // A nil configuration is equivalent to the zero
+ // configuration; see the documentation of Config for the
+ // defaults.
+ Config *Config
+}
+
+// Dial connects to the given network address and initiates a TLS
+// handshake, returning the resulting TLS connection.
+//
+// The returned [Conn], if any, will always be of type *[Conn].
+//
+// Dial uses context.Background internally; to specify the context,
+// use [Dialer.DialContext].
+func (d *Dialer) Dial(network, addr string) (net.Conn, error) {
+ return d.DialContext(context.Background(), network, addr)
+}
+
+func (d *Dialer) netDialer() *net.Dialer {
+ if d.NetDialer != nil {
+ return d.NetDialer
+ }
+ return new(net.Dialer)
+}
+
+// DialContext connects to the given network address and initiates a TLS
+// handshake, returning the resulting TLS connection.
+//
+// The provided Context must be non-nil. If the context expires before
+// the connection is complete, an error is returned. Once successfully
+// connected, any expiration of the context will not affect the
+// connection.
+//
+// The returned [Conn], if any, will always be of type *[Conn].
+func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
+ c, err := dial(ctx, d.netDialer(), network, addr, d.Config)
+ if err != nil {
+ // Don't return c (a typed nil) in an interface.
+ return nil, err
+ }
+ return c, nil
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair of
+// files. The files must contain PEM encoded data. The certificate file may
+// contain intermediate certificates following the leaf certificate to form a
+// certificate chain. On successful return, Certificate.Leaf will be populated.
+//
+// Before Go 1.23 Certificate.Leaf was left nil, and the parsed certificate was
+// discarded. This behavior can be re-enabled by setting "x509keypairleaf=0"
+// in the GODEBUG environment variable.
+func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
+ certPEMBlock, err := os.ReadFile(certFile)
+ if err != nil {
+ return Certificate{}, err
+ }
+ keyPEMBlock, err := os.ReadFile(keyFile)
+ if err != nil {
+ return Certificate{}, err
+ }
+ return X509KeyPair(certPEMBlock, keyPEMBlock)
+}
+
+// var x509keypairleaf = godebug.New("x509keypairleaf") [uTLS]
+
+// X509KeyPair parses a public/private key pair from a pair of
+// PEM encoded data. On successful return, Certificate.Leaf will be populated.
+//
+// Before Go 1.23 Certificate.Leaf was left nil, and the parsed certificate was
+// discarded. This behavior can be re-enabled by setting "x509keypairleaf=0"
+// in the GODEBUG environment variable.
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
+ fail := func(err error) (Certificate, error) { return Certificate{}, err }
+
+ var cert Certificate
+ var skippedBlockTypes []string
+ for {
+ var certDERBlock *pem.Block
+ certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
+ if certDERBlock == nil {
+ break
+ }
+ if certDERBlock.Type == "CERTIFICATE" {
+ cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+ } else {
+ skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
+ }
+ }
+
+ if len(cert.Certificate) == 0 {
+ if len(skippedBlockTypes) == 0 {
+ return fail(errors.New("tls: failed to find any PEM data in certificate input"))
+ }
+ if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
+ return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
+ }
+ return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+ }
+
+ skippedBlockTypes = skippedBlockTypes[:0]
+ var keyDERBlock *pem.Block
+ for {
+ keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
+ if keyDERBlock == nil {
+ if len(skippedBlockTypes) == 0 {
+ return fail(errors.New("tls: failed to find any PEM data in key input"))
+ }
+ if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
+ return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key"))
+ }
+ return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+ }
+ if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
+ break
+ }
+ skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
+ }
+
+ // We don't need to parse the public key for TLS, but we so do anyway
+ // to check that it looks sane and matches the private key.
+ x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+ if err != nil {
+ return fail(err)
+ }
+
+ // [uTLS section begins]
+ // if x509keypairleaf.Value() != "0" {
+ // cert.Leaf = x509Cert
+ // } else {
+ // x509keypairleaf.IncNonDefault()
+ // }
+ // [uTLS section ends]
+
+ cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
+ if err != nil {
+ return fail(err)
+ }
+
+ switch pub := x509Cert.PublicKey.(type) {
+ case *rsa.PublicKey:
+ priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
+ if !ok {
+ return fail(errors.New("tls: private key type does not match public key type"))
+ }
+ if pub.N.Cmp(priv.N) != 0 {
+ return fail(errors.New("tls: private key does not match public key"))
+ }
+ case *ecdsa.PublicKey:
+ priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+ if !ok {
+ return fail(errors.New("tls: private key type does not match public key type"))
+ }
+ if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
+ return fail(errors.New("tls: private key does not match public key"))
+ }
+ case ed25519.PublicKey:
+ priv, ok := cert.PrivateKey.(ed25519.PrivateKey)
+ if !ok {
+ return fail(errors.New("tls: private key type does not match public key type"))
+ }
+ if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) {
+ return fail(errors.New("tls: private key does not match public key"))
+ }
+ default:
+ return fail(errors.New("tls: unknown public key algorithm"))
+ }
+
+ return cert, nil
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
+ if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+ return key, nil
+ }
+ if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+ switch key := key.(type) {
+ case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
+ return key, nil
+ default:
+ return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
+ }
+ }
+ if key, err := x509.ParseECPrivateKey(der); err == nil {
+ return key, nil
+ }
+
+ return nil, errors.New("tls: failed to parse private key")
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_alias.go b/vendor/github.com/refraction-networking/utls/u_alias.go
new file mode 100644
index 00000000..a1360c55
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_alias.go
@@ -0,0 +1,39 @@
+package tls
+
+import (
+ "crypto/ecdh"
+)
+
+// This file contains all the alias functions, symbols, names, etc. that
+// was once used in the old version of the library. This is to ensure
+// backwards compatibility with the old version of the library.
+
+// TLS Extensions
+
+// UtlsExtendedMasterSecretExtension is an alias for ExtendedMasterSecretExtension.
+//
+// Deprecated: Use ExtendedMasterSecretExtension instead.
+type UtlsExtendedMasterSecretExtension = ExtendedMasterSecretExtension
+
+// Deprecated: Use KeySharePrivateKeys instead. This type is not used and will be removed in the future.
+// KeySharesParameters serves as a in-memory storage for generated keypairs by UTLS when generating
+// ClientHello. It is used to store both ecdhe and kem keypairs.
+type KeySharesParameters struct{}
+
+func NewKeySharesParameters() *KeySharesParameters { return &KeySharesParameters{} }
+
+func (*KeySharesParameters) AddEcdheKeypair(curveID CurveID, ecdheKey *ecdh.PrivateKey, ecdhePubKey *ecdh.PublicKey) {
+ return
+}
+
+func (*KeySharesParameters) GetEcdheKey(curveID CurveID) (ecdheKey *ecdh.PrivateKey, ok bool) { return }
+
+func (*KeySharesParameters) GetEcdhePubkey(curveID CurveID) (params *ecdh.PublicKey, ok bool) { return }
+
+func (*KeySharesParameters) AddKemKeypair(curveID CurveID, kemKey any, kemPubKey any) {
+ return
+}
+
+func (ksp *KeySharesParameters) GetKemKey(curveID CurveID) (kemKey any, ok bool) { return }
+
+func (ksp *KeySharesParameters) GetKemPubkey(curveID CurveID) (params any, ok bool) { return }
diff --git a/vendor/github.com/refraction-networking/utls/u_clienthello_json.go b/vendor/github.com/refraction-networking/utls/u_clienthello_json.go
new file mode 100644
index 00000000..027e082c
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_clienthello_json.go
@@ -0,0 +1,184 @@
+package tls
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/refraction-networking/utls/dicttls"
+)
+
+var ErrUnknownExtension = errors.New("extension name is unknown to the dictionary")
+
+type ClientHelloSpecJSONUnmarshaler struct {
+ CipherSuites *CipherSuitesJSONUnmarshaler `json:"cipher_suites"`
+ CompressionMethods *CompressionMethodsJSONUnmarshaler `json:"compression_methods"`
+ Extensions *TLSExtensionsJSONUnmarshaler `json:"extensions"`
+ TLSVersMin uint16 `json:"min_vers,omitempty"` // optional
+ TLSVersMax uint16 `json:"max_vers,omitempty"` // optional
+}
+
+func (chsju *ClientHelloSpecJSONUnmarshaler) ClientHelloSpec() ClientHelloSpec {
+ return ClientHelloSpec{
+ CipherSuites: chsju.CipherSuites.CipherSuites(),
+ CompressionMethods: chsju.CompressionMethods.CompressionMethods(),
+ Extensions: chsju.Extensions.Extensions(),
+ TLSVersMin: chsju.TLSVersMin,
+ TLSVersMax: chsju.TLSVersMax,
+ }
+}
+
+type CipherSuitesJSONUnmarshaler struct {
+ cipherSuites []uint16
+}
+
+func (c *CipherSuitesJSONUnmarshaler) UnmarshalJSON(jsonStr []byte) error {
+ var cipherSuiteNames []string
+ if err := json.Unmarshal(jsonStr, &cipherSuiteNames); err != nil {
+ return err
+ }
+
+ for _, name := range cipherSuiteNames {
+ if name == "GREASE" {
+ c.cipherSuites = append(c.cipherSuites, GREASE_PLACEHOLDER)
+ continue
+ }
+
+ if id, ok := dicttls.DictCipherSuiteNameIndexed[name]; ok {
+ c.cipherSuites = append(c.cipherSuites, id)
+ } else {
+ return fmt.Errorf("unknown cipher suite name: %s", name)
+ }
+ }
+
+ return nil
+}
+
+func (c *CipherSuitesJSONUnmarshaler) CipherSuites() []uint16 {
+ return c.cipherSuites
+}
+
+type CompressionMethodsJSONUnmarshaler struct {
+ compressionMethods []uint8
+}
+
+func (c *CompressionMethodsJSONUnmarshaler) UnmarshalJSON(jsonStr []byte) error {
+ var compressionMethodNames []string
+ if err := json.Unmarshal(jsonStr, &compressionMethodNames); err != nil {
+ return err
+ }
+
+ for _, name := range compressionMethodNames {
+ if id, ok := dicttls.DictCompMethNameIndexed[name]; ok {
+ c.compressionMethods = append(c.compressionMethods, id)
+ } else {
+ return fmt.Errorf("unknown compression method name: %s", name)
+ }
+ }
+
+ return nil
+}
+
+func (c *CompressionMethodsJSONUnmarshaler) CompressionMethods() []uint8 {
+ return c.compressionMethods
+}
+
+type TLSExtensionsJSONUnmarshaler struct {
+ AllowUnknownExt bool // if set, unknown extensions will be added as GenericExtension, without recovering ext payload
+ UseRealPSK bool // if set, PSK extension will be real PSK extension, otherwise it will be fake PSK extension
+ extensions []TLSExtensionJSON
+}
+
+func (e *TLSExtensionsJSONUnmarshaler) UnmarshalJSON(jsonStr []byte) error {
+ var accepters []tlsExtensionJSONAccepter
+ if err := json.Unmarshal(jsonStr, &accepters); err != nil {
+ return err
+ }
+
+ var exts []TLSExtensionJSON = make([]TLSExtensionJSON, 0, len(accepters))
+ for _, accepter := range accepters {
+ if accepter.extNameOnly.Name == "GREASE" {
+ exts = append(exts, &UtlsGREASEExtension{})
+ continue
+ }
+
+ if extID, ok := dicttls.DictExtTypeNameIndexed[accepter.extNameOnly.Name]; !ok {
+ return fmt.Errorf("%w: %s", ErrUnknownExtension, accepter.extNameOnly.Name)
+ } else {
+ // get extension type from ID
+ var ext TLSExtension = ExtensionFromID(extID)
+ if ext == nil {
+ if e.AllowUnknownExt {
+ // fallback to generic extension, without recovering ext payload
+ ext = genericExtension(extID, accepter.extNameOnly.Name)
+ } else {
+ return fmt.Errorf("extension %s (%d) is not JSON compatible", accepter.extNameOnly.Name, extID)
+ }
+ }
+
+ switch extID {
+ case extensionPreSharedKey:
+ // PSK extension, need to see if we do real or fake PSK
+ if e.UseRealPSK {
+ ext = &UtlsPreSharedKeyExtension{}
+ } else {
+ ext = &FakePreSharedKeyExtension{}
+ }
+ }
+
+ if extJsonCompatible, ok := ext.(TLSExtensionJSON); ok {
+ exts = append(exts, extJsonCompatible)
+ } else {
+ return fmt.Errorf("extension %s (%d) is not JSON compatible", accepter.extNameOnly.Name, extID)
+ }
+ }
+ }
+
+ // unmashal extensions
+ for idx, ext := range exts {
+ // json.Unmarshal will call the UnmarshalJSON method of the extension
+ if err := json.Unmarshal(accepters[idx].origJsonInput, ext); err != nil {
+ return err
+ }
+ }
+
+ e.extensions = exts
+ return nil
+}
+
+func (e *TLSExtensionsJSONUnmarshaler) Extensions() []TLSExtension {
+ var exts []TLSExtension = make([]TLSExtension, 0, len(e.extensions))
+ for _, ext := range e.extensions {
+ exts = append(exts, ext)
+ }
+ return exts
+}
+
+func genericExtension(id uint16, name string) TLSExtension {
+ var warningMsg string = "WARNING: extension "
+ warningMsg += fmt.Sprintf("%d ", id)
+ if len(name) > 0 {
+ warningMsg += fmt.Sprintf("(%s) ", name)
+ }
+ warningMsg += "is falling back to generic extension"
+ warningMsg += "\n"
+
+ fmt.Fprint(os.Stderr, warningMsg)
+
+ // fallback to generic extension
+ return &GenericExtension{Id: id}
+}
+
+type tlsExtensionJSONAccepter struct {
+ extNameOnly struct {
+ Name string `json:"name"`
+ }
+ origJsonInput []byte
+}
+
+func (t *tlsExtensionJSONAccepter) UnmarshalJSON(jsonStr []byte) error {
+ t.origJsonInput = make([]byte, len(jsonStr))
+ copy(t.origJsonInput, jsonStr)
+ return json.Unmarshal(jsonStr, &t.extNameOnly)
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_common.go b/vendor/github.com/refraction-networking/utls/u_common.go
new file mode 100644
index 00000000..e98c7ce2
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_common.go
@@ -0,0 +1,821 @@
+// Copyright 2017 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/hmac"
+ "crypto/sha512"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "hash"
+ "log"
+
+ "github.com/refraction-networking/utls/internal/helper"
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// Naming convention:
+// Unsupported things are prefixed with "Fake"
+// Things, supported by utls, but not crypto/tls' are prefixed with "utls"
+// Supported things, that have changed their ID are prefixed with "Old"
+// Supported but disabled things are prefixed with "Disabled". We will _enable_ them.
+
+// TLS handshake message types.
+const (
+ utlsTypeEncryptedExtensions uint8 = 8 // implemention incomplete by crypto/tls
+ // https://datatracker.ietf.org/doc/html/rfc8879#section-7.2
+ utlsTypeCompressedCertificate uint8 = 25
+)
+
+// TLS
+const (
+ extensionNextProtoNeg uint16 = 13172 // not IANA assigned. Removed by crypto/tls since Nov 2019
+
+ utlsExtensionPadding uint16 = 21
+ utlsExtensionCompressCertificate uint16 = 27 // https://datatracker.ietf.org/doc/html/rfc8879#section-7.1
+ utlsExtensionApplicationSettings uint16 = 17513 // not IANA assigned
+ utlsExtensionApplicationSettingsNew uint16 = 17613 // not IANA assigned
+ utlsFakeExtensionCustom uint16 = 1234 // not IANA assigned, for ALPS
+ utlsExtensionECH uint16 = 0xfe0d // draft-ietf-tls-esni-17
+ utlsExtensionECHOuterExtensions uint16 = 0xfd00 // draft-ietf-tls-esni-17
+
+ // extensions with 'fake' prefix break connection, if server echoes them back
+ fakeExtensionEncryptThenMAC uint16 = 22
+ fakeExtensionTokenBinding uint16 = 24
+ fakeExtensionDelegatedCredentials uint16 = 34
+ fakeExtensionPreSharedKey uint16 = 41
+ fakeOldExtensionChannelID uint16 = 30031 // not IANA assigned
+ fakeExtensionChannelID uint16 = 30032 // not IANA assigned
+)
+
+const (
+ OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc13)
+ OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc14)
+
+ DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = uint16(0xc024)
+ DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = uint16(0xc028)
+ DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256 = uint16(0x003d)
+
+ FAKE_OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc15) // we can try to craft these ciphersuites
+ FAKE_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = uint16(0x009e) // from existing pieces, if needed
+
+ FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = uint16(0x0033)
+ FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = uint16(0x0039)
+ FAKE_TLS_RSA_WITH_RC4_128_MD5 = uint16(0x0004)
+ FAKE_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = uint16(0x009f)
+ FAKE_TLS_DHE_DSS_WITH_AES_128_CBC_SHA = uint16(0x0032)
+ FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = uint16(0x006b)
+ FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = uint16(0x0067)
+ FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV = uint16(0x00ff)
+
+ // https://docs.microsoft.com/en-us/dotnet/api/system.net.security.tlsciphersuite?view=netcore-3.1
+ FAKE_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = uint16(0xc008)
+)
+
+const (
+ CurveSECP256R1 CurveID = 0x0017
+ CurveSECP384R1 CurveID = 0x0018
+ CurveSECP521R1 CurveID = 0x0019
+ CurveX25519 CurveID = 0x001d
+
+ FakeCurveFFDHE2048 CurveID = 0x0100
+ FakeCurveFFDHE3072 CurveID = 0x0101
+ FakeCurveFFDHE4096 CurveID = 0x0102
+ FakeCurveFFDHE6144 CurveID = 0x0103
+ FakeCurveFFDHE8192 CurveID = 0x0104
+)
+
+const (
+ X25519Kyber768Draft00 CurveID = 0x6399
+
+ FakeCurveX25519Kyber512Draft00 CurveID = 0xfe30
+ FakeCurveX25519Kyber768Draft00Old CurveID = 0xfe31
+ FakeCurveP256Kyber768Draft00 CurveID = 0xfe32
+
+ X25519Kyber512Draft00 CurveID = FakeCurveX25519Kyber512Draft00
+ X25519Kyber768Draft00Old CurveID = FakeCurveX25519Kyber768Draft00Old
+ P256Kyber768Draft00 CurveID = FakeCurveP256Kyber768Draft00
+)
+
+// Other things
+const (
+ fakeRecordSizeLimit uint16 = 0x001c
+)
+
+// newest signatures
+var (
+ FakePKCS1WithSHA224 SignatureScheme = 0x0301
+ FakeECDSAWithSHA224 SignatureScheme = 0x0303
+
+ FakeSHA1WithDSA SignatureScheme = 0x0202
+ FakeSHA256WithDSA SignatureScheme = 0x0402
+
+ // fakeEd25519 = SignatureAndHash{0x08, 0x07}
+ // fakeEd448 = SignatureAndHash{0x08, 0x08}
+)
+
+// fake curves(groups)
+var (
+ FakeFFDHE2048 = uint16(0x0100)
+ FakeFFDHE3072 = uint16(0x0101)
+)
+
+// https://tools.ietf.org/html/draft-ietf-tls-certificate-compression-04
+type CertCompressionAlgo uint16
+
+const (
+ CertCompressionZlib CertCompressionAlgo = 0x0001
+ CertCompressionBrotli CertCompressionAlgo = 0x0002
+ CertCompressionZstd CertCompressionAlgo = 0x0003
+)
+
+const (
+ PskModePlain uint8 = pskModePlain
+ PskModeDHE uint8 = pskModeDHE
+)
+
+type ClientHelloID struct {
+ Client string
+
+ // Version specifies version of a mimicked clients (e.g. browsers).
+ // Not used in randomized, custom handshake, and default Go.
+ Version string
+
+ // Seed is only used for randomized fingerprints to seed PRNG.
+ // Must not be modified once set.
+ Seed *PRNGSeed
+
+ // Weights are only used for randomized fingerprints in func
+ // generateRandomizedSpec(). Must not be modified once set.
+ Weights *Weights
+}
+
+func (p *ClientHelloID) Str() string {
+ return fmt.Sprintf("%s-%s", p.Client, p.Version)
+}
+
+func (p *ClientHelloID) IsSet() bool {
+ return (p.Client == "") && (p.Version == "")
+}
+
+const (
+ // clients
+ helloGolang = "Golang"
+ helloRandomized = "Randomized"
+ helloRandomizedALPN = "Randomized-ALPN"
+ helloRandomizedNoALPN = "Randomized-NoALPN"
+ helloCustom = "Custom"
+ helloFirefox = "Firefox"
+ helloChrome = "Chrome"
+ helloIOS = "iOS"
+ helloAndroid = "Android"
+ helloEdge = "Edge"
+ helloSafari = "Safari"
+ hello360 = "360Browser"
+ helloQQ = "QQBrowser"
+
+ // versions
+ helloAutoVers = "0"
+)
+
+type ClientHelloSpec struct {
+ CipherSuites []uint16 // nil => default
+ CompressionMethods []uint8 // nil => no compression
+ Extensions []TLSExtension // nil => no extensions
+
+ TLSVersMin uint16 // [1.0-1.3] default: parse from .Extensions, if SupportedVersions ext is not present => 1.0
+ TLSVersMax uint16 // [1.2-1.3] default: parse from .Extensions, if SupportedVersions ext is not present => 1.2
+
+ // GreaseStyle: currently only random
+ // sessionID may or may not depend on ticket; nil => random
+ GetSessionID func(ticket []byte) [32]byte
+
+ // TLSFingerprintLink string // ?? link to tlsfingerprint.io for informational purposes
+}
+
+// ReadCipherSuites is a helper function to construct a list of cipher suites from
+// a []byte into []uint16.
+//
+// example: []byte{0x13, 0x01, 0x13, 0x02, 0x13, 0x03} => []uint16{0x1301, 0x1302, 0x1303}
+func (chs *ClientHelloSpec) ReadCipherSuites(b []byte) error {
+ cipherSuites := []uint16{}
+ s := cryptobyte.String(b)
+ for !s.Empty() {
+ var suite uint16
+ if !s.ReadUint16(&suite) {
+ return errors.New("unable to read ciphersuite")
+ }
+ cipherSuites = append(cipherSuites, unGREASEUint16(suite))
+ }
+ chs.CipherSuites = cipherSuites
+ return nil
+}
+
+// ReadCompressionMethods is a helper function to construct a list of compression
+// methods from a []byte into []uint8.
+func (chs *ClientHelloSpec) ReadCompressionMethods(compressionMethods []byte) error {
+ chs.CompressionMethods = compressionMethods
+ return nil
+}
+
+// ReadTLSExtensions is a helper function to construct a list of TLS extensions from
+// a byte slice into []TLSExtension.
+func (chs *ClientHelloSpec) ReadTLSExtensions(b []byte, allowBluntMimicry bool, realPSK bool) error {
+ extensions := cryptobyte.String(b)
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) {
+ return fmt.Errorf("unable to read extension ID")
+ }
+ if !extensions.ReadUint16LengthPrefixed(&extData) {
+ return fmt.Errorf("unable to read data for extension %x", extension)
+ }
+
+ ext := ExtensionFromID(extension)
+ extWriter, ok := ext.(TLSExtensionWriter)
+ if ext != nil && ok { // known extension and implements TLSExtensionWriter properly
+ switch extension {
+ case extensionPreSharedKey:
+ // PSK extension, need to see if we do real or fake PSK
+ if realPSK {
+ extWriter = &UtlsPreSharedKeyExtension{}
+ } else {
+ extWriter = &FakePreSharedKeyExtension{}
+ }
+ case extensionSupportedVersions:
+ chs.TLSVersMin = 0
+ chs.TLSVersMax = 0
+ }
+
+ if _, err := extWriter.Write(extData); err != nil {
+ return err
+ }
+
+ chs.Extensions = append(chs.Extensions, extWriter)
+ } else {
+ if allowBluntMimicry {
+ chs.Extensions = append(chs.Extensions, &GenericExtension{extension, extData})
+ } else {
+ return fmt.Errorf("unsupported extension %d", extension)
+ }
+ }
+ }
+ return nil
+}
+
+func (chs *ClientHelloSpec) AlwaysAddPadding() {
+ alreadyHasPadding := false
+ for idx, ext := range chs.Extensions {
+ if _, ok := ext.(*UtlsPaddingExtension); ok {
+ alreadyHasPadding = true
+ break
+ }
+ if _, ok := ext.(PreSharedKeyExtension); ok {
+ alreadyHasPadding = true // PSK must be last, so we can't append padding after it
+ // instead we will insert padding before PSK
+ chs.Extensions = append(chs.Extensions[:idx], append([]TLSExtension{&UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}}, chs.Extensions[idx:]...)...)
+ break
+ }
+ }
+ if !alreadyHasPadding {
+ chs.Extensions = append(chs.Extensions, &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle})
+ }
+}
+
+// Import TLS ClientHello data from client.tlsfingerprint.io:8443
+//
+// data is a map of []byte with following keys:
+// - cipher_suites: [10, 10, 19, 1, 19, 2, 19, 3, 192, 43, 192, 47, 192, 44, 192, 48, 204, 169, 204, 168, 192, 19, 192, 20, 0, 156, 0, 157, 0, 47, 0, 53]
+// - compression_methods: [0] => null
+// - extensions: [10, 10, 255, 1, 0, 45, 0, 35, 0, 16, 68, 105, 0, 11, 0, 43, 0, 18, 0, 13, 0, 0, 0, 10, 0, 27, 0, 5, 0, 51, 0, 23, 10, 10, 0, 21]
+// - pt_fmts (ec_point_formats): [1, 0] => len: 1, content: 0x00
+// - sig_algs (signature_algorithms): [0, 16, 4, 3, 8, 4, 4, 1, 5, 3, 8, 5, 5, 1, 8, 6, 6, 1] => len: 16, content: 0x0403, 0x0804, 0x0401, 0x0503, 0x0805, 0x0501, 0x0806, 0x0601
+// - supported_versions: [10, 10, 3, 4, 3, 3] => 0x0a0a, 0x0304, 0x0303 (GREASE, TLS 1.3, TLS 1.2)
+// - curves (named_groups, supported_groups): [0, 8, 10, 10, 0, 29, 0, 23, 0, 24] => len: 8, content: GREASE, 0x001d, 0x0017, 0x0018
+// - alpn: [0, 12, 2, 104, 50, 8, 104, 116, 116, 112, 47, 49, 46, 49] => len: 12, content: h2, http/1.1
+// - key_share: [10, 10, 0, 1, 0, 29, 0, 32] => {group: 0x0a0a, len:1}, {group: 0x001d, len:32}
+// - psk_key_exchange_modes: [1] => psk_dhe_ke(0x01)
+// - cert_compression_algs: [2, 0, 2] => brotli (0x0002)
+// - record_size_limit: [0, 255] => 255
+//
+// TLSVersMin/TLSVersMax are set to 0 if supported_versions is present.
+// To prevent conflict, they should be set manually if needed BEFORE calling this function.
+func (chs *ClientHelloSpec) ImportTLSClientHello(data map[string][]byte) error {
+ var tlsExtensionTypes []uint16
+ var err error
+
+ if data["cipher_suites"] == nil {
+ return errors.New("cipher_suites is required")
+ }
+ chs.CipherSuites, err = helper.Uint8to16(data["cipher_suites"])
+ if err != nil {
+ return err
+ }
+
+ if data["compression_methods"] == nil {
+ return errors.New("compression_methods is required")
+ }
+ chs.CompressionMethods = data["compression_methods"]
+
+ if data["extensions"] == nil {
+ return errors.New("extensions is required")
+ }
+ tlsExtensionTypes, err = helper.Uint8to16(data["extensions"])
+ if err != nil {
+ return err
+ }
+
+ for _, extType := range tlsExtensionTypes {
+ extension := ExtensionFromID(extType)
+ extWriter, ok := extension.(TLSExtensionWriter)
+ if !ok {
+ return fmt.Errorf("unsupported extension %d", extType)
+ }
+ if extension == nil || !ok {
+ log.Printf("[Warning] Unsupported extension %d added as a &GenericExtension without Data", extType)
+ chs.Extensions = append(chs.Extensions, &GenericExtension{extType, []byte{}})
+ } else {
+ switch extType {
+ case extensionSupportedPoints:
+ if data["pt_fmts"] == nil {
+ return errors.New("pt_fmts is required")
+ }
+ _, err = extWriter.Write(data["pt_fmts"])
+ if err != nil {
+ return err
+ }
+ case extensionSignatureAlgorithms:
+ if data["sig_algs"] == nil {
+ return errors.New("sig_algs is required")
+ }
+ _, err = extWriter.Write(data["sig_algs"])
+ if err != nil {
+ return err
+ }
+ case extensionSupportedVersions:
+ chs.TLSVersMin = 0
+ chs.TLSVersMax = 0
+
+ if data["supported_versions"] == nil {
+ return errors.New("supported_versions is required")
+ }
+
+ // need to add uint8 length prefix
+ fixedData := make([]byte, len(data["supported_versions"])+1)
+ fixedData[0] = uint8(len(data["supported_versions"]) & 0xff)
+ copy(fixedData[1:], data["supported_versions"])
+ _, err = extWriter.Write(fixedData)
+ if err != nil {
+ return err
+ }
+ case extensionSupportedCurves:
+ if data["curves"] == nil {
+ return errors.New("curves is required")
+ }
+
+ _, err = extWriter.Write(data["curves"])
+ if err != nil {
+ return err
+ }
+ case extensionALPN:
+ if data["alpn"] == nil {
+ return errors.New("alpn is required")
+ }
+
+ _, err = extWriter.Write(data["alpn"])
+ if err != nil {
+ return err
+ }
+ case extensionKeyShare:
+ if data["key_share"] == nil {
+ return errors.New("key_share is required")
+ }
+
+ // need to add (zero) data per each key share, [10, 10, 0, 1] => [10, 10, 0, 1, 0]
+ fixedData := make([]byte, 0)
+ for i := 0; i < len(data["key_share"]); i += 4 {
+ fixedData = append(fixedData, data["key_share"][i:i+4]...)
+ for j := 0; j < int(data["key_share"][i+3]); j++ {
+ fixedData = append(fixedData, 0)
+ }
+ }
+ // add uint16 length prefix
+ fixedData = append([]byte{uint8(len(fixedData) >> 8), uint8(len(fixedData) & 0xff)}, fixedData...)
+
+ _, err = extWriter.Write(fixedData)
+ if err != nil {
+ return err
+ }
+ case extensionPSKModes:
+ if data["psk_key_exchange_modes"] == nil {
+ return errors.New("psk_key_exchange_modes is required")
+ }
+
+ // need to add uint8 length prefix
+ fixedData := make([]byte, len(data["psk_key_exchange_modes"])+1)
+ fixedData[0] = uint8(len(data["psk_key_exchange_modes"]) & 0xff)
+ copy(fixedData[1:], data["psk_key_exchange_modes"])
+ _, err = extWriter.Write(fixedData)
+ if err != nil {
+ return err
+ }
+ case utlsExtensionCompressCertificate:
+ if data["cert_compression_algs"] == nil {
+ return errors.New("cert_compression_algs is required")
+ }
+
+ // need to add uint8 length prefix
+ fixedData := make([]byte, len(data["cert_compression_algs"])+1)
+ fixedData[0] = uint8(len(data["cert_compression_algs"]) & 0xff)
+ copy(fixedData[1:], data["cert_compression_algs"])
+ _, err = extWriter.Write(fixedData)
+ if err != nil {
+ return err
+ }
+ case fakeRecordSizeLimit:
+ if data["record_size_limit"] == nil {
+ return errors.New("record_size_limit is required")
+ }
+
+ _, err = extWriter.Write(data["record_size_limit"]) // uint16 as []byte
+ if err != nil {
+ return err
+ }
+ case utlsExtensionApplicationSettings:
+ // TODO: tlsfingerprint.io should record/provide application settings data
+ extWriter.(*ApplicationSettingsExtension).SupportedProtocols = []string{"h2"}
+ case utlsExtensionApplicationSettingsNew:
+ extWriter.(*ApplicationSettingsExtensionNew).SupportedProtocols = []string{"h2"}
+ case extensionPreSharedKey:
+ log.Printf("[Warning] PSK extension added without data")
+ default:
+ if !isGREASEUint16(extType) {
+ log.Printf("[Warning] extension %d added without data", extType)
+ } /*else {
+ log.Printf("[Warning] GREASE extension added but ID/Data discarded. They will be automatically re-GREASEd on ApplyPreset() call.")
+ }*/
+ }
+ chs.Extensions = append(chs.Extensions, extWriter)
+ }
+ }
+ return nil
+}
+
+// ImportTLSClientHelloFromJSON imports ClientHelloSpec from JSON data from client.tlsfingerprint.io format
+//
+// It calls ImportTLSClientHello internally after unmarshaling JSON data into map[string][]byte
+func (chs *ClientHelloSpec) ImportTLSClientHelloFromJSON(jsonB []byte) error {
+ var data map[string][]byte
+ err := json.Unmarshal(jsonB, &data)
+ if err != nil {
+ return err
+ }
+ return chs.ImportTLSClientHello(data)
+}
+
+// FromRaw converts a ClientHello message in the form of raw bytes into a ClientHelloSpec.
+//
+// ctrlFlags: []bool{bluntMimicry, realPSK}
+func (chs *ClientHelloSpec) FromRaw(raw []byte, ctrlFlags ...bool) error {
+ if chs == nil {
+ return errors.New("cannot unmarshal into nil ClientHelloSpec")
+ }
+
+ var bluntMimicry = false
+ var realPSK = false
+ if len(ctrlFlags) > 0 {
+ bluntMimicry = ctrlFlags[0]
+ }
+ if len(ctrlFlags) > 1 {
+ realPSK = ctrlFlags[1]
+ }
+
+ *chs = ClientHelloSpec{} // reset
+ s := cryptobyte.String(raw)
+
+ var contentType uint8
+ var recordVersion uint16
+ if !s.ReadUint8(&contentType) || // record type
+ !s.ReadUint16(&recordVersion) || !s.Skip(2) { // record version and length
+ return errors.New("unable to read record type, version, and length")
+ }
+
+ if recordType(contentType) != recordTypeHandshake {
+ return errors.New("record is not a handshake")
+ }
+
+ var handshakeVersion uint16
+ var handshakeType uint8
+
+ if !s.ReadUint8(&handshakeType) || !s.Skip(3) || // message type and 3 byte length
+ !s.ReadUint16(&handshakeVersion) || !s.Skip(32) { // 32 byte random
+ return errors.New("unable to read handshake message type, length, and random")
+ }
+
+ if handshakeType != typeClientHello {
+ return errors.New("handshake message is not a ClientHello")
+ }
+
+ chs.TLSVersMin = recordVersion
+ chs.TLSVersMax = handshakeVersion
+
+ var ignoredSessionID cryptobyte.String
+ if !s.ReadUint8LengthPrefixed(&ignoredSessionID) {
+ return errors.New("unable to read session id")
+ }
+
+ // CipherSuites
+ var cipherSuitesBytes cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&cipherSuitesBytes) {
+ return errors.New("unable to read ciphersuites")
+ }
+
+ if err := chs.ReadCipherSuites(cipherSuitesBytes); err != nil {
+ return err
+ }
+
+ // CompressionMethods
+ var compressionMethods cryptobyte.String
+ if !s.ReadUint8LengthPrefixed(&compressionMethods) {
+ return errors.New("unable to read compression methods")
+ }
+
+ if err := chs.ReadCompressionMethods(compressionMethods); err != nil {
+ return err
+ }
+
+ if s.Empty() {
+ // Extensions are optional
+ return nil
+ }
+
+ var extensions cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&extensions) {
+ return errors.New("unable to read extensions data")
+ }
+
+ if err := chs.ReadTLSExtensions(extensions, bluntMimicry, realPSK); err != nil {
+ return err
+ }
+
+ // if extension list includes padding, we update the padding-to-len according to
+ // the raw ClientHello length
+ for _, ext := range chs.Extensions {
+ if _, ok := ext.(*UtlsPaddingExtension); ok {
+ ext.(*UtlsPaddingExtension).GetPaddingLen = AlwaysPadToLen(len(raw) - 5)
+ break
+ }
+ }
+
+ return nil
+}
+
+// UnmarshalJSON unmarshals a ClientHello message in the form of JSON into a ClientHelloSpec.
+func (chs *ClientHelloSpec) UnmarshalJSON(jsonB []byte) error {
+ var chsju ClientHelloSpecJSONUnmarshaler
+ if err := json.Unmarshal(jsonB, &chsju); err != nil {
+ return err
+ }
+
+ *chs = chsju.ClientHelloSpec()
+ return nil
+}
+
+var (
+ // HelloGolang will use default "crypto/tls" handshake marshaling codepath, which WILL
+ // overwrite your changes to Hello(Config, Session are fine).
+ // You might want to call BuildHandshakeState() before applying any changes.
+ // UConn.Extensions will be completely ignored.
+ HelloGolang = ClientHelloID{helloGolang, helloAutoVers, nil, nil}
+
+ // HelloCustom will prepare ClientHello with empty uconn.Extensions so you can fill it with
+ // TLSExtensions manually or use ApplyPreset function
+ HelloCustom = ClientHelloID{helloCustom, helloAutoVers, nil, nil}
+
+ // HelloRandomized* randomly adds/reorders extensions, ciphersuites, etc.
+ HelloRandomized = ClientHelloID{helloRandomized, helloAutoVers, nil, nil}
+ HelloRandomizedALPN = ClientHelloID{helloRandomizedALPN, helloAutoVers, nil, nil}
+ HelloRandomizedNoALPN = ClientHelloID{helloRandomizedNoALPN, helloAutoVers, nil, nil}
+
+ // The rest will will parrot given browser.
+ HelloFirefox_Auto = HelloFirefox_120
+ HelloFirefox_55 = ClientHelloID{helloFirefox, "55", nil, nil}
+ HelloFirefox_56 = ClientHelloID{helloFirefox, "56", nil, nil}
+ HelloFirefox_63 = ClientHelloID{helloFirefox, "63", nil, nil}
+ HelloFirefox_65 = ClientHelloID{helloFirefox, "65", nil, nil}
+ HelloFirefox_99 = ClientHelloID{helloFirefox, "99", nil, nil}
+ HelloFirefox_102 = ClientHelloID{helloFirefox, "102", nil, nil}
+ HelloFirefox_105 = ClientHelloID{helloFirefox, "105", nil, nil}
+ HelloFirefox_120 = ClientHelloID{helloFirefox, "120", nil, nil}
+
+ HelloChrome_Auto = HelloChrome_133
+ HelloChrome_58 = ClientHelloID{helloChrome, "58", nil, nil}
+ HelloChrome_62 = ClientHelloID{helloChrome, "62", nil, nil}
+ HelloChrome_70 = ClientHelloID{helloChrome, "70", nil, nil}
+ HelloChrome_72 = ClientHelloID{helloChrome, "72", nil, nil}
+ HelloChrome_83 = ClientHelloID{helloChrome, "83", nil, nil}
+ HelloChrome_87 = ClientHelloID{helloChrome, "87", nil, nil}
+ HelloChrome_96 = ClientHelloID{helloChrome, "96", nil, nil}
+ HelloChrome_100 = ClientHelloID{helloChrome, "100", nil, nil}
+ HelloChrome_102 = ClientHelloID{helloChrome, "102", nil, nil}
+ HelloChrome_106_Shuffle = ClientHelloID{helloChrome, "106", nil, nil} // TLS Extension shuffler enabled starting from 106
+
+ // Chrome w/ PSK: Chrome start sending this ClientHello after doing TLS 1.3 handshake with the same server.
+ // Beta: PSK extension added. However, uTLS doesn't ship with full PSK support.
+ // Use at your own discretion.
+ HelloChrome_100_PSK = ClientHelloID{helloChrome, "100_PSK", nil, nil}
+ HelloChrome_112_PSK_Shuf = ClientHelloID{helloChrome, "112_PSK", nil, nil}
+ HelloChrome_114_Padding_PSK_Shuf = ClientHelloID{helloChrome, "114_PSK", nil, nil}
+
+ // Chrome w/ Post-Quantum Key Agreement
+ // Beta: PQ extension added. However, uTLS doesn't ship with full PQ support. Use at your own discretion.
+ HelloChrome_115_PQ = ClientHelloID{helloChrome, "115_PQ", nil, nil}
+ HelloChrome_115_PQ_PSK = ClientHelloID{helloChrome, "115_PQ_PSK", nil, nil}
+
+ // Chrome ECH
+ HelloChrome_120 = ClientHelloID{helloChrome, "120", nil, nil}
+ // Chrome w/ Post-Quantum Key Agreement and Encrypted ClientHello
+ HelloChrome_120_PQ = ClientHelloID{helloChrome, "120_PQ", nil, nil}
+ // Chrome w/ ML-KEM curve
+ HelloChrome_131 = ClientHelloID{helloChrome, "131", nil, nil}
+ // Chrome w/ New ALPS codepoint
+ HelloChrome_133 = ClientHelloID{helloChrome, "133", nil, nil}
+
+ HelloIOS_Auto = HelloIOS_14
+ HelloIOS_11_1 = ClientHelloID{helloIOS, "111", nil, nil} // legacy "111" means 11.1
+ HelloIOS_12_1 = ClientHelloID{helloIOS, "12.1", nil, nil}
+ HelloIOS_13 = ClientHelloID{helloIOS, "13", nil, nil}
+ HelloIOS_14 = ClientHelloID{helloIOS, "14", nil, nil}
+
+ HelloAndroid_11_OkHttp = ClientHelloID{helloAndroid, "11", nil, nil}
+
+ HelloEdge_Auto = HelloEdge_85 // HelloEdge_106 seems to be incompatible with this library
+ HelloEdge_85 = ClientHelloID{helloEdge, "85", nil, nil}
+ HelloEdge_106 = ClientHelloID{helloEdge, "106", nil, nil}
+
+ HelloSafari_Auto = HelloSafari_16_0
+ HelloSafari_16_0 = ClientHelloID{helloSafari, "16.0", nil, nil}
+
+ Hello360_Auto = Hello360_7_5 // Hello360_11_0 seems to be incompatible with this library
+ Hello360_7_5 = ClientHelloID{hello360, "7.5", nil, nil}
+ Hello360_11_0 = ClientHelloID{hello360, "11.0", nil, nil}
+
+ HelloQQ_Auto = HelloQQ_11_1
+ HelloQQ_11_1 = ClientHelloID{helloQQ, "11.1", nil, nil}
+)
+
+type Weights struct {
+ Extensions_Append_ALPN float64
+ TLSVersMax_Set_VersionTLS13 float64
+ CipherSuites_Remove_RandomCiphers float64
+ SigAndHashAlgos_Append_ECDSAWithSHA1 float64
+ SigAndHashAlgos_Append_ECDSAWithP521AndSHA512 float64
+ SigAndHashAlgos_Append_PSSWithSHA256 float64
+ SigAndHashAlgos_Append_PSSWithSHA384_PSSWithSHA512 float64
+ CurveIDs_Append_X25519 float64
+ CurveIDs_Append_CurveP521 float64
+ Extensions_Append_Padding float64
+ Extensions_Append_Status float64
+ Extensions_Append_SCT float64
+ Extensions_Append_Reneg float64
+ Extensions_Append_EMS float64
+ FirstKeyShare_Set_CurveP256 float64
+ KeyShare_Append_RandomGroups float64
+ Extensions_Append_ALPS float64
+}
+
+// Do not modify them directly as they may being used. If you
+// want to use your custom weights, please make a copy first.
+var DefaultWeights = Weights{
+ Extensions_Append_ALPN: 0.7,
+ TLSVersMax_Set_VersionTLS13: 0.4,
+ CipherSuites_Remove_RandomCiphers: 0.4,
+ SigAndHashAlgos_Append_ECDSAWithSHA1: 0.63,
+ SigAndHashAlgos_Append_ECDSAWithP521AndSHA512: 0.59,
+ SigAndHashAlgos_Append_PSSWithSHA256: 0.51,
+ SigAndHashAlgos_Append_PSSWithSHA384_PSSWithSHA512: 0.9,
+ CurveIDs_Append_X25519: 0.71,
+ CurveIDs_Append_CurveP521: 0.46,
+ Extensions_Append_Padding: 0.62,
+ Extensions_Append_Status: 0.74,
+ Extensions_Append_SCT: 0.46,
+ Extensions_Append_Reneg: 0.75,
+ Extensions_Append_EMS: 0.77,
+ FirstKeyShare_Set_CurveP256: 0.00, // legacy setting
+ KeyShare_Append_RandomGroups: 0.50,
+ Extensions_Append_ALPS: 0.33,
+}
+
+// based on spec's GreaseStyle, GREASE_PLACEHOLDER may be replaced by another GREASE value
+// https://tools.ietf.org/html/draft-ietf-tls-grease-01
+const GREASE_PLACEHOLDER = 0x0a0a
+
+func isGREASEUint16(v uint16) bool {
+ // First byte is same as second byte
+ // and lowest nibble is 0xa
+ return ((v >> 8) == v&0xff) && v&0xf == 0xa
+}
+
+func unGREASEUint16(v uint16) uint16 {
+ if isGREASEUint16(v) {
+ return GREASE_PLACEHOLDER
+ } else {
+ return v
+ }
+}
+
+// utlsMacSHA384 returns a SHA-384 based MAC. These are only supported in TLS 1.2
+// so the given version is ignored.
+func utlsMacSHA384(key []byte) hash.Hash {
+ return hmac.New(sha512.New384, key)
+}
+
+var utlsSupportedCipherSuites []*cipherSuite
+
+func init() {
+ utlsSupportedCipherSuites = append(cipherSuites, []*cipherSuite{
+ {OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, ecdheRSAKA,
+ suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ {OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12, ecdheECDSAKA,
+ suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ }...)
+}
+
+// EnableWeakCiphers allows utls connections to continue in some cases, when weak cipher was chosen.
+// This provides better compatibility with servers on the web, but weakens security. Feel free
+// to use this option if you establish additional secure connection inside of utls connection.
+// This option does not change the shape of parrots (i.e. same ciphers will be offered either way).
+// Must be called before establishing any connections.
+func EnableWeakCiphers() {
+ utlsSupportedCipherSuites = append(cipherSuites, []*cipherSuite{
+ {DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256, 32, 32, 16, rsaKA,
+ suiteTLS12, cipherAES, macSHA256, nil},
+
+ {DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheECDSAKA,
+ suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, cipherAES, utlsMacSHA384, nil},
+ {DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheRSAKA,
+ suiteECDHE | suiteTLS12 | suiteSHA384, cipherAES, utlsMacSHA384, nil},
+ }...)
+}
+
+func mapSlice[T any, U any](slice []T, transform func(T) U) []U {
+ newSlice := make([]U, 0, len(slice))
+ for _, t := range slice {
+ newSlice = append(newSlice, transform(t))
+ }
+ return newSlice
+}
+
+func panicOnNil(caller string, params ...any) {
+ for i, p := range params {
+ if p == nil {
+ panic(fmt.Sprintf("tls: %s failed: the [%d] parameter is nil", caller, i))
+ }
+ }
+}
+
+func anyTrue[T any](slice []T, predicate func(i int, t *T) bool) bool {
+ for i := 0; i < len(slice); i++ {
+ if predicate(i, &slice[i]) {
+ return true
+ }
+ }
+ return false
+}
+
+func allTrue[T any](slice []T, predicate func(i int, t *T) bool) bool {
+ for i := 0; i < len(slice); i++ {
+ if !predicate(i, &slice[i]) {
+ return false
+ }
+ }
+ return true
+}
+
+func uAssert(condition bool, msg string) {
+ if !condition {
+ panic(msg)
+ }
+}
+
+func sliceEq[T comparable](sliceA []T, sliceB []T) bool {
+ if len(sliceA) != len(sliceB) {
+ return false
+ }
+ for i := 0; i < len(sliceA); i++ {
+ if sliceA[i] != sliceB[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type Initializable interface {
+ // IsInitialized returns a boolean indicating whether the extension has been initialized.
+ // If false is returned, utls will initialize the extension.
+ IsInitialized() bool
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_conn.go b/vendor/github.com/refraction-networking/utls/u_conn.go
new file mode 100644
index 00000000..074b4f3f
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_conn.go
@@ -0,0 +1,984 @@
+// Copyright 2017 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bufio"
+ "bytes"
+ "context"
+ "crypto/cipher"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "hash"
+ "net"
+ "slices"
+ "strconv"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+type ClientHelloBuildStatus int
+
+const NotBuilt ClientHelloBuildStatus = 0
+const BuildByUtls ClientHelloBuildStatus = 1
+const BuildByGoTLS ClientHelloBuildStatus = 2
+
+type UConn struct {
+ *Conn
+
+ Extensions []TLSExtension
+ ClientHelloID ClientHelloID
+ sessionController *sessionController
+
+ clientHelloBuildStatus ClientHelloBuildStatus
+ clientHelloSpec *ClientHelloSpec
+
+ HandshakeState PubClientHandshakeState
+
+ greaseSeed [ssl_grease_last_index]uint16
+
+ omitSNIExtension bool
+
+ // skipResumptionOnNilExtension is copied from `Config.PreferSkipResumptionOnNilExtension`.
+ //
+ // By default, if ClientHelloSpec is predefined or utls-generated (as opposed to HelloCustom), this flag will be updated to true.
+ skipResumptionOnNilExtension bool
+
+ // certCompressionAlgs represents the set of advertised certificate compression
+ // algorithms, as specified in the ClientHello. This is only relevant client-side, for the
+ // server certificate. All other forms of certificate compression are unsupported.
+ certCompressionAlgs []CertCompressionAlgo
+
+ // ech extension is a shortcut to the ECH extension in the Extensions slice if there is one.
+ ech ECHExtension
+
+ // echCtx is the echContex returned by makeClientHello()
+ echCtx *echClientContext
+}
+
+// UClient returns a new uTLS client, with behavior depending on clientHelloID.
+// Config CAN be nil, but make sure to eventually specify ServerName.
+func UClient(conn net.Conn, config *Config, clientHelloID ClientHelloID) *UConn {
+ if config == nil {
+ config = &Config{}
+ }
+ tlsConn := Conn{conn: conn, config: config, isClient: true}
+ handshakeState := PubClientHandshakeState{C: &tlsConn, Hello: &PubClientHelloMsg{}}
+ uconn := UConn{Conn: &tlsConn, ClientHelloID: clientHelloID, HandshakeState: handshakeState}
+ uconn.HandshakeState.uconn = &uconn
+ uconn.handshakeFn = uconn.clientHandshake
+ uconn.sessionController = newSessionController(&uconn)
+ uconn.utls.sessionController = uconn.sessionController
+ uconn.skipResumptionOnNilExtension = config.PreferSkipResumptionOnNilExtension || clientHelloID.Client != helloCustom
+ return &uconn
+}
+
+// BuildHandshakeState behavior varies based on ClientHelloID and
+// whether it was already called before.
+// If HelloGolang:
+//
+// [only once] make default ClientHello and overwrite existing state
+//
+// If any other mimicking ClientHelloID is used:
+//
+// [only once] make ClientHello based on ID and overwrite existing state
+// [each call] apply uconn.Extensions config to internal crypto/tls structures
+// [each call] marshal ClientHello.
+//
+// BuildHandshakeState is automatically called before uTLS performs handshake,
+// and should only be called explicitly to inspect/change fields of
+// default/mimicked ClientHello.
+// With the excpetion of session ticket and psk extensions, which cannot be changed
+// after calling BuildHandshakeState, all other fields can be modified.
+func (uconn *UConn) BuildHandshakeState() error {
+ return uconn.buildHandshakeState(true)
+}
+
+// BuildHandshakeStateWithoutSession is the same as BuildHandshakeState, but does not
+// set the session. This is only useful when you want to inspect the ClientHello before
+// setting the session manually through SetSessionTicketExtension or SetPSKExtension.
+// BuildHandshakeState is automatically called before uTLS performs handshake.
+func (uconn *UConn) BuildHandshakeStateWithoutSession() error {
+ return uconn.buildHandshakeState(false)
+}
+
+func (uconn *UConn) buildHandshakeState(loadSession bool) error {
+ if uconn.ClientHelloID == HelloGolang {
+ if uconn.clientHelloBuildStatus == BuildByGoTLS {
+ return nil
+ }
+ uAssert(uconn.clientHelloBuildStatus == NotBuilt, "BuildHandshakeState failed: invalid call, client hello has already been built by utls")
+
+ // use default Golang ClientHello.
+ hello, keySharePrivate, ech, err := uconn.makeClientHello()
+ if err != nil {
+ return err
+ }
+
+ uconn.HandshakeState.Hello = hello.getPublicPtr()
+ uconn.HandshakeState.State13.KeyShareKeys = keySharePrivate.ToPublic()
+ uconn.HandshakeState.C = uconn.Conn
+ uconn.echCtx = ech
+ uconn.clientHelloBuildStatus = BuildByGoTLS
+ } else {
+ uAssert(uconn.clientHelloBuildStatus == BuildByUtls || uconn.clientHelloBuildStatus == NotBuilt, "BuildHandshakeState failed: invalid call, client hello has already been built by go-tls")
+ if uconn.clientHelloBuildStatus == NotBuilt {
+ err := uconn.applyPresetByID(uconn.ClientHelloID)
+ if err != nil {
+ return err
+ }
+ if uconn.omitSNIExtension {
+ uconn.removeSNIExtension()
+ }
+ }
+
+ err := uconn.ApplyConfig()
+ if err != nil {
+ return err
+ }
+
+ if loadSession {
+ err = uconn.uLoadSession()
+ if err != nil {
+ return err
+ }
+ }
+
+ err = uconn.MarshalClientHello()
+ if err != nil {
+ return err
+ }
+
+ if loadSession {
+ uconn.uApplyPatch()
+ uconn.sessionController.finalCheck()
+ uconn.clientHelloBuildStatus = BuildByUtls
+ }
+
+ }
+ return nil
+}
+
+func (uconn *UConn) uLoadSession() error {
+ if cfg := uconn.config; cfg.SessionTicketsDisabled || cfg.ClientSessionCache == nil {
+ return nil
+ }
+ switch uconn.sessionController.shouldLoadSession() {
+ case shouldReturn:
+ case shouldSetTicket:
+ uconn.sessionController.setSessionTicketToUConn()
+ case shouldSetPsk:
+ uconn.sessionController.setPskToUConn()
+ case shouldLoad:
+ hello := uconn.HandshakeState.Hello.getPrivatePtr()
+ uconn.sessionController.utlsAboutToLoadSession()
+ session, earlySecret, binderKey, err := uconn.loadSession(hello)
+ if session == nil || err != nil {
+ return err
+ }
+ if session.version == VersionTLS12 {
+ // We use the session ticket extension for tls 1.2 session resumption
+ uconn.sessionController.initSessionTicketExt(session, hello.sessionTicket)
+ uconn.sessionController.setSessionTicketToUConn()
+ } else {
+ uconn.sessionController.initPskExt(session, earlySecret, binderKey, hello.pskIdentities)
+ }
+ }
+
+ return nil
+}
+
+func (uconn *UConn) uApplyPatch() {
+ helloLen := len(uconn.HandshakeState.Hello.Raw)
+ if uconn.sessionController.shouldUpdateBinders() {
+ uconn.sessionController.updateBinders()
+ uconn.sessionController.setPskToUConn()
+ }
+ uAssert(helloLen == len(uconn.HandshakeState.Hello.Raw), "tls: uApplyPatch Failed: the patch should never change the length of the marshaled clientHello")
+}
+
+func (uconn *UConn) DidTls12Resume() bool {
+ return uconn.didResume
+}
+
+// SetSessionState sets the session ticket, which may be preshared or fake.
+// If session is nil, the body of session ticket extension will be unset,
+// but the extension itself still MAY be present for mimicking purposes.
+// Session tickets to be reused - use same cache on following connections.
+//
+// Deprecated: This method is deprecated in favor of SetSessionTicketExtension,
+// as it only handles session override of TLS 1.2
+func (uconn *UConn) SetSessionState(session *ClientSessionState) error {
+ sessionTicketExt := &SessionTicketExtension{Initialized: true}
+ if session != nil {
+ sessionTicketExt.Ticket = session.session.ticket
+ sessionTicketExt.Session = session.session
+ }
+ return uconn.SetSessionTicketExtension(sessionTicketExt)
+}
+
+// SetSessionTicket sets the session ticket extension.
+// If extension is nil, this will be a no-op.
+func (uconn *UConn) SetSessionTicketExtension(sessionTicketExt ISessionTicketExtension) error {
+ if uconn.config.SessionTicketsDisabled || uconn.config.ClientSessionCache == nil {
+ return fmt.Errorf("tls: SetSessionTicketExtension failed: session is disabled")
+ }
+ if sessionTicketExt == nil {
+ return nil
+ }
+ return uconn.sessionController.overrideSessionTicketExt(sessionTicketExt)
+}
+
+// SetPskExtension sets the psk extension for tls 1.3 resumption. This is a no-op if the psk is nil.
+func (uconn *UConn) SetPskExtension(pskExt PreSharedKeyExtension) error {
+ if uconn.config.SessionTicketsDisabled || uconn.config.ClientSessionCache == nil {
+ return fmt.Errorf("tls: SetPskExtension failed: session is disabled")
+ }
+ if pskExt == nil {
+ return nil
+ }
+
+ uconn.HandshakeState.Hello.TicketSupported = true
+ return uconn.sessionController.overridePskExt(pskExt)
+}
+
+// If you want session tickets to be reused - use same cache on following connections
+func (uconn *UConn) SetSessionCache(cache ClientSessionCache) {
+ uconn.config.ClientSessionCache = cache
+ uconn.HandshakeState.Hello.TicketSupported = true
+}
+
+// SetClientRandom sets client random explicitly.
+// BuildHandshakeFirst() must be called before SetClientRandom.
+// r must to be 32 bytes long.
+func (uconn *UConn) SetClientRandom(r []byte) error {
+ if len(r) != 32 {
+ return errors.New("Incorrect client random length! Expected: 32, got: " + strconv.Itoa(len(r)))
+ } else {
+ uconn.HandshakeState.Hello.Random = make([]byte, 32)
+ copy(uconn.HandshakeState.Hello.Random, r)
+ return nil
+ }
+}
+
+func (uconn *UConn) SetSNI(sni string) {
+ hname := hostnameInSNI(sni)
+ uconn.config.ServerName = hname
+ for _, ext := range uconn.Extensions {
+ sniExt, ok := ext.(*SNIExtension)
+ if ok {
+ sniExt.ServerName = hname
+ }
+ }
+}
+
+// RemoveSNIExtension removes SNI from the list of extensions sent in ClientHello
+// It returns an error when used with HelloGolang ClientHelloID
+func (uconn *UConn) RemoveSNIExtension() error {
+ if uconn.ClientHelloID == HelloGolang {
+ return fmt.Errorf("cannot call RemoveSNIExtension on a UConn with a HelloGolang ClientHelloID")
+ }
+ uconn.omitSNIExtension = true
+ return nil
+}
+
+func (uconn *UConn) removeSNIExtension() {
+ filteredExts := make([]TLSExtension, 0, len(uconn.Extensions))
+ for _, e := range uconn.Extensions {
+ if _, ok := e.(*SNIExtension); !ok {
+ filteredExts = append(filteredExts, e)
+ }
+ }
+ uconn.Extensions = filteredExts
+}
+
+// Handshake runs the client handshake using given clientHandshakeState
+// Requires hs.hello, and, optionally, hs.session to be set.
+func (c *UConn) Handshake() error {
+ return c.HandshakeContext(context.Background())
+}
+
+// HandshakeContext runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// The provided Context must be non-nil. If the context is canceled before
+// the handshake is complete, the handshake is interrupted and an error is returned.
+// Once the handshake has completed, cancellation of the context will not affect the
+// connection.
+func (c *UConn) HandshakeContext(ctx context.Context) error {
+ // Delegate to unexported method for named return
+ // without confusing documented signature.
+ return c.handshakeContext(ctx)
+}
+
+func (c *UConn) handshakeContext(ctx context.Context) (ret error) {
+ // Fast sync/atomic-based exit if there is no handshake in flight and the
+ // last one succeeded without an error. Avoids the expensive context setup
+ // and mutex for most Read and Write calls.
+ if c.isHandshakeComplete.Load() {
+ return nil
+ }
+
+ handshakeCtx, cancel := context.WithCancel(ctx)
+ // Note: defer this before starting the "interrupter" goroutine
+ // so that we can tell the difference between the input being canceled and
+ // this cancellation. In the former case, we need to close the connection.
+ defer cancel()
+
+ // Start the "interrupter" goroutine, if this context might be canceled.
+ // (The background context cannot).
+ //
+ // The interrupter goroutine waits for the input context to be done and
+ // closes the connection if this happens before the function returns.
+ if c.quic != nil {
+ c.quic.cancelc = handshakeCtx.Done()
+ c.quic.cancel = cancel
+ } else if ctx.Done() != nil {
+ done := make(chan struct{})
+ interruptRes := make(chan error, 1)
+ defer func() {
+ close(done)
+ if ctxErr := <-interruptRes; ctxErr != nil {
+ // Return context error to user.
+ ret = ctxErr
+ }
+ }()
+ go func() {
+ select {
+ case <-handshakeCtx.Done():
+ // Close the connection, discarding the error
+ _ = c.conn.Close()
+ interruptRes <- handshakeCtx.Err()
+ case <-done:
+ interruptRes <- nil
+ }
+ }()
+ }
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ if err := c.handshakeErr; err != nil {
+ return err
+ }
+ if c.isHandshakeComplete.Load() {
+ return nil
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ // [uTLS section begins]
+ if c.isClient {
+ err := c.BuildHandshakeState()
+ if err != nil {
+ return err
+ }
+ }
+ // [uTLS section ends]
+ c.handshakeErr = c.handshakeFn(handshakeCtx)
+ if c.handshakeErr == nil {
+ c.handshakes++
+ } else {
+ // If an error occurred during the hadshake try to flush the
+ // alert that might be left in the buffer.
+ c.flush()
+ }
+
+ if c.handshakeErr == nil && !c.isHandshakeComplete.Load() {
+ c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
+ }
+ if c.handshakeErr != nil && c.isHandshakeComplete.Load() {
+ panic("tls: internal error: handshake returned an error but is marked successful")
+ }
+
+ if c.quic != nil {
+ if c.handshakeErr == nil {
+ c.quicHandshakeComplete()
+ // Provide the 1-RTT read secret now that the handshake is complete.
+ // The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing
+ // the handshake (RFC 9001, Section 5.7).
+ c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret)
+ } else {
+ var a alert
+ c.out.Lock()
+ if !errors.As(c.out.err, &a) {
+ a = alertInternalError
+ }
+ c.out.Unlock()
+ // Return an error which wraps both the handshake error and
+ // any alert error we may have sent, or alertInternalError
+ // if we didn't send an alert.
+ // Truncate the text of the alert to 0 characters.
+ c.handshakeErr = fmt.Errorf("%w%.0w", c.handshakeErr, AlertError(a))
+ }
+ close(c.quic.blockedc)
+ close(c.quic.signalc)
+ }
+
+ return c.handshakeErr
+}
+
+// Copy-pasted from tls.Conn in its entirety. But c.Handshake() is now utls' one, not tls.
+// Write writes data to the connection.
+func (c *UConn) Write(b []byte) (int, error) {
+ // interlock with Close below
+ for {
+ x := c.activeCall.Load()
+ if x&1 != 0 {
+ return 0, net.ErrClosed
+ }
+ if c.activeCall.CompareAndSwap(x, x+2) {
+ defer c.activeCall.Add(-2)
+ break
+ }
+ }
+
+ if err := c.Handshake(); err != nil {
+ return 0, err
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if err := c.out.err; err != nil {
+ return 0, err
+ }
+
+ if !c.isHandshakeComplete.Load() {
+ return 0, alertInternalError
+ }
+
+ if c.closeNotifySent {
+ return 0, errShutdown
+ }
+
+ // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
+ // attack when using block mode ciphers due to predictable IVs.
+ // This can be prevented by splitting each Application Data
+ // record into two records, effectively randomizing the IV.
+ //
+ // https://www.openssl.org/~bodo/tls-cbc.txt
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=665814
+ // https://www.imperialviolet.org/2012/01/15/beastfollowup.html
+
+ var m int
+ if len(b) > 1 && c.vers <= VersionTLS10 {
+ if _, ok := c.out.cipher.(cipher.BlockMode); ok {
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
+ if err != nil {
+ return n, c.out.setErrorLocked(err)
+ }
+ m, b = 1, b[1:]
+ }
+ }
+
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b)
+ return n + m, c.out.setErrorLocked(err)
+}
+
+func (uconn *UConn) ApplyConfig() error {
+ for _, ext := range uconn.Extensions {
+ err := ext.writeToUConn(uconn)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (uconn *UConn) extensionsList() []uint16 {
+
+ outerExts := []uint16{}
+ for _, ext := range uconn.Extensions {
+ buffer := cryptobyte.String(make([]byte, 2000))
+ ext.Read(buffer)
+ var extension uint16
+ buffer.ReadUint16(&extension)
+ outerExts = append(outerExts, extension)
+ }
+ return outerExts
+}
+
+func (uconn *UConn) computeAndUpdateOuterECHExtension(inner *clientHelloMsg, ech *echClientContext, useKey bool) error {
+ // This function is mostly copied from
+ // https://github.com/refraction-networking/utls/blob/e430876b1d82fdf582efc57f3992d448e7ab3d8a/ech.go#L408
+ var encapKey []byte
+ if useKey {
+ encapKey = ech.encapsulatedKey
+ }
+
+ encodedInner, err := encodeInnerClientHelloReorderOuterExts(inner, int(ech.config.MaxNameLength), uconn.extensionsList())
+ if err != nil {
+ return err
+ }
+
+ encryptedLen := len(encodedInner) + 16
+ outerECHExt, err := generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen))
+ if err != nil {
+ return err
+ }
+
+ echExtIdx := slices.IndexFunc(uconn.Extensions, func(ext TLSExtension) bool {
+ _, ok := ext.(EncryptedClientHelloExtension)
+ return ok
+ })
+ if echExtIdx < 0 {
+ return fmt.Errorf("extension satisfying EncryptedClientHelloExtension not present")
+ }
+ oldExt := uconn.Extensions[echExtIdx]
+
+ uconn.Extensions[echExtIdx] = &GenericExtension{
+ Id: extensionEncryptedClientHello,
+ Data: outerECHExt,
+ }
+
+ if err := uconn.MarshalClientHelloNoECH(); err != nil {
+ return err
+ }
+
+ serializedOuter := uconn.HandshakeState.Hello.Raw
+ serializedOuter = serializedOuter[4:]
+ encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner)
+ if err != nil {
+ return err
+ }
+ outerECHExt, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner)
+ if err != nil {
+ return err
+ }
+ uconn.Extensions[echExtIdx] = &GenericExtension{
+ Id: extensionEncryptedClientHello,
+ Data: outerECHExt,
+ }
+
+ if err := uconn.MarshalClientHelloNoECH(); err != nil {
+ return err
+ }
+
+ uconn.Extensions[echExtIdx] = oldExt
+ return nil
+
+}
+
+func (uconn *UConn) MarshalClientHello() error {
+ if len(uconn.config.EncryptedClientHelloConfigList) > 0 {
+ inner, _, ech, err := uconn.makeClientHello()
+ if err != nil {
+ return err
+ }
+
+ // copy compressed extensions to the ClientHelloInner
+ inner.keyShares = KeyShares(uconn.HandshakeState.Hello.KeyShares).ToPrivate()
+ inner.supportedSignatureAlgorithms = uconn.HandshakeState.Hello.SupportedSignatureAlgorithms
+ inner.sessionId = uconn.HandshakeState.Hello.SessionId
+ inner.supportedCurves = uconn.HandshakeState.Hello.SupportedCurves
+
+ ech.innerHello = inner
+
+ uconn.computeAndUpdateOuterECHExtension(inner, ech, true)
+
+ uconn.echCtx = ech
+ return nil
+ }
+
+ if err := uconn.MarshalClientHelloNoECH(); err != nil {
+ return err
+ }
+
+ return nil
+
+}
+
+// MarshalClientHelloNoECH marshals ClientHello as if there was no
+// ECH extension present.
+func (uconn *UConn) MarshalClientHelloNoECH() error {
+ hello := uconn.HandshakeState.Hello
+ headerLength := 2 + 32 + 1 + len(hello.SessionId) +
+ 2 + len(hello.CipherSuites)*2 +
+ 1 + len(hello.CompressionMethods)
+
+ extensionsLen := 0
+ var paddingExt *UtlsPaddingExtension // reference to padding extension, if present
+ for _, ext := range uconn.Extensions {
+ if pe, ok := ext.(*UtlsPaddingExtension); !ok {
+ // If not padding - just add length of extension to total length
+ extensionsLen += ext.Len()
+ } else {
+ // If padding - process it later
+ if paddingExt == nil {
+ paddingExt = pe
+ } else {
+ return errors.New("multiple padding extensions")
+ }
+ }
+ }
+
+ if paddingExt != nil {
+ // determine padding extension presence and length
+ paddingExt.Update(headerLength + 4 + extensionsLen + 2)
+ extensionsLen += paddingExt.Len()
+ }
+
+ helloLen := headerLength
+ if len(uconn.Extensions) > 0 {
+ helloLen += 2 + extensionsLen // 2 bytes for extensions' length
+ }
+
+ helloBuffer := bytes.Buffer{}
+ bufferedWriter := bufio.NewWriterSize(&helloBuffer, helloLen+4) // 1 byte for tls record type, 3 for length
+ // We use buffered Writer to avoid checking write errors after every Write(): whenever first error happens
+ // Write() will become noop, and error will be accessible via Flush(), which is called once in the end
+
+ binary.Write(bufferedWriter, binary.BigEndian, typeClientHello)
+ helloLenBytes := []byte{byte(helloLen >> 16), byte(helloLen >> 8), byte(helloLen)} // poor man's uint24
+ binary.Write(bufferedWriter, binary.BigEndian, helloLenBytes)
+ binary.Write(bufferedWriter, binary.BigEndian, hello.Vers)
+
+ binary.Write(bufferedWriter, binary.BigEndian, hello.Random)
+
+ binary.Write(bufferedWriter, binary.BigEndian, uint8(len(hello.SessionId)))
+ binary.Write(bufferedWriter, binary.BigEndian, hello.SessionId)
+
+ binary.Write(bufferedWriter, binary.BigEndian, uint16(len(hello.CipherSuites)<<1))
+ for _, suite := range hello.CipherSuites {
+ binary.Write(bufferedWriter, binary.BigEndian, suite)
+ }
+
+ binary.Write(bufferedWriter, binary.BigEndian, uint8(len(hello.CompressionMethods)))
+ binary.Write(bufferedWriter, binary.BigEndian, hello.CompressionMethods)
+
+ if len(uconn.Extensions) > 0 {
+ binary.Write(bufferedWriter, binary.BigEndian, uint16(extensionsLen))
+ for _, ext := range uconn.Extensions {
+ if _, err := bufferedWriter.ReadFrom(ext); err != nil {
+ return err
+ }
+ }
+ }
+
+ err := bufferedWriter.Flush()
+ if err != nil {
+ return err
+ }
+
+ if helloBuffer.Len() != 4+helloLen {
+ return errors.New("utls: unexpected ClientHello length. Expected: " + strconv.Itoa(4+helloLen) +
+ ". Got: " + strconv.Itoa(helloBuffer.Len()))
+ }
+
+ hello.Raw = helloBuffer.Bytes()
+ return nil
+}
+
+// get current state of cipher and encrypt zeros to get keystream
+func (uconn *UConn) GetOutKeystream(length int) ([]byte, error) {
+ zeros := make([]byte, length)
+
+ if outCipher, ok := uconn.out.cipher.(cipher.AEAD); ok {
+ // AEAD.Seal() does not mutate internal state, other ciphers might
+ return outCipher.Seal(nil, uconn.out.seq[:], zeros, nil), nil
+ }
+ return nil, errors.New("could not convert OutCipher to cipher.AEAD")
+}
+
+// SetTLSVers sets min and max TLS version in all appropriate places.
+// Function will use first non-zero version parsed in following order:
+// 1. Provided minTLSVers, maxTLSVers
+// 2. specExtensions may have SupportedVersionsExtension
+// 3. [default] min = TLS 1.0, max = TLS 1.2
+//
+// Error is only returned if things are in clearly undesirable state
+// to help user fix them.
+func (uconn *UConn) SetTLSVers(minTLSVers, maxTLSVers uint16, specExtensions []TLSExtension) error {
+ if minTLSVers == 0 && maxTLSVers == 0 {
+ // if version is not set explicitly in the ClientHelloSpec, check the SupportedVersions extension
+ supportedVersionsExtensionsPresent := 0
+ for _, e := range specExtensions {
+ switch ext := e.(type) {
+ case *SupportedVersionsExtension:
+ findVersionsInSupportedVersionsExtensions := func(versions []uint16) (uint16, uint16) {
+ // returns (minVers, maxVers)
+ minVers := uint16(0)
+ maxVers := uint16(0)
+ for _, vers := range versions {
+ if isGREASEUint16(vers) {
+ continue
+ }
+ if maxVers < vers || maxVers == 0 {
+ maxVers = vers
+ }
+ if minVers > vers || minVers == 0 {
+ minVers = vers
+ }
+ }
+ return minVers, maxVers
+ }
+
+ supportedVersionsExtensionsPresent += 1
+ minTLSVers, maxTLSVers = findVersionsInSupportedVersionsExtensions(ext.Versions)
+ if minTLSVers == 0 && maxTLSVers == 0 {
+ return fmt.Errorf("SupportedVersions extension has invalid Versions field")
+ } // else: proceed
+ }
+ }
+ switch supportedVersionsExtensionsPresent {
+ case 0:
+ // if mandatory for TLS 1.3 extension is not present, just default to 1.2
+ minTLSVers = VersionTLS10
+ maxTLSVers = VersionTLS12
+ case 1:
+ default:
+ return fmt.Errorf("uconn.Extensions contains %v separate SupportedVersions extensions",
+ supportedVersionsExtensionsPresent)
+ }
+ }
+
+ if minTLSVers < VersionTLS10 || minTLSVers > VersionTLS13 {
+ return fmt.Errorf("uTLS does not support 0x%X as min version", minTLSVers)
+ }
+
+ if maxTLSVers < VersionTLS10 || maxTLSVers > VersionTLS13 {
+ return fmt.Errorf("uTLS does not support 0x%X as max version", maxTLSVers)
+ }
+
+ uconn.HandshakeState.Hello.SupportedVersions = makeSupportedVersions(minTLSVers, maxTLSVers)
+ if uconn.config.EncryptedClientHelloConfigList == nil {
+ uconn.config.MinVersion = minTLSVers
+ uconn.config.MaxVersion = maxTLSVers
+ }
+
+ return nil
+}
+
+func (uconn *UConn) SetUnderlyingConn(c net.Conn) {
+ uconn.Conn.conn = c
+}
+
+func (uconn *UConn) GetUnderlyingConn() net.Conn {
+ return uconn.Conn.conn
+}
+
+// MakeConnWithCompleteHandshake allows to forge both server and client side TLS connections.
+// Major Hack Alert.
+func MakeConnWithCompleteHandshake(tcpConn net.Conn, version uint16, cipherSuite uint16, masterSecret []byte, clientRandom []byte, serverRandom []byte, isClient bool) *Conn {
+ tlsConn := &Conn{conn: tcpConn, config: &Config{}, isClient: isClient}
+ cs := cipherSuiteByID(cipherSuite)
+ if cs != nil {
+ // This is mostly borrowed from establishKeys()
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(version, cs, masterSecret, clientRandom, serverRandom,
+ cs.macLen, cs.keyLen, cs.ivLen)
+
+ var clientCipher, serverCipher interface{}
+ var clientHash, serverHash hash.Hash
+ if cs.cipher != nil {
+ clientCipher = cs.cipher(clientKey, clientIV, true /* for reading */)
+ clientHash = cs.mac(clientMAC)
+ serverCipher = cs.cipher(serverKey, serverIV, false /* not for reading */)
+ serverHash = cs.mac(serverMAC)
+ } else {
+ clientCipher = cs.aead(clientKey, clientIV)
+ serverCipher = cs.aead(serverKey, serverIV)
+ }
+
+ if isClient {
+ tlsConn.in.prepareCipherSpec(version, serverCipher, serverHash)
+ tlsConn.out.prepareCipherSpec(version, clientCipher, clientHash)
+ } else {
+ tlsConn.in.prepareCipherSpec(version, clientCipher, clientHash)
+ tlsConn.out.prepareCipherSpec(version, serverCipher, serverHash)
+ }
+
+ // skip the handshake states
+ tlsConn.isHandshakeComplete.Store(true)
+ tlsConn.cipherSuite = cipherSuite
+ tlsConn.haveVers = true
+ tlsConn.vers = version
+
+ // Update to the new cipher specs
+ // and consume the finished messages
+ tlsConn.in.changeCipherSpec()
+ tlsConn.out.changeCipherSpec()
+
+ tlsConn.in.incSeq()
+ tlsConn.out.incSeq()
+
+ return tlsConn
+ } else {
+ // TODO: Support TLS 1.3 Cipher Suites
+ return nil
+ }
+}
+
+func makeSupportedVersions(minVers, maxVers uint16) []uint16 {
+ a := make([]uint16, maxVers-minVers+1)
+ for i := range a {
+ a[i] = maxVers - uint16(i)
+ }
+ return a
+}
+
+// Extending (*Conn).readHandshake() to support more customized handshake messages.
+func (c *Conn) utlsHandshakeMessageType(msgType byte) (handshakeMessage, error) {
+ switch msgType {
+ case utlsTypeCompressedCertificate:
+ return new(utlsCompressedCertificateMsg), nil
+ case utlsTypeEncryptedExtensions:
+ if c.isClient {
+ return new(encryptedExtensionsMsg), nil
+ } else {
+ return new(utlsClientEncryptedExtensionsMsg), nil
+ }
+ default:
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+}
+
+// Extending (*Conn).connectionStateLocked()
+func (c *Conn) utlsConnectionStateLocked(state *ConnectionState) {
+ state.PeerApplicationSettings = c.utls.peerApplicationSettings
+}
+
+type utlsConnExtraFields struct {
+ // Application Settings (ALPS)
+ peerApplicationSettings []byte
+ localApplicationSettings []byte
+ applicationSettingsCodepoint uint16
+
+ sessionController *sessionController
+}
+
+// Read reads data from the connection.
+//
+// As Read calls [Conn.Handshake], in order to prevent indefinite blocking a deadline
+// must be set for both Read and [Conn.Write] before Read is called when the handshake
+// has not yet completed. See [Conn.SetDeadline], [Conn.SetReadDeadline], and
+// [Conn.SetWriteDeadline].
+func (c *UConn) Read(b []byte) (int, error) {
+ if err := c.Handshake(); err != nil {
+ return 0, err
+ }
+ if len(b) == 0 {
+ // Put this after Handshake, in case people were calling
+ // Read(nil) for the side effect of the Handshake.
+ return 0, nil
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ for c.input.Len() == 0 {
+ if err := c.readRecord(); err != nil {
+ return 0, err
+ }
+ for c.hand.Len() > 0 {
+ if err := c.handlePostHandshakeMessage(); err != nil {
+ return 0, err
+ }
+ }
+ }
+
+ n, _ := c.input.Read(b)
+
+ // If a close-notify alert is waiting, read it so that we can return (n,
+ // EOF) instead of (n, nil), to signal to the HTTP response reading
+ // goroutine that the connection is now closed. This eliminates a race
+ // where the HTTP response reading goroutine would otherwise not observe
+ // the EOF until its next read, by which time a client goroutine might
+ // have already tried to reuse the HTTP connection for a new request.
+ // See https://golang.org/cl/76400046 and https://golang.org/issue/3514
+ if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
+ recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
+ if err := c.readRecord(); err != nil {
+ return n, err // will be io.EOF on closeNotify
+ }
+ }
+
+ return n, nil
+}
+
+// handleRenegotiation processes a HelloRequest handshake message.
+func (c *UConn) handleRenegotiation() error {
+ if c.vers == VersionTLS13 {
+ return errors.New("tls: internal error: unexpected renegotiation")
+ }
+
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ helloReq, ok := msg.(*helloRequestMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(helloReq, msg)
+ }
+
+ if !c.isClient {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+
+ switch c.config.Renegotiation {
+ case RenegotiateNever:
+ return c.sendAlert(alertNoRenegotiation)
+ case RenegotiateOnceAsClient:
+ if c.handshakes > 1 {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+ case RenegotiateFreelyAsClient:
+ // Ok.
+ default:
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: unknown Renegotiation value")
+ }
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ c.isHandshakeComplete.Store(false)
+
+ // [uTLS section begins]
+ if err = c.BuildHandshakeState(); err != nil {
+ return err
+ }
+ // [uTLS section ends]
+ if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
+ c.handshakes++
+ }
+ return c.handshakeErr
+}
+
+// handlePostHandshakeMessage processes a handshake message arrived after the
+// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation.
+func (c *UConn) handlePostHandshakeMessage() error {
+ if c.vers != VersionTLS13 {
+ return c.handleRenegotiation()
+ }
+
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ c.retryCount++
+ if c.retryCount > maxUselessRecords {
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(errors.New("tls: too many non-advancing records"))
+ }
+
+ switch msg := msg.(type) {
+ case *newSessionTicketMsgTLS13:
+ return c.handleNewSessionTicket(msg)
+ case *keyUpdateMsg:
+ return c.handleKeyUpdate(msg)
+ }
+ // The QUIC layer is supposed to treat an unexpected post-handshake CertificateRequest
+ // as a QUIC-level PROTOCOL_VIOLATION error (RFC 9001, Section 4.4). Returning an
+ // unexpected_message alert here doesn't provide it with enough information to distinguish
+ // this condition from other unexpected messages. This is probably fine.
+ c.sendAlert(alertUnexpectedMessage)
+ return fmt.Errorf("tls: received unexpected handshake message of type %T", msg)
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_ech.go b/vendor/github.com/refraction-networking/utls/u_ech.go
new file mode 100644
index 00000000..27392a29
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_ech.go
@@ -0,0 +1,306 @@
+package tls
+
+import (
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "sync"
+
+ "github.com/refraction-networking/utls/dicttls"
+ "github.com/refraction-networking/utls/internal/hpke"
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// Unstable API: This is a work in progress and may change in the future. Using
+// it in your application may cause your application to break when updating to
+// a new version of uTLS.
+
+const (
+ OuterClientHello byte = 0x00
+ InnerClientHello byte = 0x01
+)
+
+type EncryptedClientHelloExtension interface {
+ // TLSExtension must be implemented by all EncryptedClientHelloExtension implementations.
+ TLSExtension
+
+ // MarshalClientHello is called by (*UConn).MarshalClientHello() when an ECH extension
+ // is present to allow the ECH extension to take control of the generation of the
+ // entire ClientHello message.
+ MarshalClientHello(*UConn) error
+
+ mustEmbedUnimplementedECHExtension()
+}
+
+type ECHExtension = EncryptedClientHelloExtension // alias
+
+// type guard: GREASEEncryptedClientHelloExtension must implement EncryptedClientHelloExtension
+var (
+ _ EncryptedClientHelloExtension = (*GREASEEncryptedClientHelloExtension)(nil)
+
+ _ EncryptedClientHelloExtension = (*UnimplementedECHExtension)(nil)
+)
+
+type GREASEEncryptedClientHelloExtension struct {
+ CandidateCipherSuites []HPKESymmetricCipherSuite
+ cipherSuite HPKESymmetricCipherSuite // randomly picked from CandidateCipherSuites or generated if empty
+ CandidateConfigIds []uint8
+ configId uint8 // randomly picked from CandidateConfigIds or generated if empty
+ EncapsulatedKey []byte // if empty, will generate random bytes
+ CandidatePayloadLens []uint16 // Pre-encryption. If 0, will pick 128(+16=144)
+ payload []byte // payload should be calculated ONCE and stored here, HRR will reuse this
+
+ initOnce sync.Once
+
+ UnimplementedECHExtension
+}
+
+type GREASEECHExtension = GREASEEncryptedClientHelloExtension // alias
+
+// init initializes the GREASEEncryptedClientHelloExtension with random values if they are not set.
+//
+// Based on cloudflare/go's echGenerateGreaseExt()
+func (g *GREASEEncryptedClientHelloExtension) init() error {
+ var initErr error
+ g.initOnce.Do(func() {
+ // Set the config_id field to a random byte.
+ //
+ // Note: must not reuse this extension unless for HRR. It is required
+ // to generate new random bytes for config_id for each new ClientHello,
+ // but reuse the same config_id for HRR.
+ if len(g.CandidateConfigIds) == 0 {
+ var b []byte = make([]byte, 1)
+ _, err := rand.Read(b[:])
+ if err != nil {
+ initErr = fmt.Errorf("error generating random byte for config_id: %w", err)
+ return
+ }
+ g.configId = b[0]
+ } else {
+ // randomly pick one from the list
+ rndIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(g.CandidateConfigIds))))
+ if err != nil {
+ initErr = fmt.Errorf("error generating random index for config_id: %w", err)
+ return
+ }
+ g.configId = g.CandidateConfigIds[rndIndex.Int64()]
+ }
+
+ // Set the cipher_suite field to a supported HpkeSymmetricCipherSuite.
+ // The selection SHOULD vary to exercise all supported configurations,
+ // but MAY be held constant for successive connections to the same server
+ // in the same session.
+ if len(g.CandidateCipherSuites) == 0 {
+ g.cipherSuite = HPKESymmetricCipherSuite{uint16(defaultHpkeKdf), uint16(defaultHpkeAead)}
+ } else {
+ // randomly pick one from the list
+ rndIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(g.CandidateCipherSuites))))
+ if err != nil {
+ initErr = fmt.Errorf("error generating random index for cipher_suite: %w", err)
+ return
+ }
+ g.cipherSuite = HPKESymmetricCipherSuite{
+ g.CandidateCipherSuites[rndIndex.Int64()].KdfId,
+ g.CandidateCipherSuites[rndIndex.Int64()].AeadId,
+ }
+ // aead = hpke.AEAD(g.cipherSuite.AeadId)
+ }
+
+ if len(g.EncapsulatedKey) == 0 {
+ kem := uint16(defaultHpkeKem)
+
+ echPK, err := hpke.ParseHPKEPublicKey(uint16(kem), dummyX25519PublicKey)
+ if err != nil {
+ initErr = fmt.Errorf("tls: grease ech: failed to parse dummy public key: %w", err)
+ return
+ }
+ suite := echCipher{
+ KDFID: defaultHpkeKdf,
+ AEADID: defaultHpkeAead,
+ }
+ g.EncapsulatedKey, _, err = hpke.SetupSender(kem, suite.KDFID, suite.AEADID, echPK, []byte{})
+ if err != nil {
+ initErr = fmt.Errorf("tls: grease ech: failed to setup encapsulated key: %w", err)
+ return
+ }
+ }
+
+ if len(g.payload) == 0 {
+ if len(g.CandidatePayloadLens) == 0 {
+ g.CandidatePayloadLens = []uint16{128}
+ }
+
+ // randomly pick one from the list
+ rndIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(g.CandidatePayloadLens))))
+ if err != nil {
+ initErr = fmt.Errorf("error generating random index for payload length: %w", err)
+ return
+ }
+
+ initErr = g.randomizePayload(g.CandidatePayloadLens[rndIndex.Int64()])
+ }
+ })
+
+ return initErr
+}
+
+func (g *GREASEEncryptedClientHelloExtension) randomizePayload(encodedHelloInnerLen uint16) error {
+ if len(g.payload) != 0 {
+ return errors.New("tls: grease ech: regenerating payload is forbidden")
+ }
+
+ g.payload = make([]byte, cipherLen(g.cipherSuite.AeadId, int(encodedHelloInnerLen)))
+ _, err := rand.Read(g.payload)
+ if err != nil {
+ return fmt.Errorf("tls: generating grease ech payload: %w", err)
+ }
+ return nil
+}
+
+// writeToUConn implements TLSExtension.
+//
+// For ECH extensions, writeToUConn simply points the ech field in UConn to the extension.
+func (g *GREASEEncryptedClientHelloExtension) writeToUConn(uconn *UConn) error {
+ uconn.ech = g
+ return uconn.MarshalClientHelloNoECH()
+}
+
+// Len implements TLSExtension.
+func (g *GREASEEncryptedClientHelloExtension) Len() int {
+ g.init()
+ return 2 + 2 + 1 /* ClientHello Type */ + 4 /* CipherSuite */ + 1 /* Config ID */ + 2 + len(g.EncapsulatedKey) + 2 + len(g.payload)
+}
+
+// Read implements TLSExtension.
+func (g *GREASEEncryptedClientHelloExtension) Read(b []byte) (int, error) {
+ if len(b) < g.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ b[0] = byte(utlsExtensionECH >> 8)
+ b[1] = byte(utlsExtensionECH & 0xFF)
+ b[2] = byte((g.Len() - 4) >> 8)
+ b[3] = byte((g.Len() - 4) & 0xFF)
+ b[4] = OuterClientHello
+ b[5] = byte(g.cipherSuite.KdfId >> 8)
+ b[6] = byte(g.cipherSuite.KdfId & 0xFF)
+ b[7] = byte(g.cipherSuite.AeadId >> 8)
+ b[8] = byte(g.cipherSuite.AeadId & 0xFF)
+ b[9] = g.configId
+ b[10] = byte(len(g.EncapsulatedKey) >> 8)
+ b[11] = byte(len(g.EncapsulatedKey) & 0xFF)
+ copy(b[12:], g.EncapsulatedKey)
+ b[12+len(g.EncapsulatedKey)] = byte(len(g.payload) >> 8)
+ b[12+len(g.EncapsulatedKey)+1] = byte(len(g.payload) & 0xFF)
+ copy(b[12+len(g.EncapsulatedKey)+2:], g.payload)
+
+ return g.Len(), io.EOF
+}
+
+// MarshalClientHello implements EncryptedClientHelloExtension.
+func (*GREASEEncryptedClientHelloExtension) MarshalClientHello(*UConn) error {
+ return errors.New("tls: grease ech: MarshalClientHello() is not implemented, use (*UConn).MarshalClientHello() instead")
+}
+
+// Write implements TLSExtensionWriter.
+func (g *GREASEEncryptedClientHelloExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+
+ // Check the extension type, it must be OuterClientHello otherwise we are not
+ // parsing the correct extension
+ var chType uint8 // 0: outer, 1: inner
+ var ignored cryptobyte.String
+ if !extData.ReadUint8(&chType) || chType != 0 {
+ return fullLen, errors.New("bad Client Hello type, expected 0, got " + fmt.Sprintf("%d", chType))
+ }
+
+ // Parse the cipher suite
+ if !extData.ReadUint16(&g.cipherSuite.KdfId) || !extData.ReadUint16(&g.cipherSuite.AeadId) {
+ return fullLen, errors.New("bad cipher suite")
+ }
+ if g.cipherSuite.KdfId != dicttls.HKDF_SHA256 &&
+ g.cipherSuite.KdfId != dicttls.HKDF_SHA384 &&
+ g.cipherSuite.KdfId != dicttls.HKDF_SHA512 {
+ return fullLen, errors.New("bad KDF ID: " + fmt.Sprintf("%d", g.cipherSuite.KdfId))
+ }
+ if g.cipherSuite.AeadId != dicttls.AEAD_AES_128_GCM &&
+ g.cipherSuite.AeadId != dicttls.AEAD_AES_256_GCM &&
+ g.cipherSuite.AeadId != dicttls.AEAD_CHACHA20_POLY1305 {
+ return fullLen, errors.New("bad AEAD ID: " + fmt.Sprintf("%d", g.cipherSuite.AeadId))
+ }
+ g.CandidateCipherSuites = []HPKESymmetricCipherSuite{g.cipherSuite}
+
+ // GREASE the ConfigId
+ if !extData.ReadUint8(&g.configId) {
+ return fullLen, errors.New("bad config ID")
+ }
+ // we don't write to CandidateConfigIds because we don't really want to reuse the same config_id
+
+ // GREASE the EncapsulatedKey
+ if !extData.ReadUint16LengthPrefixed(&ignored) {
+ return fullLen, errors.New("bad encapsulated key")
+ }
+ g.EncapsulatedKey = make([]byte, len(ignored))
+ n, err := rand.Read(g.EncapsulatedKey)
+ if err != nil {
+ return fullLen, fmt.Errorf("tls: generating grease ech encapsulated key: %w", err)
+ }
+ if n != len(g.EncapsulatedKey) {
+ return fullLen, fmt.Errorf("tls: generating grease ech encapsulated key: short read for %d bytes", len(ignored)-n)
+ }
+
+ // GREASE the payload
+ if !extData.ReadUint16LengthPrefixed(&ignored) {
+ return fullLen, errors.New("bad payload")
+ }
+ g.CandidatePayloadLens = []uint16{uint16(len(ignored) - cipherLen(g.cipherSuite.AeadId, 0))}
+
+ return fullLen, nil
+}
+
+// UnimplementedECHExtension is a placeholder for an ECH extension that is not implemented.
+// All implementations of EncryptedClientHelloExtension should embed this struct to ensure
+// forward compatibility.
+type UnimplementedECHExtension struct{}
+
+// writeToUConn implements TLSExtension.
+func (*UnimplementedECHExtension) writeToUConn(_ *UConn) error {
+ return errors.New("tls: unimplemented ECHExtension")
+}
+
+// Len implements TLSExtension.
+func (*UnimplementedECHExtension) Len() int {
+ return 0
+}
+
+// Read implements TLSExtension.
+func (*UnimplementedECHExtension) Read(_ []byte) (int, error) {
+ return 0, errors.New("tls: unimplemented ECHExtension")
+}
+
+// MarshalClientHello implements EncryptedClientHelloExtension.
+func (*UnimplementedECHExtension) MarshalClientHello(*UConn) error {
+ return errors.New("tls: unimplemented ECHExtension")
+}
+
+// mustEmbedUnimplementedECHExtension is a noop function but is required to
+// ensure forward compatibility.
+func (*UnimplementedECHExtension) mustEmbedUnimplementedECHExtension() {
+ panic("mustEmbedUnimplementedECHExtension() is not implemented")
+}
+
+// BoringGREASEECH returns a GREASE scheme BoringSSL uses by default.
+func BoringGREASEECH() *GREASEEncryptedClientHelloExtension {
+ return &GREASEEncryptedClientHelloExtension{
+ CandidateCipherSuites: []HPKESymmetricCipherSuite{
+ {
+ KdfId: dicttls.HKDF_SHA256,
+ AeadId: dicttls.AEAD_AES_128_GCM,
+ },
+ },
+ CandidatePayloadLens: []uint16{128, 160, 192, 224}, // +16: 144, 176, 208, 240
+ }
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_fingerprinter.go b/vendor/github.com/refraction-networking/utls/u_fingerprinter.go
new file mode 100644
index 00000000..61afc733
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_fingerprinter.go
@@ -0,0 +1,74 @@
+// Copyright 2017 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+// Fingerprinter is a struct largely for holding options for the FingerprintClientHello func
+type Fingerprinter struct {
+ // AllowBluntMimicry will ensure that unknown extensions are
+ // passed along into the resulting ClientHelloSpec as-is
+ // WARNING: there could be numerous subtle issues with ClientHelloSpecs
+ // that are generated with this flag which could compromise security and/or mimicry
+ AllowBluntMimicry bool
+ // AlwaysAddPadding will always add a UtlsPaddingExtension with BoringPaddingStyle
+ // at the end of the extensions list if it isn't found in the fingerprinted hello.
+ // This could be useful in scenarios where the hello you are fingerprinting does not
+ // have any padding, but you suspect that other changes you make to the final hello
+ // (including things like different SNI lengths) would cause padding to be necessary
+ AlwaysAddPadding bool
+
+ RealPSKResumption bool // if set, PSK extension (if any) will be real PSK extension, otherwise it will be fake PSK extension
+}
+
+// FingerprintClientHello returns a ClientHelloSpec which is based on the
+// ClientHello that is passed in as the data argument
+//
+// If the ClientHello passed in has extensions that are not recognized or cannot be handled
+// it will return a non-nil error and a nil *ClientHelloSpec value
+//
+// The data should be the full tls record, including the record type/version/length header
+// as well as the handshake type/length/version header
+// https://tools.ietf.org/html/rfc5246#section-6.2
+// https://tools.ietf.org/html/rfc5246#section-7.4
+//
+// It calls UnmarshalClientHello internally, and is kept for backwards compatibility
+func (f *Fingerprinter) FingerprintClientHello(data []byte) (clientHelloSpec *ClientHelloSpec, err error) {
+ return f.RawClientHello(data)
+}
+
+// RawClientHello returns a ClientHelloSpec which is based on the
+// ClientHello raw bytes that is passed in as the raw argument.
+//
+// It was renamed from FingerprintClientHello in v1.3.1 and earlier versions
+// as a more precise name for the function
+func (f *Fingerprinter) RawClientHello(raw []byte) (clientHelloSpec *ClientHelloSpec, err error) {
+ clientHelloSpec = &ClientHelloSpec{}
+
+ err = clientHelloSpec.FromRaw(raw, f.AllowBluntMimicry, f.RealPSKResumption)
+ if err != nil {
+ return nil, err
+ }
+
+ if f.AlwaysAddPadding {
+ clientHelloSpec.AlwaysAddPadding()
+ }
+
+ return clientHelloSpec, nil
+}
+
+// UnmarshalJSONClientHello returns a ClientHelloSpec which is based on the
+// ClientHello JSON bytes that is passed in as the json argument.
+func (f *Fingerprinter) UnmarshalJSONClientHello(json []byte) (clientHelloSpec *ClientHelloSpec, err error) {
+ clientHelloSpec = &ClientHelloSpec{}
+ err = clientHelloSpec.UnmarshalJSON(json)
+ if err != nil {
+ return nil, err
+ }
+
+ if f.AlwaysAddPadding {
+ clientHelloSpec.AlwaysAddPadding()
+ }
+
+ return clientHelloSpec, nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_handshake_client.go b/vendor/github.com/refraction-networking/utls/u_handshake_client.go
new file mode 100644
index 00000000..9928f0c3
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_handshake_client.go
@@ -0,0 +1,595 @@
+// Copyright 2022 uTLS 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 tls
+
+import (
+ "bytes"
+ "compress/zlib"
+ "context"
+ "errors"
+ "fmt"
+ "io"
+
+ "github.com/andybalholm/brotli"
+ "github.com/klauspost/compress/zstd"
+ "github.com/refraction-networking/utls/internal/fips140tls"
+ "github.com/refraction-networking/utls/internal/hpke"
+ "github.com/refraction-networking/utls/internal/tls13"
+)
+
+// This function is called by (*clientHandshakeStateTLS13).readServerCertificate()
+// to retrieve the certificate out of a message read by (*Conn).readHandshake()
+func (hs *clientHandshakeStateTLS13) utlsReadServerCertificate(msg any) (processedMsg any, err error) {
+ for _, ext := range hs.uconn.Extensions {
+ switch ext.(type) {
+ case *UtlsCompressCertExtension:
+ // Included Compressed Certificate extension
+ if len(hs.uconn.certCompressionAlgs) > 0 {
+ compressedCertMsg, ok := msg.(*utlsCompressedCertificateMsg)
+ if ok {
+ if err = transcriptMsg(compressedCertMsg, hs.transcript); err != nil {
+ return nil, err
+ }
+ msg, err = hs.decompressCert(*compressedCertMsg)
+ if err != nil {
+ return nil, fmt.Errorf("tls: failed to decompress certificate message: %w", err)
+ } else {
+ return msg, nil
+ }
+ }
+ }
+ default:
+ continue
+ }
+ }
+ return nil, nil
+}
+
+// called by (*clientHandshakeStateTLS13).utlsReadServerCertificate() when UtlsCompressCertExtension is used
+func (hs *clientHandshakeStateTLS13) decompressCert(m utlsCompressedCertificateMsg) (*certificateMsgTLS13, error) {
+ var (
+ decompressed io.Reader
+ compressed = bytes.NewReader(m.compressedCertificateMessage)
+ c = hs.c
+ )
+
+ // Check to see if the peer responded with an algorithm we advertised.
+ supportedAlg := false
+ for _, alg := range hs.uconn.certCompressionAlgs {
+ if m.algorithm == uint16(alg) {
+ supportedAlg = true
+ }
+ }
+ if !supportedAlg {
+ c.sendAlert(alertBadCertificate)
+ return nil, fmt.Errorf("unadvertised algorithm (%d)", m.algorithm)
+ }
+
+ switch CertCompressionAlgo(m.algorithm) {
+ case CertCompressionBrotli:
+ decompressed = brotli.NewReader(compressed)
+
+ case CertCompressionZlib:
+ rc, err := zlib.NewReader(compressed)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return nil, fmt.Errorf("failed to open zlib reader: %w", err)
+ }
+ defer rc.Close()
+ decompressed = rc
+
+ case CertCompressionZstd:
+ rc, err := zstd.NewReader(compressed)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return nil, fmt.Errorf("failed to open zstd reader: %w", err)
+ }
+ defer rc.Close()
+ decompressed = rc
+
+ default:
+ c.sendAlert(alertBadCertificate)
+ return nil, fmt.Errorf("unsupported algorithm (%d)", m.algorithm)
+ }
+
+ rawMsg := make([]byte, m.uncompressedLength+4) // +4 for message type and uint24 length field
+ rawMsg[0] = typeCertificate
+ rawMsg[1] = uint8(m.uncompressedLength >> 16)
+ rawMsg[2] = uint8(m.uncompressedLength >> 8)
+ rawMsg[3] = uint8(m.uncompressedLength)
+
+ n, err := decompressed.Read(rawMsg[4:])
+ if err != nil && !errors.Is(err, io.EOF) {
+ c.sendAlert(alertBadCertificate)
+ return nil, err
+ }
+ if n < len(rawMsg)-4 {
+ // If, after decompression, the specified length does not match the actual length, the party
+ // receiving the invalid message MUST abort the connection with the "bad_certificate" alert.
+ // https://datatracker.ietf.org/doc/html/rfc8879#section-4
+ c.sendAlert(alertBadCertificate)
+ return nil, fmt.Errorf("decompressed len (%d) does not match specified len (%d)", n, m.uncompressedLength)
+ }
+ certMsg := new(certificateMsgTLS13)
+ if !certMsg.unmarshal(rawMsg) {
+ return nil, c.sendAlert(alertUnexpectedMessage)
+ }
+ return certMsg, nil
+}
+
+// to be called in (*clientHandshakeStateTLS13).handshake(),
+// after hs.readServerFinished() and before hs.sendClientCertificate()
+func (hs *clientHandshakeStateTLS13) serverFinishedReceived() error {
+ if err := hs.sendClientEncryptedExtensions(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientEncryptedExtensions() error {
+ c := hs.c
+ clientEncryptedExtensions := new(utlsClientEncryptedExtensionsMsg)
+ if c.utls.applicationSettingsCodepoint != 0 {
+ clientEncryptedExtensions.applicationSettingsCodepoint = c.utls.applicationSettingsCodepoint
+ clientEncryptedExtensions.applicationSettings = c.utls.localApplicationSettings
+ if _, err := c.writeHandshakeRecord(clientEncryptedExtensions, hs.transcript); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) utlsReadServerParameters(encryptedExtensions *encryptedExtensionsMsg) error {
+ hs.c.utls.peerApplicationSettings = encryptedExtensions.utls.applicationSettings
+ hs.c.utls.applicationSettingsCodepoint = encryptedExtensions.utls.applicationSettingsCodepoint
+
+ if hs.c.utls.applicationSettingsCodepoint != 0 {
+ if hs.uconn.vers < VersionTLS13 {
+ return errors.New("tls: server sent application settings at invalid version")
+ }
+ if len(hs.uconn.clientProtocol) == 0 {
+ return errors.New("tls: server sent application settings without ALPN")
+ }
+
+ // Check if the ALPN selected by the server exists in the client's list.
+ if alps, ok := hs.uconn.config.ApplicationSettings[hs.serverHello.alpnProtocol]; ok {
+ hs.c.utls.localApplicationSettings = alps
+ } else {
+ // return errors.New("tls: server selected ALPN doesn't match a client ALPS")
+ return nil // ignore if client doesn't have ALPS in use.
+ // TODO: is this a issue or not?
+ }
+ }
+
+ return nil
+}
+
+func (c *Conn) makeClientHelloForApplyPreset() (*clientHelloMsg, *keySharePrivateKeys, *echClientContext, error) {
+ config := c.config
+
+ // [UTLS SECTION START]
+ if len(config.ServerName) == 0 && !config.InsecureSkipVerify && len(config.InsecureServerNameToVerify) == 0 {
+ return nil, nil, nil, errors.New("tls: at least one of ServerName, InsecureSkipVerify or InsecureServerNameToVerify must be specified in the tls.Config")
+ }
+ // [UTLS SECTION END]
+
+ nextProtosLength := 0
+ for _, proto := range config.NextProtos {
+ if l := len(proto); l == 0 || l > 255 {
+ return nil, nil, nil, errors.New("tls: invalid NextProtos value")
+ } else {
+ nextProtosLength += 1 + l
+ }
+ }
+ if nextProtosLength > 0xffff {
+ return nil, nil, nil, errors.New("tls: NextProtos values too large")
+ }
+
+ supportedVersions := config.supportedVersions(roleClient)
+ if len(supportedVersions) == 0 {
+ return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
+ }
+ maxVersion := config.maxSupportedVersion(roleClient)
+
+ hello := &clientHelloMsg{
+ vers: maxVersion,
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ extendedMasterSecret: true,
+ ocspStapling: true,
+ scts: true,
+ serverName: hostnameInSNI(config.ServerName),
+ supportedCurves: config.curvePreferences(maxVersion),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ secureRenegotiationSupported: true,
+ alpnProtocols: config.NextProtos,
+ supportedVersions: supportedVersions,
+ }
+
+ // The version at the beginning of the ClientHello was capped at TLS 1.2
+ // for compatibility reasons. The supported_versions extension is used
+ // to negotiate versions now. See RFC 8446, Section 4.2.1.
+ if hello.vers > VersionTLS12 {
+ hello.vers = VersionTLS12
+ }
+
+ if c.handshakes > 0 {
+ hello.secureRenegotiation = c.clientFinished[:]
+ }
+
+ preferenceOrder := cipherSuitesPreferenceOrder
+ if !hasAESGCMHardwareSupport {
+ preferenceOrder = cipherSuitesPreferenceOrderNoAES
+ }
+ configCipherSuites := config.cipherSuites()
+ hello.cipherSuites = make([]uint16, 0, len(configCipherSuites))
+
+ for _, suiteId := range preferenceOrder {
+ suite := mutualCipherSuite(configCipherSuites, suiteId)
+ if suite == nil {
+ continue
+ }
+ // Don't advertise TLS 1.2-only cipher suites unless
+ // we're attempting TLS 1.2.
+ if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
+ continue
+ }
+ hello.cipherSuites = append(hello.cipherSuites, suiteId)
+ }
+
+ _, err := io.ReadFull(config.rand(), hello.random)
+ if err != nil {
+ return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+ }
+
+ // A random session ID is used to detect when the server accepted a ticket
+ // and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
+ // a compatibility measure (see RFC 8446, Section 4.1.2).
+ //
+ // The session ID is not set for QUIC connections (see RFC 9001, Section 8.4).
+ if c.quic == nil {
+ hello.sessionId = make([]byte, 32)
+ if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {
+ return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+ }
+ }
+
+ if maxVersion >= VersionTLS12 {
+ hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+ if testingOnlyForceClientHelloSignatureAlgorithms != nil {
+ hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
+ }
+
+ var keyShareKeys *keySharePrivateKeys
+ if hello.supportedVersions[0] == VersionTLS13 {
+ // Reset the list of ciphers when the client only supports TLS 1.3.
+ if len(hello.supportedVersions) == 1 {
+ hello.cipherSuites = nil
+ }
+ if fips140tls.Required() {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
+ } else if hasAESGCMHardwareSupport {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
+ } else {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
+ }
+
+ if len(hello.supportedCurves) == 0 {
+ return nil, nil, nil, errors.New("tls: no supported elliptic curves for ECDHE")
+ }
+ // curveID := hello.supportedCurves[0]
+ // keyShareKeys = &keySharePrivateKeys{curveID: curveID}
+ // // Note that if X25519MLKEM768 is supported, it will be first because
+ // // the preference order is fixed.
+ // if curveID == X25519MLKEM768 {
+ // keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519)
+ // if err != nil {
+ // return nil, nil, nil, err
+ // }
+ // seed := make([]byte, mlkem.SeedSize)
+ // if _, err := io.ReadFull(config.rand(), seed); err != nil {
+ // return nil, nil, nil, err
+ // }
+ // keyShareKeys.mlkem, err = mlkem.NewDecapsulationKey768(seed)
+ // if err != nil {
+ // return nil, nil, nil, err
+ // }
+ // mlkemEncapsulationKey := keyShareKeys.mlkem.EncapsulationKey().Bytes()
+ // x25519EphemeralKey := keyShareKeys.ecdhe.PublicKey().Bytes()
+ // hello.keyShares = []keyShare{
+ // {group: X25519MLKEM768, data: append(mlkemEncapsulationKey, x25519EphemeralKey...)},
+ // }
+ // // If both X25519MLKEM768 and X25519 are supported, we send both key
+ // // shares (as a fallback) and we reuse the same X25519 ephemeral
+ // // key, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2.
+ // if slices.Contains(hello.supportedCurves, X25519) {
+ // hello.keyShares = append(hello.keyShares, keyShare{group: X25519, data: x25519EphemeralKey})
+ // }
+ // } else {
+ // if _, ok := curveForCurveID(curveID); !ok {
+ // return nil, nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
+ // }
+ // keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), curveID)
+ // if err != nil {
+ // return nil, nil, nil, err
+ // }
+ // hello.keyShares = []keyShare{{group: curveID, data: keyShareKeys.ecdhe.PublicKey().Bytes()}}
+ // }
+ }
+
+ // [UTLS] We don't need this, since it is not ready yet
+ // if c.quic != nil {
+ // p, err := c.quicGetTransportParameters()
+ // if err != nil {
+ // return nil, nil, nil, err
+ // }
+ // if p == nil {
+ // p = []byte{}
+ // }
+ // hello.quicTransportParameters = p
+ // }
+
+ var ech *echClientContext
+ if c.config.EncryptedClientHelloConfigList != nil {
+ if c.config.MinVersion != 0 && c.config.MinVersion < VersionTLS13 {
+ return nil, nil, nil, errors.New("tls: MinVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
+ }
+ if c.config.MaxVersion != 0 && c.config.MaxVersion <= VersionTLS12 {
+ return nil, nil, nil, errors.New("tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated")
+ }
+ echConfigs, err := parseECHConfigList(c.config.EncryptedClientHelloConfigList)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ echConfig := pickECHConfig(echConfigs)
+ if echConfig == nil {
+ return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs")
+ }
+ ech = &echClientContext{config: echConfig}
+ hello.encryptedClientHello = []byte{1} // indicate inner hello
+ // We need to explicitly set these 1.2 fields to nil, as we do not
+ // marshal them when encoding the inner hello, otherwise transcripts
+ // will later mismatch.
+ hello.supportedPoints = nil
+ hello.ticketSupported = false
+ hello.secureRenegotiationSupported = false
+ hello.extendedMasterSecret = false
+
+ echPK, err := hpke.ParseHPKEPublicKey(ech.config.KemID, ech.config.PublicKey)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ suite, err := pickECHCipherSuite(ech.config.SymmetricCipherSuite)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ ech.kdfID, ech.aeadID = suite.KDFID, suite.AEADID
+ info := append([]byte("tls ech\x00"), ech.config.raw...)
+ ech.encapsulatedKey, ech.hpkeContext, err = hpke.SetupSender(ech.config.KemID, suite.KDFID, suite.AEADID, echPK, info)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ }
+
+ return hello, keyShareKeys, ech, nil
+}
+
+// clientHandshakeWithOneState checks that exactly one expected state is set (1.2 or 1.3)
+// and performs client TLS handshake with that state
+func (c *UConn) clientHandshake(ctx context.Context) (err error) {
+ // [uTLS section begins]
+ hello := c.HandshakeState.Hello.getPrivatePtr()
+ ech := c.echCtx
+ defer func() { c.HandshakeState.Hello = hello.getPublicPtr() }()
+
+ sessionIsLocked := c.utls.sessionController.isSessionLocked()
+
+ // after this point exactly 1 out of 2 HandshakeState pointers is non-nil,
+ // useTLS13 variable tells which pointer
+ // [uTLS section ends]
+
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
+
+ // This may be a renegotiation handshake, in which case some fields
+ // need to be reset.
+ c.didResume = false
+
+ // [uTLS section begins]
+ // don't make new ClientHello, use hs.hello
+ // preserve the checks from beginning and end of makeClientHello()
+ if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify && len(c.config.InsecureServerNameToVerify) == 0 {
+ return errors.New("tls: at least one of ServerName, InsecureSkipVerify or InsecureServerNameToVerify must be specified in the tls.Config")
+ }
+
+ nextProtosLength := 0
+ for _, proto := range c.config.NextProtos {
+ if l := len(proto); l == 0 || l > 255 {
+ return errors.New("tls: invalid NextProtos value")
+ } else {
+ nextProtosLength += 1 + l
+ }
+ }
+
+ if nextProtosLength > 0xffff {
+ return errors.New("tls: NextProtos values too large")
+ }
+
+ if c.handshakes > 0 {
+ hello.secureRenegotiation = c.clientFinished[:]
+ }
+
+ var (
+ session *SessionState
+ earlySecret *tls13.EarlySecret
+ binderKey []byte
+ )
+ if !sessionIsLocked {
+ // [uTLS section ends]
+
+ session, earlySecret, binderKey, err = c.loadSession(hello)
+
+ // [uTLS section start]
+ } else {
+ session = c.HandshakeState.Session
+
+ if c.HandshakeState.State13.EarlySecret != nil && session != nil {
+ cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
+ earlySecret = tls13.NewEarlySecretFromSecret(cipherSuite.hash.New, c.HandshakeState.State13.EarlySecret)
+ }
+
+ binderKey = c.HandshakeState.State13.BinderKey
+ }
+ // [uTLS section ends]
+ if err != nil {
+ return err
+ }
+ if session != nil {
+ defer func() {
+ // If we got a handshake failure when resuming a session, throw away
+ // the session ticket. See RFC 5077, Section 3.2.
+ //
+ // RFC 8446 makes no mention of dropping tickets on failure, but it
+ // does require servers to abort on invalid binders, so we need to
+ // delete tickets to recover from a corrupted PSK.
+ if err != nil {
+ if cacheKey := c.clientSessionCacheKey(); cacheKey != "" {
+ c.config.ClientSessionCache.Put(cacheKey, nil)
+ }
+ }
+ }()
+ }
+
+ if ech != nil && c.clientHelloBuildStatus != BuildByUtls {
+ // Split hello into inner and outer
+ ech.innerHello = hello.clone()
+
+ // Overwrite the server name in the outer hello with the public facing
+ // name.
+ hello.serverName = string(ech.config.PublicName)
+ // Generate a new random for the outer hello.
+ hello.random = make([]byte, 32)
+ _, err = io.ReadFull(c.config.rand(), hello.random)
+ if err != nil {
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+
+ // NOTE: we don't do PSK GREASE, in line with boringssl, it's meant to
+ // work around _possibly_ broken middleboxes, but there is little-to-no
+ // evidence that this is actually a problem.
+
+ if err := computeAndUpdateOuterECHExtension(hello, ech.innerHello, ech, true); err != nil {
+ return err
+ }
+ }
+
+ c.serverName = hello.serverName
+
+ if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
+ return err
+ }
+
+ if hello.earlyData {
+ suite := cipherSuiteTLS13ByID(session.cipherSuite)
+ transcript := suite.hash.New()
+ if err := transcriptMsg(hello, transcript); err != nil {
+ return err
+ }
+ earlyTrafficSecret := earlySecret.ClientEarlyTrafficSecret(transcript)
+ c.quicSetWriteSecret(QUICEncryptionLevelEarly, suite.id, earlyTrafficSecret)
+ }
+
+ // serverHelloMsg is not included in the transcript
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
+ }
+
+ if err := c.pickTLSVersion(serverHello); err != nil {
+ return err
+ }
+
+ // If we are negotiating a protocol version that's lower than what we
+ // support, check for the server downgrade canaries.
+ // See RFC 8446, Section 4.1.3.
+ maxVers := c.config.maxSupportedVersion(roleClient)
+ tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
+ tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
+ if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
+ maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox")
+ }
+
+ // uTLS: do not create new handshakeState, use existing one
+ c.HandshakeState.ServerHello = serverHello.getPublicPtr()
+ if c.vers == VersionTLS13 {
+ hs13 := c.HandshakeState.toPrivate13()
+ hs13.serverHello = serverHello
+ hs13.hello = hello
+ hs13.echContext = ech
+ if c.HandshakeState.State13.EarlySecret != nil && session.cipherSuite != 0 {
+ hs13.earlySecret = tls13.NewEarlySecretFromSecret(cipherSuiteTLS13ByID(session.cipherSuite).hash.New, c.HandshakeState.State13.EarlySecret)
+ }
+ if c.HandshakeState.MasterSecret != nil && session.cipherSuite != 0 {
+ hs13.masterSecret = tls13.NewMasterSecretFromSecret(cipherSuiteTLS13ByID(session.cipherSuite).hash.New, c.HandshakeState.MasterSecret)
+ }
+ if !sessionIsLocked {
+ hs13.earlySecret = earlySecret
+ hs13.binderKey = binderKey
+ hs13.session = session
+ }
+ hs13.ctx = ctx
+ // In TLS 1.3, session tickets are delivered after the handshake.
+ err = hs13.handshake()
+ if handshakeState := hs13.toPublic13(); handshakeState != nil {
+ c.HandshakeState = *handshakeState
+ }
+ return err
+ }
+
+ hs12 := c.HandshakeState.toPrivate12()
+ hs12.serverHello = serverHello
+ hs12.hello = hello
+ hs12.ctx = ctx
+ hs12.session = session
+ err = hs12.handshake()
+ if handshakeState := hs12.toPublic12(); handshakeState != nil {
+ c.HandshakeState = *handshakeState
+ }
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (c *UConn) echTranscriptMsg(outer *clientHelloMsg, echCtx *echClientContext) (err error) {
+ // Recreate the inner ClientHello from its compressed form using server's decodeInnerClientHello function.
+ // See https://github.com/refraction-networking/utls/blob/e430876b1d82fdf582efc57f3992d448e7ab3d8a/ech.go#L276-L283
+ encodedInner, err := encodeInnerClientHelloReorderOuterExts(echCtx.innerHello, int(echCtx.config.MaxNameLength), c.extensionsList())
+ if err != nil {
+ return err
+ }
+
+ decodedInner, err := decodeInnerClientHello(outer, encodedInner)
+ if err != nil {
+ return err
+ }
+
+ if err := transcriptMsg(decodedInner, echCtx.innerTranscript); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_handshake_messages.go b/vendor/github.com/refraction-networking/utls/u_handshake_messages.go
new file mode 100644
index 00000000..dd8a1d98
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_handshake_messages.go
@@ -0,0 +1,138 @@
+// Copyright 2022 uTLS 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 tls
+
+import (
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// Only implemented client-side, for server certificates.
+// Alternate certificate message formats (https://datatracker.ietf.org/doc/html/rfc7250) are not
+// supported.
+// https://datatracker.ietf.org/doc/html/rfc8879
+type utlsCompressedCertificateMsg struct {
+ raw []byte
+
+ algorithm uint16
+ uncompressedLength uint32 // uint24
+ compressedCertificateMessage []byte
+}
+
+func (m *utlsCompressedCertificateMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(utlsTypeCompressedCertificate)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16(m.algorithm)
+ b.AddUint24(m.uncompressedLength)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.compressedCertificateMessage)
+ })
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *utlsCompressedCertificateMsg) unmarshal(data []byte) bool {
+ *m = utlsCompressedCertificateMsg{raw: data}
+ s := cryptobyte.String(data)
+
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16(&m.algorithm) ||
+ !s.ReadUint24(&m.uncompressedLength) ||
+ !readUint24LengthPrefixed(&s, &m.compressedCertificateMessage) {
+ return false
+ }
+ return true
+}
+
+type utlsEncryptedExtensionsMsgExtraFields struct {
+ applicationSettings []byte
+ applicationSettingsCodepoint uint16
+ customExtension []byte
+}
+
+func (m *encryptedExtensionsMsg) utlsUnmarshal(extension uint16, extData cryptobyte.String) bool {
+ switch extension {
+ case utlsExtensionApplicationSettings:
+ fallthrough
+ case utlsExtensionApplicationSettingsNew:
+ m.utls.applicationSettingsCodepoint = extension
+ m.utls.applicationSettings = []byte(extData)
+ }
+ return true // success/unknown extension
+}
+
+type utlsClientEncryptedExtensionsMsg struct {
+ raw []byte
+ applicationSettings []byte
+ applicationSettingsCodepoint uint16
+ customExtension []byte
+}
+
+func (m *utlsClientEncryptedExtensionsMsg) marshal() (x []byte, err error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var builder cryptobyte.Builder
+ builder.AddUint8(typeEncryptedExtensions)
+ builder.AddUint24LengthPrefixed(func(body *cryptobyte.Builder) {
+ body.AddUint16LengthPrefixed(func(extensions *cryptobyte.Builder) {
+ if m.applicationSettingsCodepoint != 0 {
+ extensions.AddUint16(m.applicationSettingsCodepoint)
+ extensions.AddUint16LengthPrefixed(func(msg *cryptobyte.Builder) {
+ msg.AddBytes(m.applicationSettings)
+ })
+ }
+ if len(m.customExtension) > 0 {
+ extensions.AddUint16(utlsFakeExtensionCustom)
+ extensions.AddUint16LengthPrefixed(func(msg *cryptobyte.Builder) {
+ msg.AddBytes(m.customExtension)
+ })
+ }
+ })
+ })
+
+ m.raw, err = builder.Bytes()
+ return m.raw, err
+}
+
+func (m *utlsClientEncryptedExtensionsMsg) unmarshal(data []byte) bool {
+ *m = utlsClientEncryptedExtensionsMsg{raw: data}
+ s := cryptobyte.String(data)
+
+ var extensions cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+ return false
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ switch extension {
+ case utlsExtensionApplicationSettings:
+ fallthrough
+ case utlsExtensionApplicationSettingsNew:
+ m.applicationSettingsCodepoint = extension
+ m.applicationSettings = []byte(extData)
+ default:
+ // Unknown extensions are illegal in EncryptedExtensions.
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_hpke.go b/vendor/github.com/refraction-networking/utls/u_hpke.go
new file mode 100644
index 00000000..e07ada27
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_hpke.go
@@ -0,0 +1,35 @@
+package tls
+
+import (
+ "github.com/refraction-networking/utls/internal/hpke"
+)
+
+type HPKERawPublicKey = []byte
+type HPKE_KEM_ID = uint16 // RFC 9180
+type HPKE_KDF_ID = uint16 // RFC 9180
+type HPKE_AEAD_ID = uint16 // RFC 9180
+
+type HPKESymmetricCipherSuite struct {
+ KdfId HPKE_KDF_ID
+ AeadId HPKE_AEAD_ID
+}
+
+const defaultHpkeKdf = hpke.KDF_HKDF_SHA256
+const defaultHpkeKem = hpke.DHKEM_X25519_HKDF_SHA256
+const defaultHpkeAead = hpke.AEAD_AES_128_GCM
+
+var dummyX25519PublicKey = []byte{
+ 143, 38, 37, 36, 12, 6, 229, 30, 140, 27, 167, 73, 26, 100, 203, 107, 216,
+ 81, 163, 222, 52, 211, 54, 210, 46, 37, 78, 216, 157, 97, 241, 244,
+}
+
+// cipherLen returns the length of a ciphertext corresponding to a message of
+// length mLen.
+func cipherLen(a uint16, mLen int) int {
+ switch a {
+ case hpke.AEAD_AES_128_GCM, hpke.AEAD_AES_256_GCM, hpke.AEAD_ChaCha20Poly1305:
+ return mLen + 16
+ default:
+ panic("hpke: invalid AEAD identifier")
+ }
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_key_schedule.go b/vendor/github.com/refraction-networking/utls/u_key_schedule.go
new file mode 100644
index 00000000..f52839d9
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_key_schedule.go
@@ -0,0 +1,30 @@
+package tls
+
+import (
+ "crypto/mlkem"
+
+ "golang.org/x/crypto/sha3"
+)
+
+// kyberDecapsulate implements decapsulation according to Kyber Round 3.
+func kyberDecapsulate(dk *mlkem.DecapsulationKey768, c []byte) ([]byte, error) {
+ K, err := dk.Decapsulate(c)
+ if err != nil {
+ return nil, err
+ }
+ return kyberSharedSecret(c, K), nil
+}
+
+func kyberSharedSecret(c, K []byte) []byte {
+ // Package mlkem implements ML-KEM, which compared to Kyber removed a
+ // final hashing step. Compute SHAKE-256(K || SHA3-256(c), 32) to match Kyber.
+ // See https://words.filippo.io/mlkem768/#bonus-track-using-a-ml-kem-implementation-as-kyber-v3.
+ h := sha3.NewShake256()
+ h.Write(K)
+ ch := sha3.New256()
+ ch.Write(c)
+ h.Write(ch.Sum(nil))
+ out := make([]byte, 32)
+ h.Read(out)
+ return out
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_parrots.go b/vendor/github.com/refraction-networking/utls/u_parrots.go
new file mode 100644
index 00000000..3dc72c3e
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_parrots.go
@@ -0,0 +1,3241 @@
+// Copyright 2017 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/mlkem"
+ crand "crypto/rand"
+ "crypto/sha256"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "math/big"
+ "math/rand"
+ "sort"
+ "strconv"
+
+ "github.com/refraction-networking/utls/dicttls"
+)
+
+var ErrUnknownClientHelloID = errors.New("tls: unknown ClientHelloID")
+
+// UTLSIdToSpec converts a ClientHelloID to a corresponding ClientHelloSpec.
+//
+// Exported internal function utlsIdToSpec per request.
+func UTLSIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
+ return utlsIdToSpec(id)
+}
+
+func utlsIdToSpec(id ClientHelloID) (ClientHelloSpec, error) {
+ switch id {
+ case HelloChrome_58, HelloChrome_62:
+ return ClientHelloSpec{
+ TLSVersMax: VersionTLS12,
+ TLSVersMin: VersionTLS10,
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{compressionNone},
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &SessionTicketExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1},
+ },
+ &StatusRequestExtension{},
+ &SCTExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &FakeChannelIDExtension{},
+ &SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}},
+ &SupportedCurvesExtension{[]CurveID{CurveID(GREASE_PLACEHOLDER),
+ X25519, CurveP256, CurveP384}},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ GetSessionID: sha256.Sum256,
+ }, nil
+ case HelloChrome_70:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS10,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ compressionNone,
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &SessionTicketExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ }},
+ &StatusRequestExtension{},
+ &SCTExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &FakeChannelIDExtension{},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ pointFormatUncompressed,
+ }},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{pskModeDHE}},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10}},
+ &SupportedCurvesExtension{[]CurveID{
+ CurveID(GREASE_PLACEHOLDER),
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{CertCompressionBrotli}},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloChrome_72:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ CurveID(GREASE_PLACEHOLDER),
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloChrome_83:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ CurveID(GREASE_PLACEHOLDER),
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloChrome_87:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ CurveID(GREASE_PLACEHOLDER),
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloChrome_96:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ CurveID(GREASE_PLACEHOLDER),
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloChrome_100, HelloChrome_102:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloChrome_106_Shuffle:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ }),
+ }, nil
+ // Chrome w/ Post-Quantum Key Agreement
+ case HelloChrome_115_PQ:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519Kyber768Draft00,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519Kyber768Draft00},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ }),
+ }, nil
+ // Chrome ECH
+ case HelloChrome_120:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{Curves: []CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{KeyShares: []KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{Modes: []uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{Versions: []uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{Algorithms: []CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ BoringGREASEECH(),
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ }),
+ }, nil
+ // Chrome w/ Post-Quantum Key Agreement and ECH
+ case HelloChrome_120_PQ:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519Kyber768Draft00,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519Kyber768Draft00},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ BoringGREASEECH(),
+ &UtlsGREASEExtension{},
+ }),
+ }, nil
+ case HelloChrome_131:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519MLKEM768,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519MLKEM768},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ BoringGREASEECH(),
+ &UtlsGREASEExtension{},
+ }),
+ }, nil
+ case HelloChrome_133:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519MLKEM768,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519MLKEM768},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtensionNew{SupportedProtocols: []string{"h2"}},
+ BoringGREASEECH(),
+ &UtlsGREASEExtension{},
+ }),
+ }, nil
+ case HelloFirefox_55, HelloFirefox_56:
+ return ClientHelloSpec{
+ TLSVersMax: VersionTLS12,
+ TLSVersMin: VersionTLS10,
+ CipherSuites: []uint16{
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{compressionNone},
+ Extensions: []TLSExtension{
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{X25519, CurveP256, CurveP384, CurveP521}},
+ &SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithSHA1,
+ PKCS1WithSHA1},
+ },
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ GetSessionID: nil,
+ }, nil
+ case HelloFirefox_63, HelloFirefox_65:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS10,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ compressionNone,
+ },
+ Extensions: []TLSExtension{
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ CurveID(FakeFFDHE2048),
+ CurveID(FakeFFDHE3072),
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ pointFormatUncompressed,
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: X25519},
+ {Group: CurveP256},
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10}},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithSHA1,
+ PKCS1WithSHA1,
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{pskModeDHE}},
+ &FakeRecordSizeLimitExtension{0x4001},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ }}, nil
+ case HelloFirefox_99:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS10,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ compressionNone,
+ },
+ Extensions: []TLSExtension{
+ &SNIExtension{}, //server_name
+ &ExtendedMasterSecretExtension{}, //extended_master_secret
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient}, //extensionRenegotiationInfo
+ &SupportedCurvesExtension{[]CurveID{ //supported_groups
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ CurveID(FakeFFDHE2048),
+ CurveID(FakeFFDHE3072),
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{ //ec_point_formats
+ pointFormatUncompressed,
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}, //application_layer_protocol_negotiation
+ &StatusRequestExtension{},
+ &FakeDelegatedCredentialsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ ECDSAWithSHA1,
+ },
+ },
+ &KeyShareExtension{[]KeyShare{
+ {Group: X25519},
+ {Group: CurveP256}, //key_share
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ VersionTLS13, //supported_versions
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ }},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithSHA1,
+ PKCS1WithSHA1,
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{ //psk_key_exchange_modes
+ PskModeDHE,
+ }},
+ &FakeRecordSizeLimitExtension{Limit: 0x4001}, //record_size_limit
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}, //padding
+ }}, nil
+ case HelloFirefox_102:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS10,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ compressionNone,
+ },
+ Extensions: []TLSExtension{
+ &SNIExtension{}, //server_name
+ &ExtendedMasterSecretExtension{}, //extended_master_secret
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient}, //extensionRenegotiationInfo
+ &SupportedCurvesExtension{[]CurveID{ //supported_groups
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ CurveID(FakeFFDHE2048),
+ CurveID(FakeFFDHE3072),
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{ //ec_point_formats
+ pointFormatUncompressed,
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2"}}, //application_layer_protocol_negotiation
+ &StatusRequestExtension{},
+ &FakeDelegatedCredentialsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ ECDSAWithSHA1,
+ },
+ },
+ &KeyShareExtension{[]KeyShare{
+ {Group: X25519},
+ {Group: CurveP256}, //key_share
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ VersionTLS13, //supported_versions
+ VersionTLS12,
+ }},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{ //signature_algorithms
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithSHA1,
+ PKCS1WithSHA1,
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{ //psk_key_exchange_modes
+ PskModeDHE,
+ }},
+ &FakeRecordSizeLimitExtension{Limit: 0x4001}, //record_size_limit
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}, //padding
+ }}, nil
+ case HelloFirefox_105:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS12,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ 256,
+ 257,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // uncompressed
+ },
+ },
+ &SessionTicketExtension{},
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "h2",
+ "http/1.1",
+ },
+ },
+ &StatusRequestExtension{},
+ &FakeDelegatedCredentialsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ ECDSAWithSHA1,
+ },
+ },
+ &KeyShareExtension{
+ KeyShares: []KeyShare{
+ {
+ Group: X25519,
+ },
+ {
+ Group: CurveP256,
+ },
+ },
+ },
+ &SupportedVersionsExtension{
+ Versions: []uint16{
+ VersionTLS13,
+ VersionTLS12,
+ },
+ },
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithSHA1,
+ PKCS1WithSHA1,
+ },
+ },
+ &PSKKeyExchangeModesExtension{
+ Modes: []uint8{
+ PskModeDHE,
+ },
+ },
+ &FakeRecordSizeLimitExtension{
+ Limit: 0x4001,
+ },
+ &UtlsPaddingExtension{
+ GetPaddingLen: BoringPaddingStyle,
+ },
+ },
+ }, nil
+ case HelloFirefox_120:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS12,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ 256,
+ 257,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // uncompressed
+ },
+ },
+ &SessionTicketExtension{},
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "h2",
+ "http/1.1",
+ },
+ },
+ &StatusRequestExtension{},
+ &FakeDelegatedCredentialsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ ECDSAWithSHA1,
+ },
+ },
+ &KeyShareExtension{
+ KeyShares: []KeyShare{
+ {
+ Group: X25519,
+ },
+ {
+ Group: CurveP256,
+ },
+ },
+ },
+ &SupportedVersionsExtension{
+ Versions: []uint16{
+ VersionTLS13,
+ VersionTLS12,
+ },
+ },
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithSHA1,
+ PKCS1WithSHA1,
+ },
+ },
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &FakeRecordSizeLimitExtension{
+ Limit: 0x4001,
+ },
+ &GREASEEncryptedClientHelloExtension{
+ CandidateCipherSuites: []HPKESymmetricCipherSuite{
+ {
+ KdfId: dicttls.HKDF_SHA256,
+ AeadId: dicttls.AEAD_AES_128_GCM,
+ },
+ {
+ KdfId: dicttls.HKDF_SHA256,
+ AeadId: dicttls.AEAD_CHACHA20_POLY1305,
+ },
+ },
+ CandidatePayloadLens: []uint16{223}, // +16: 239
+ },
+ },
+ }, nil
+ case HelloIOS_11_1:
+ return ClientHelloSpec{
+ TLSVersMax: VersionTLS12,
+ TLSVersMin: VersionTLS10,
+ CipherSuites: []uint16{
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ compressionNone,
+ },
+ Extensions: []TLSExtension{
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ }},
+ &StatusRequestExtension{},
+ &NPNExtension{},
+ &SCTExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "h2-16", "h2-15", "h2-14", "spdy/3.1", "spdy/3", "http/1.1"}},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ pointFormatUncompressed,
+ }},
+ &SupportedCurvesExtension{Curves: []CurveID{
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ }},
+ },
+ }, nil
+ case HelloIOS_12_1:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ 0xc008,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ compressionNone,
+ },
+ Extensions: []TLSExtension{
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithSHA1,
+ PSSWithSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ }},
+ &StatusRequestExtension{},
+ &NPNExtension{},
+ &SCTExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "h2-16", "h2-15", "h2-14", "spdy/3.1", "spdy/3", "http/1.1"}},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ pointFormatUncompressed,
+ }},
+ &SupportedCurvesExtension{[]CurveID{
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ }},
+ },
+ }, nil
+ case HelloIOS_13:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ 0xc008,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithSHA1,
+ PSSWithSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ }},
+ &StatusRequestExtension{},
+ &SCTExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &KeyShareExtension{[]KeyShare{
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ }},
+ &SupportedCurvesExtension{[]CurveID{
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ }},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloIOS_14:
+ return ClientHelloSpec{
+ // TLSVersMax: VersionTLS12,
+ // TLSVersMin: VersionTLS10,
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ DISABLED_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ DISABLED_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ 0xc008,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ CurveID(GREASE_PLACEHOLDER),
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithSHA1,
+ PSSWithSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ }},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ },
+ }, nil
+ case HelloAndroid_11_OkHttp:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ 0xcca9, // Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ 0xcca8, // Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{},
+ // supported_groups
+ &SupportedCurvesExtension{[]CurveID{
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ }},
+ },
+ }, nil
+ case HelloEdge_85:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // pointFormatUncompressed
+ },
+ },
+ &SessionTicketExtension{},
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "h2",
+ "http/1.1",
+ },
+ },
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ },
+ },
+ &SCTExtension{},
+ &KeyShareExtension{
+ KeyShares: []KeyShare{
+ {
+ Group: GREASE_PLACEHOLDER,
+ Data: []byte{
+ 0,
+ },
+ },
+ {
+ Group: X25519,
+ },
+ },
+ },
+ &PSKKeyExchangeModesExtension{
+ Modes: []uint8{
+ PskModeDHE,
+ },
+ },
+ &SupportedVersionsExtension{
+ Versions: []uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ },
+ },
+ &UtlsCompressCertExtension{
+ Algorithms: []CertCompressionAlgo{
+ CertCompressionBrotli,
+ },
+ },
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{
+ GetPaddingLen: BoringPaddingStyle,
+ },
+ },
+ }, nil
+ case HelloEdge_106:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS12,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // uncompressed
+ },
+ },
+ &SessionTicketExtension{},
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "h2",
+ "http/1.1",
+ },
+ },
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ },
+ },
+ &SCTExtension{},
+ &KeyShareExtension{
+ KeyShares: []KeyShare{
+ {
+ Group: GREASE_PLACEHOLDER,
+ Data: []byte{
+ 0,
+ },
+ },
+ {
+ Group: X25519,
+ },
+ },
+ },
+ &PSKKeyExchangeModesExtension{
+ Modes: []uint8{
+ PskModeDHE,
+ },
+ },
+ &SupportedVersionsExtension{
+ Versions: []uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ },
+ },
+ &UtlsCompressCertExtension{
+ Algorithms: []CertCompressionAlgo{
+ CertCompressionBrotli,
+ },
+ },
+ &ApplicationSettingsExtension{
+ SupportedProtocols: []string{
+ "h2",
+ },
+ },
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{
+ GetPaddingLen: BoringPaddingStyle,
+ },
+ },
+ }, nil
+ case HelloSafari_16_0:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS10,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ FAKE_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // uncompressed
+ },
+ },
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "h2",
+ "http/1.1",
+ },
+ },
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithSHA1,
+ PSSWithSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ },
+ },
+ &SCTExtension{},
+ &KeyShareExtension{
+ KeyShares: []KeyShare{
+ {
+ Group: GREASE_PLACEHOLDER,
+ Data: []byte{
+ 0,
+ },
+ },
+ {
+ Group: X25519,
+ },
+ },
+ },
+ &PSKKeyExchangeModesExtension{
+ Modes: []uint8{
+ PskModeDHE,
+ },
+ },
+ &SupportedVersionsExtension{
+ Versions: []uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ },
+ },
+ &UtlsCompressCertExtension{
+ Algorithms: []CertCompressionAlgo{
+ CertCompressionZlib,
+ },
+ },
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{
+ GetPaddingLen: BoringPaddingStyle,
+ },
+ },
+ }, nil
+ case Hello360_7_5:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ DISABLED_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ FAKE_TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_RC4_128_SHA,
+ FAKE_TLS_RSA_WITH_RC4_128_MD5,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &SNIExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ CurveP256,
+ CurveP384,
+ CurveP521,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // pointFormatUncompressed
+ },
+ },
+ &SessionTicketExtension{},
+ &NPNExtension{},
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "spdy/2",
+ "spdy/3",
+ "spdy/3.1",
+ "http/1.1",
+ },
+ },
+ &FakeChannelIDExtension{
+ OldExtensionID: true,
+ },
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA1,
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithSHA1,
+ FakeSHA256WithDSA,
+ FakeSHA1WithDSA,
+ },
+ },
+ },
+ }, nil
+ case Hello360_11_0:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS10,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // uncompressed
+ },
+ },
+ &SessionTicketExtension{},
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "h2",
+ "http/1.1",
+ },
+ },
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ PKCS1WithSHA1,
+ },
+ },
+ &SCTExtension{},
+ &FakeChannelIDExtension{
+ OldExtensionID: false,
+ },
+ &KeyShareExtension{
+ KeyShares: []KeyShare{
+ {
+ Group: GREASE_PLACEHOLDER,
+ Data: []byte{
+ 0,
+ },
+ },
+ {
+ Group: X25519,
+ },
+ },
+ },
+ &PSKKeyExchangeModesExtension{
+ Modes: []uint8{
+ PskModeDHE,
+ },
+ },
+ &SupportedVersionsExtension{
+ Versions: []uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ },
+ },
+ &UtlsCompressCertExtension{
+ Algorithms: []CertCompressionAlgo{
+ CertCompressionBrotli,
+ },
+ },
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{
+ GetPaddingLen: BoringPaddingStyle,
+ },
+ },
+ }, nil
+ case HelloQQ_11_1:
+ return ClientHelloSpec{
+ TLSVersMin: VersionTLS10,
+ TLSVersMax: VersionTLS13,
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []uint8{
+ 0x0, // no compression
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{
+ Renegotiation: RenegotiateOnceAsClient,
+ },
+ &SupportedCurvesExtension{
+ Curves: []CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ },
+ },
+ &SupportedPointsExtension{
+ SupportedPoints: []uint8{
+ 0x0, // uncompressed
+ },
+ },
+ &SessionTicketExtension{},
+ &ALPNExtension{
+ AlpnProtocols: []string{
+ "h2",
+ "http/1.1",
+ },
+ },
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{
+ SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ },
+ },
+ &SCTExtension{},
+ &KeyShareExtension{
+ KeyShares: []KeyShare{
+ {
+ Group: GREASE_PLACEHOLDER,
+ Data: []byte{
+ 0,
+ },
+ },
+ {
+ Group: X25519,
+ },
+ },
+ },
+ &PSKKeyExchangeModesExtension{
+ Modes: []uint8{
+ PskModeDHE,
+ },
+ },
+ &SupportedVersionsExtension{
+ Versions: []uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ },
+ },
+ &UtlsCompressCertExtension{
+ Algorithms: []CertCompressionAlgo{
+ CertCompressionBrotli,
+ },
+ },
+ &ApplicationSettingsExtension{
+ SupportedProtocols: []string{
+ "h2",
+ },
+ },
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{
+ GetPaddingLen: BoringPaddingStyle,
+ },
+ },
+ }, nil
+ case HelloChrome_100_PSK:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: []TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPreSharedKeyExtension{},
+ },
+ }, nil
+ case HelloChrome_112_PSK_Shuf:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPreSharedKeyExtension{},
+ }),
+ }, nil
+ case HelloChrome_114_Padding_PSK_Shuf:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle},
+ &UtlsPreSharedKeyExtension{},
+ }),
+ }, nil
+ // Chrome w/ Post-Quantum Key Agreement
+ case HelloChrome_115_PQ_PSK:
+ return ClientHelloSpec{
+ CipherSuites: []uint16{
+ GREASE_PLACEHOLDER,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ CompressionMethods: []byte{
+ 0x00, // compressionNone
+ },
+ Extensions: ShuffleChromeTLSExtensions([]TLSExtension{
+ &UtlsGREASEExtension{},
+ &SNIExtension{},
+ &ExtendedMasterSecretExtension{},
+ &RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient},
+ &SupportedCurvesExtension{[]CurveID{
+ GREASE_PLACEHOLDER,
+ X25519Kyber768Draft00,
+ X25519,
+ CurveP256,
+ CurveP384,
+ }},
+ &SupportedPointsExtension{SupportedPoints: []byte{
+ 0x00, // pointFormatUncompressed
+ }},
+ &SessionTicketExtension{},
+ &ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
+ &StatusRequestExtension{},
+ &SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PSSWithSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PSSWithSHA384,
+ PKCS1WithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA512,
+ }},
+ &SCTExtension{},
+ &KeyShareExtension{[]KeyShare{
+ {Group: CurveID(GREASE_PLACEHOLDER), Data: []byte{0}},
+ {Group: X25519Kyber768Draft00},
+ {Group: X25519},
+ }},
+ &PSKKeyExchangeModesExtension{[]uint8{
+ PskModeDHE,
+ }},
+ &SupportedVersionsExtension{[]uint16{
+ GREASE_PLACEHOLDER,
+ VersionTLS13,
+ VersionTLS12,
+ }},
+ &UtlsCompressCertExtension{[]CertCompressionAlgo{
+ CertCompressionBrotli,
+ }},
+ &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}},
+ &UtlsGREASEExtension{},
+ &UtlsPreSharedKeyExtension{},
+ }),
+ }, nil
+ default:
+ if id.Client == helloRandomized || id.Client == helloRandomizedALPN || id.Client == helloRandomizedNoALPN {
+ // Use empty values as they can be filled later by UConn.ApplyPreset or manually.
+ return generateRandomizedSpec(&id, "", nil)
+ }
+
+ return ClientHelloSpec{}, fmt.Errorf("%w: %s", ErrUnknownClientHelloID, id.Str())
+ }
+}
+
+// ShuffleChromeTLSExtensions shuffles the extensions in the ClientHelloSpec to avoid ossification.
+// It shuffles every extension except GREASE, padding and pre_shared_key extensions.
+//
+// This feature was first introduced by Chrome 106.
+func ShuffleChromeTLSExtensions(exts []TLSExtension) []TLSExtension {
+ // unshufCheck checks if the exts[idx] is a GREASE/padding/pre_shared_key extension,
+ // and returns true on success. For these extensions are considered positionally invariant.
+ var skipShuf = func(idx int, exts []TLSExtension) bool {
+ switch exts[idx].(type) {
+ case *UtlsGREASEExtension, *UtlsPaddingExtension, PreSharedKeyExtension:
+ return true
+ default:
+ return false
+ }
+ }
+
+ // Shuffle other extensions
+ randInt64, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
+ if err != nil {
+ // warning: random could be deterministic
+ rand.Shuffle(len(exts), func(i, j int) {
+ if skipShuf(i, exts) || skipShuf(j, exts) {
+ return // do not shuffle some of the extensions
+ }
+ exts[i], exts[j] = exts[j], exts[i]
+ })
+ fmt.Println("Warning: failed to use a cryptographically secure random number generator. The shuffle can be deterministic.")
+ } else {
+ rand.New(rand.NewSource(randInt64.Int64())).Shuffle(len(exts), func(i, j int) {
+ if skipShuf(i, exts) || skipShuf(j, exts) {
+ return // do not shuffle some of the extensions
+ }
+ exts[i], exts[j] = exts[j], exts[i]
+ })
+ }
+
+ return exts
+}
+
+func (uconn *UConn) applyPresetByID(id ClientHelloID) (err error) {
+
+ if uconn.clientHelloSpec == nil {
+ var spec ClientHelloSpec
+ uconn.ClientHelloID = id
+
+ // choose/generate the spec
+ switch id.Client {
+ case helloRandomized, helloRandomizedNoALPN, helloRandomizedALPN:
+ spec, err = uconn.generateRandomizedSpec()
+ if err != nil {
+ return err
+ }
+ case helloCustom:
+ return nil
+ default:
+ spec, err = UTLSIdToSpec(id)
+ if err != nil {
+ return err
+ }
+ }
+
+ uconn.clientHelloSpec = &spec
+ }
+
+ return uconn.ApplyPreset(uconn.clientHelloSpec)
+}
+
+// ApplyPreset should only be used in conjunction with HelloCustom to apply custom specs.
+// Fields of TLSExtensions that are slices/pointers are shared across different connections with
+// same ClientHelloSpec. It is advised to use different specs and avoid any shared state.
+func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
+ var err error
+
+ err = uconn.SetTLSVers(p.TLSVersMin, p.TLSVersMax, p.Extensions)
+ if err != nil {
+ return err
+ }
+
+ privateHello, clientKeySharePrivate, ech, err := uconn.makeClientHelloForApplyPreset()
+ if err != nil {
+ return err
+ }
+ uconn.HandshakeState.Hello = privateHello.getPublicPtr()
+ if clientKeySharePrivate != nil {
+ uconn.HandshakeState.State13.KeyShareKeys = clientKeySharePrivate.ToPublic()
+ } else {
+ uconn.HandshakeState.State13.KeyShareKeys = &KeySharePrivateKeys{}
+ }
+ uconn.echCtx = ech
+ hello := uconn.HandshakeState.Hello
+
+ switch len(hello.Random) {
+ case 0:
+ hello.Random = make([]byte, 32)
+ _, err := io.ReadFull(uconn.config.rand(), hello.Random)
+ if err != nil {
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ case 32:
+ // carry on
+ default:
+ return errors.New("ClientHello expected length: 32 bytes. Got: " +
+ strconv.Itoa(len(hello.Random)) + " bytes")
+ }
+
+ if len(hello.CompressionMethods) == 0 {
+ hello.CompressionMethods = []uint8{compressionNone}
+ }
+
+ // Currently, GREASE is assumed to come from BoringSSL
+ grease_bytes := make([]byte, 2*ssl_grease_last_index)
+ grease_extensions_seen := 0
+ _, err = io.ReadFull(uconn.config.rand(), grease_bytes)
+ if err != nil {
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ for i := range uconn.greaseSeed {
+ uconn.greaseSeed[i] = binary.LittleEndian.Uint16(grease_bytes[2*i : 2*i+2])
+ }
+ if GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension1) == GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension2) {
+ uconn.greaseSeed[ssl_grease_extension2] ^= 0x1010
+ }
+
+ hello.CipherSuites = make([]uint16, len(p.CipherSuites))
+ copy(hello.CipherSuites, p.CipherSuites)
+ for i := range hello.CipherSuites {
+ if isGREASEUint16(hello.CipherSuites[i]) { // just in case the user set a GREASE value instead of unGREASEd
+ hello.CipherSuites[i] = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_cipher)
+ }
+ }
+
+ // A random session ID is used to detect when the server accepted a ticket
+ // and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
+ // a compatibility measure (see RFC 8446, Section 4.1.2).
+ //
+ // The session ID is not set for QUIC connections (see RFC 9001, Section 8.4).
+ if uconn.quic == nil {
+ var sessionID [32]byte
+ _, err = io.ReadFull(uconn.config.rand(), sessionID[:])
+ if err != nil {
+ return err
+ }
+ uconn.HandshakeState.Hello.SessionId = sessionID[:]
+ }
+
+ uconn.Extensions = make([]TLSExtension, len(p.Extensions))
+ copy(uconn.Extensions, p.Extensions)
+
+ // Check whether NPN extension actually exists
+ var haveNPN bool
+
+ // reGrease, and point things to each other
+ for _, e := range uconn.Extensions {
+ switch ext := e.(type) {
+ case *SNIExtension:
+ if ext.ServerName == "" {
+ ext.ServerName = uconn.config.ServerName
+ }
+ if uconn.config.EncryptedClientHelloConfigList != nil {
+ ext.ServerName = string(ech.config.PublicName)
+ }
+ case *UtlsGREASEExtension:
+ switch grease_extensions_seen {
+ case 0:
+ ext.Value = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension1)
+ case 1:
+ ext.Value = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_extension2)
+ ext.Body = []byte{0}
+ default:
+ return errors.New("at most 2 grease extensions are supported")
+ }
+ grease_extensions_seen += 1
+ case *SupportedCurvesExtension:
+ for i := range ext.Curves {
+ if isGREASEUint16(uint16(ext.Curves[i])) {
+ ext.Curves[i] = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
+ }
+ }
+ case *KeyShareExtension:
+ preferredCurveIsSet := false
+ for i := range ext.KeyShares {
+ curveID := ext.KeyShares[i].Group
+ if isGREASEUint16(uint16(curveID)) { // just in case the user set a GREASE value instead of unGREASEd
+ ext.KeyShares[i].Group = CurveID(GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_group))
+ continue
+ }
+ if len(ext.KeyShares[i].Data) > 1 {
+ continue
+ }
+
+ if curveID == X25519MLKEM768 || curveID == X25519Kyber768Draft00 {
+ ecdheKey, err := generateECDHEKey(uconn.config.rand(), X25519)
+ if err != nil {
+ return err
+ }
+ seed := make([]byte, mlkem.SeedSize)
+ if _, err := io.ReadFull(uconn.config.rand(), seed); err != nil {
+ return err
+ }
+ mlkemKey, err := mlkem.NewDecapsulationKey768(seed)
+ if err != nil {
+ return err
+ }
+
+ if curveID == X25519Kyber768Draft00 {
+ ext.KeyShares[i].Data = append(ecdheKey.PublicKey().Bytes(), mlkemKey.EncapsulationKey().Bytes()...)
+ } else {
+ ext.KeyShares[i].Data = append(mlkemKey.EncapsulationKey().Bytes(), ecdheKey.PublicKey().Bytes()...)
+ }
+ uconn.HandshakeState.State13.KeyShareKeys.Mlkem = mlkemKey
+ uconn.HandshakeState.State13.KeyShareKeys.MlkemEcdhe = ecdheKey
+ } else {
+ ecdheKey, err := generateECDHEKey(uconn.config.rand(), curveID)
+ if err != nil {
+ return fmt.Errorf("unsupported Curve in KeyShareExtension: %v."+
+ "To mimic it, fill the Data(key) field manually", curveID)
+ }
+
+ ext.KeyShares[i].Data = ecdheKey.PublicKey().Bytes()
+ if !preferredCurveIsSet {
+ // only do this once for the first non-grease curve
+ uconn.HandshakeState.State13.KeyShareKeys.Ecdhe = ecdheKey
+ preferredCurveIsSet = true
+ }
+ }
+ }
+ case *SupportedVersionsExtension:
+ for i := range ext.Versions {
+ if isGREASEUint16(ext.Versions[i]) { // just in case the user set a GREASE value instead of unGREASEd
+ ext.Versions[i] = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_version)
+ }
+ }
+ case *NPNExtension:
+ haveNPN = true
+ }
+ }
+
+ // The default golang behavior in makeClientHello always sets NextProtoNeg if NextProtos is set,
+ // but NextProtos is also used by ALPN and our spec nmay not actually have a NPN extension
+ hello.NextProtoNeg = haveNPN
+
+ err = uconn.sessionController.syncSessionExts()
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (uconn *UConn) generateRandomizedSpec() (ClientHelloSpec, error) {
+ return generateRandomizedSpec(&uconn.ClientHelloID, uconn.serverName, uconn.config.NextProtos)
+}
+
+func generateRandomizedSpec(
+ id *ClientHelloID,
+ serverName string,
+ nextProtos []string,
+) (ClientHelloSpec, error) {
+ p := ClientHelloSpec{}
+
+ if id.Seed == nil {
+ seed, err := NewPRNGSeed()
+ if err != nil {
+ return p, err
+ }
+ id.Seed = seed
+ }
+
+ r, err := newPRNGWithSeed(id.Seed)
+ if err != nil {
+ return p, err
+ }
+
+ if id.Weights == nil {
+ id.Weights = &DefaultWeights
+ }
+
+ var WithALPN bool
+ switch id.Client {
+ case helloRandomizedALPN:
+ WithALPN = true
+ case helloRandomizedNoALPN:
+ WithALPN = false
+ case helloRandomized:
+ if r.FlipWeightedCoin(id.Weights.Extensions_Append_ALPN) {
+ WithALPN = true
+ } else {
+ WithALPN = false
+ }
+ default:
+ return p, fmt.Errorf("using non-randomized ClientHelloID %v to generate randomized spec", id.Client)
+ }
+
+ p.CipherSuites = defaultCipherSuites()
+ shuffledSuites, err := shuffledCiphers(r)
+ if err != nil {
+ return p, err
+ }
+
+ if r.FlipWeightedCoin(id.Weights.TLSVersMax_Set_VersionTLS13) {
+ // randomize min TLS version
+ minTLSVersCandidates := []uint16{VersionTLS10, VersionTLS12}
+ p.TLSVersMin = minTLSVersCandidates[r.Intn(len(minTLSVersCandidates))]
+ p.TLSVersMax = VersionTLS13
+ tls13ciphers := make([]uint16, len(defaultCipherSuitesTLS13))
+ copy(tls13ciphers, defaultCipherSuitesTLS13)
+ r.rand.Shuffle(len(tls13ciphers), func(i, j int) {
+ tls13ciphers[i], tls13ciphers[j] = tls13ciphers[j], tls13ciphers[i]
+ })
+ // appending TLS 1.3 ciphers before TLS 1.2, since that's what popular implementations do
+ shuffledSuites = append(tls13ciphers, shuffledSuites...)
+
+ // TLS 1.3 forbids RC4 in any configurations
+ shuffledSuites = removeRC4Ciphers(shuffledSuites)
+ } else {
+ p.TLSVersMin = VersionTLS10
+ p.TLSVersMax = VersionTLS12
+ }
+
+ p.CipherSuites = removeRandomCiphers(r, shuffledSuites, id.Weights.CipherSuites_Remove_RandomCiphers)
+
+ sni := SNIExtension{serverName}
+ sessionTicket := SessionTicketExtension{}
+
+ sigAndHashAlgos := []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ PKCS1WithSHA256,
+ ECDSAWithP384AndSHA384,
+ PKCS1WithSHA384,
+ PKCS1WithSHA1,
+ PKCS1WithSHA512,
+ }
+
+ if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_ECDSAWithSHA1) {
+ sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithSHA1)
+ }
+ if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_ECDSAWithP521AndSHA512) {
+ sigAndHashAlgos = append(sigAndHashAlgos, ECDSAWithP521AndSHA512)
+ }
+ if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_PSSWithSHA256) || p.TLSVersMax == VersionTLS13 {
+ // https://tools.ietf.org/html/rfc8446 says "...RSASSA-PSS (which is mandatory in TLS 1.3)..."
+ sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA256)
+ if r.FlipWeightedCoin(id.Weights.SigAndHashAlgos_Append_PSSWithSHA384_PSSWithSHA512) {
+ // these usually go together
+ sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA384)
+ sigAndHashAlgos = append(sigAndHashAlgos, PSSWithSHA512)
+ }
+ }
+
+ r.rand.Shuffle(len(sigAndHashAlgos), func(i, j int) {
+ sigAndHashAlgos[i], sigAndHashAlgos[j] = sigAndHashAlgos[j], sigAndHashAlgos[i]
+ })
+ sigAndHash := SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: sigAndHashAlgos}
+
+ status := StatusRequestExtension{}
+ sct := SCTExtension{}
+ ems := ExtendedMasterSecretExtension{}
+ points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
+
+ curveIDs := []CurveID{}
+ if r.FlipWeightedCoin(id.Weights.CurveIDs_Append_X25519) && p.TLSVersMax == VersionTLS13 {
+ curveIDs = append(curveIDs, X25519MLKEM768)
+ }
+ if r.FlipWeightedCoin(id.Weights.CurveIDs_Append_X25519) || p.TLSVersMax == VersionTLS13 {
+ curveIDs = append(curveIDs, X25519)
+ }
+ curveIDs = append(curveIDs, CurveP256, CurveP384)
+ if r.FlipWeightedCoin(id.Weights.CurveIDs_Append_CurveP521) {
+ curveIDs = append(curveIDs, CurveP521)
+ }
+
+ curves := SupportedCurvesExtension{curveIDs}
+
+ padding := UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle}
+ reneg := RenegotiationInfoExtension{Renegotiation: RenegotiateOnceAsClient}
+
+ p.Extensions = []TLSExtension{
+ &sni,
+ &sessionTicket,
+ &sigAndHash,
+ &points,
+ &curves,
+ }
+
+ if WithALPN {
+ if len(nextProtos) == 0 {
+ // if user didn't specify alpn yet, choose something popular
+ nextProtos = []string{"h2", "http/1.1"}
+ }
+ alpn := ALPNExtension{AlpnProtocols: nextProtos}
+ p.Extensions = append(p.Extensions, &alpn)
+ }
+
+ if r.FlipWeightedCoin(id.Weights.Extensions_Append_Padding) || p.TLSVersMax == VersionTLS13 {
+ // always include for TLS 1.3, since TLS 1.3 ClientHellos are often over 256 bytes
+ // and that's when padding is required to work around buggy middleboxes
+ p.Extensions = append(p.Extensions, &padding)
+ }
+ if r.FlipWeightedCoin(id.Weights.Extensions_Append_Status) {
+ p.Extensions = append(p.Extensions, &status)
+ }
+ if r.FlipWeightedCoin(id.Weights.Extensions_Append_SCT) {
+ p.Extensions = append(p.Extensions, &sct)
+ }
+ if r.FlipWeightedCoin(id.Weights.Extensions_Append_Reneg) {
+ p.Extensions = append(p.Extensions, &reneg)
+ }
+ if r.FlipWeightedCoin(id.Weights.Extensions_Append_EMS) {
+ p.Extensions = append(p.Extensions, &ems)
+ }
+ if p.TLSVersMax == VersionTLS13 {
+ ks := KeyShareExtension{[]KeyShare{
+ {Group: X25519}, // the key for the group will be generated later
+ }}
+ if r.FlipWeightedCoin(id.Weights.FirstKeyShare_Set_CurveP256) { // legacy setting, not used by default
+ ks.KeyShares[0].Group = CurveP256
+ } else {
+ if r.FlipWeightedCoin(id.Weights.KeyShare_Append_RandomGroups) {
+ ks.KeyShares = append(ks.KeyShares, KeyShare{Group: CurveP256})
+ }
+ if r.FlipWeightedCoin(id.Weights.KeyShare_Append_RandomGroups) {
+ ks.KeyShares = append([]KeyShare{{Group: X25519MLKEM768}}, ks.KeyShares...)
+ }
+ }
+ pskExchangeModes := PSKKeyExchangeModesExtension{[]uint8{pskModeDHE}}
+ supportedVersionsExt := SupportedVersionsExtension{
+ Versions: makeSupportedVersions(p.TLSVersMin, p.TLSVersMax),
+ }
+ p.Extensions = append(p.Extensions, &ks, &pskExchangeModes, &supportedVersionsExt)
+
+ // Randomly add an ALPS extension. ALPS is TLS 1.3-only and may only
+ // appear when an ALPN extension is present
+ // (https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01#section-3).
+ // ALPS is a draft specification at this time, but appears in
+ // Chrome/BoringSSL.
+ if WithALPN {
+
+ // ALPS is a new addition to generateRandomizedSpec. Use a salted
+ // seed to create a new, independent PRNG, so that a seed used
+ // with the previous version of generateRandomizedSpec will
+ // produce the exact same spec as long as ALPS isn't selected.
+ r, err := newPRNGWithSaltedSeed(id.Seed, "ALPS")
+ if err != nil {
+ return p, err
+ }
+ if r.FlipWeightedCoin(id.Weights.Extensions_Append_ALPS) {
+ // As with the ALPN case above, default to something popular
+ // (unlike ALPN, ALPS can't yet be specified in uconn.config).
+ alps := &ApplicationSettingsExtension{SupportedProtocols: []string{"h2"}}
+ p.Extensions = append(p.Extensions, alps)
+ }
+ }
+
+ // TODO: randomly add DelegatedCredentialsExtension, once it is
+ // sufficiently popular.
+ }
+ r.rand.Shuffle(len(p.Extensions), func(i, j int) {
+ p.Extensions[i], p.Extensions[j] = p.Extensions[j], p.Extensions[i]
+ })
+
+ return p, nil
+}
+
+func removeRandomCiphers(r *prng, s []uint16, maxRemovalProbability float64) []uint16 {
+ // removes elements in place
+ // probability to remove increases for further elements
+ // never remove first cipher
+ if len(s) <= 1 {
+ return s
+ }
+
+ // remove random elements
+ floatLen := float64(len(s))
+ sliceLen := len(s)
+ for i := 1; i < sliceLen; i++ {
+ if r.FlipWeightedCoin(maxRemovalProbability * float64(i) / floatLen) {
+ s = append(s[:i], s[i+1:]...)
+ sliceLen--
+ i--
+ }
+ }
+ return s[:sliceLen]
+}
+
+func shuffledCiphers(r *prng) ([]uint16, error) {
+ ciphers := make(sortableCiphers, len(cipherSuites))
+ perm := r.Perm(len(cipherSuites))
+ for i, suite := range cipherSuites {
+ ciphers[i] = sortableCipher{suite: suite.id,
+ isObsolete: ((suite.flags & suiteTLS12) == 0),
+ randomTag: perm[i]}
+ }
+ sort.Sort(ciphers)
+ return ciphers.GetCiphers(), nil
+}
+
+type sortableCipher struct {
+ isObsolete bool
+ randomTag int
+ suite uint16
+}
+
+type sortableCiphers []sortableCipher
+
+func (ciphers sortableCiphers) Len() int {
+ return len(ciphers)
+}
+
+func (ciphers sortableCiphers) Less(i, j int) bool {
+ if ciphers[i].isObsolete && !ciphers[j].isObsolete {
+ return false
+ }
+ if ciphers[j].isObsolete && !ciphers[i].isObsolete {
+ return true
+ }
+ return ciphers[i].randomTag < ciphers[j].randomTag
+}
+
+func (ciphers sortableCiphers) Swap(i, j int) {
+ ciphers[i], ciphers[j] = ciphers[j], ciphers[i]
+}
+
+func (ciphers sortableCiphers) GetCiphers() []uint16 {
+ cipherIDs := make([]uint16, len(ciphers))
+ for i := range ciphers {
+ cipherIDs[i] = ciphers[i].suite
+ }
+ return cipherIDs
+}
+
+func removeRC4Ciphers(s []uint16) []uint16 {
+ // removes elements in place
+ sliceLen := len(s)
+ for i := 0; i < sliceLen; i++ {
+ cipher := s[i]
+ if cipher == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA ||
+ cipher == TLS_ECDHE_RSA_WITH_RC4_128_SHA ||
+ cipher == TLS_RSA_WITH_RC4_128_SHA {
+ s = append(s[:i], s[i+1:]...)
+ sliceLen--
+ i--
+ }
+ }
+ return s[:sliceLen]
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_pre_shared_key.go b/vendor/github.com/refraction-networking/utls/u_pre_shared_key.go
new file mode 100644
index 00000000..f1e4995e
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_pre_shared_key.go
@@ -0,0 +1,486 @@
+package tls
+
+import (
+ "encoding/json"
+ "errors"
+ "io"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+var ErrEmptyPsk = errors.New("tls: empty psk detected; remove the psk extension for this connection or set OmitEmptyPsk to true to conceal it in utls")
+
+type PreSharedKeyCommon struct {
+ Identities []PskIdentity
+ Binders [][]byte
+ BinderKey []byte // this will be used to compute the binder when hello message is ready
+ EarlySecret []byte
+ Session *SessionState
+}
+
+// The lifecycle of a PreSharedKeyExtension:
+//
+// Creation Phase:
+// - The extension is created.
+//
+// Write Phase:
+//
+// - [writeToUConn() called]:
+//
+// > - During this phase, it is important to note that implementations should not write any session data to the UConn (Underlying Connection) as the session is not yet loaded. The session context is not active at this point.
+//
+// Initialization Phase:
+//
+// - [IsInitialized() called]:
+//
+// If IsInitialized() returns true
+//
+// > - GetPreSharedKeyCommon() will be called subsequently and the PSK states in handshake/clientHello will be fully initialized.
+//
+// If IsInitialized() returns false:
+//
+// > - [conn.loadSession() called]:
+//
+// >> - Once the session is available:
+//
+// >>> - [InitializeByUtls() called]:
+//
+// >>>> - The InitializeByUtls() method is invoked to initialize the extension based on the loaded session data.
+//
+// >>>> - This step prepares the extension for further processing.
+//
+// Marshal Phase:
+//
+// - [Len() called], [Read() called]:
+//
+// > - Implementations should marshal the extension into bytes, using placeholder binders to maintain the correct length.
+//
+// Binders Preparation Phase:
+//
+// - [PatchBuiltHello(hello) called]:
+//
+// > - The client hello is already marshaled in the "hello.Raw" format.
+//
+// > - Implementations are expected to update the binders within the marshaled client hello.
+//
+// - [GetPreSharedKeyCommon() called]:
+//
+// > - Implementations should gather and provide the final pre-shared key (PSK) related data.
+//
+// > - This data will be incorporated into both the clientHello and HandshakeState, ensuring that the PSK-related information is properly set and ready for the handshake process.
+type PreSharedKeyExtension interface {
+ // TLSExtension must be implemented by all PreSharedKeyExtension implementations.
+ TLSExtension
+
+ // If false is returned, utls will invoke `InitializeByUtls()` for the necessary initialization.
+ Initializable
+
+ SetOmitEmptyPsk(val bool)
+
+ // InitializeByUtls is invoked when IsInitialized() returns false.
+ // It initializes the extension using a real and valid TLS 1.3 session.
+ InitializeByUtls(session *SessionState, earlySecret []byte, binderKey []byte, identities []PskIdentity)
+
+ // GetPreSharedKeyCommon retrieves the final PreSharedKey-related states as defined in PreSharedKeyCommon.
+ GetPreSharedKeyCommon() PreSharedKeyCommon
+
+ // PatchBuiltHello is called once the hello message is fully applied and marshaled.
+ // Its purpose is to update the binders of PSK (Pre-Shared Key) identities.
+ PatchBuiltHello(hello *PubClientHelloMsg) error
+
+ mustEmbedUnimplementedPreSharedKeyExtension() // this works like a type guard
+}
+
+type UnimplementedPreSharedKeyExtension struct{}
+
+func (UnimplementedPreSharedKeyExtension) mustEmbedUnimplementedPreSharedKeyExtension() {}
+
+func (*UnimplementedPreSharedKeyExtension) IsInitialized() bool {
+ panic("tls: IsInitialized is not implemented for the PreSharedKeyExtension")
+}
+
+func (*UnimplementedPreSharedKeyExtension) InitializeByUtls(session *SessionState, earlySecret []byte, binderKey []byte, identities []PskIdentity) {
+ panic("tls: Initialize is not implemented for the PreSharedKeyExtension")
+}
+
+func (*UnimplementedPreSharedKeyExtension) writeToUConn(*UConn) error {
+ panic("tls: writeToUConn is not implemented for the PreSharedKeyExtension")
+}
+
+func (*UnimplementedPreSharedKeyExtension) Len() int {
+ panic("tls: Len is not implemented for the PreSharedKeyExtension")
+}
+
+func (*UnimplementedPreSharedKeyExtension) Read([]byte) (int, error) {
+ panic("tls: Read is not implemented for the PreSharedKeyExtension")
+}
+
+func (*UnimplementedPreSharedKeyExtension) GetPreSharedKeyCommon() PreSharedKeyCommon {
+ panic("tls: GetPreSharedKeyCommon is not implemented for the PreSharedKeyExtension")
+}
+
+func (*UnimplementedPreSharedKeyExtension) PatchBuiltHello(hello *PubClientHelloMsg) error {
+ panic("tls: ReadWithRawHello is not implemented for the PreSharedKeyExtension")
+}
+
+func (*UnimplementedPreSharedKeyExtension) SetOmitEmptyPsk(val bool) {
+ panic("tls: SetOmitEmptyPsk is not implemented for the PreSharedKeyExtension")
+}
+
+// UtlsPreSharedKeyExtension is an extension used to set the PSK extension in the
+// ClientHello.
+type UtlsPreSharedKeyExtension struct {
+ UnimplementedPreSharedKeyExtension
+ PreSharedKeyCommon
+ cipherSuite *cipherSuiteTLS13
+ cachedLength *int
+ // Deprecated: Set OmitEmptyPsk in Config instead.
+ OmitEmptyPsk bool
+}
+
+func (e *UtlsPreSharedKeyExtension) IsInitialized() bool {
+ return e.Session != nil
+}
+
+func (e *UtlsPreSharedKeyExtension) InitializeByUtls(session *SessionState, earlySecret []byte, binderKey []byte, identities []PskIdentity) {
+ e.Session = session
+ e.EarlySecret = earlySecret
+ e.BinderKey = binderKey
+ e.cipherSuite = cipherSuiteTLS13ByID(e.Session.cipherSuite)
+ e.Identities = identities
+ e.Binders = make([][]byte, 0, len(e.Identities))
+ for i := 0; i < len(e.Identities); i++ {
+ e.Binders = append(e.Binders, make([]byte, e.cipherSuite.hash.Size()))
+ }
+}
+
+func (e *UtlsPreSharedKeyExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.TicketSupported = true // This doesn't matter though, as utls doesn't care about this field. We write this for consistency.
+ return nil
+}
+
+func (e *UtlsPreSharedKeyExtension) GetPreSharedKeyCommon() PreSharedKeyCommon {
+ return e.PreSharedKeyCommon
+}
+
+func pskExtLen(identities []PskIdentity, binders [][]byte) int {
+ if len(identities) == 0 || len(binders) == 0 {
+ // If there isn't psk identities, we don't write this ticket to the client hello, and therefore the length should be 0.
+ return 0
+ }
+ length := 4 // extension type + extension length
+ length += 2 // identities length
+ for _, identity := range identities {
+ length += 2 + len(identity.Label) + 4 // identity length + identity + obfuscated ticket age
+ }
+ length += 2 // binders length
+ for _, binder := range binders {
+ length += len(binder) + 1
+ }
+ return length
+}
+
+func (e *UtlsPreSharedKeyExtension) Len() int {
+ if e.Session == nil {
+ return 0
+ }
+ if e.cachedLength != nil {
+ return *e.cachedLength
+ }
+ length := pskExtLen(e.Identities, e.Binders)
+ e.cachedLength = &length
+ return length
+}
+
+func readPskIntoBytes(b []byte, identities []PskIdentity, binders [][]byte) (int, error) {
+ extLen := pskExtLen(identities, binders)
+ if extLen == 0 {
+ return 0, io.EOF
+ }
+ if len(b) < extLen {
+ return 0, io.ErrShortBuffer
+ }
+
+ b[0] = byte(extensionPreSharedKey >> 8)
+ b[1] = byte(extensionPreSharedKey)
+ b[2] = byte((extLen - 4) >> 8)
+ b[3] = byte(extLen - 4)
+
+ // identities length
+ identitiesLength := 0
+ for _, identity := range identities {
+ identitiesLength += 2 + len(identity.Label) + 4 // identity length + identity + obfuscated ticket age
+ }
+ b[4] = byte(identitiesLength >> 8)
+ b[5] = byte(identitiesLength)
+
+ // identities
+ offset := 6
+ for _, identity := range identities {
+ b[offset] = byte(len(identity.Label) >> 8)
+ b[offset+1] = byte(len(identity.Label))
+ offset += 2
+ copy(b[offset:], identity.Label)
+ offset += len(identity.Label)
+ b[offset] = byte(identity.ObfuscatedTicketAge >> 24)
+ b[offset+1] = byte(identity.ObfuscatedTicketAge >> 16)
+ b[offset+2] = byte(identity.ObfuscatedTicketAge >> 8)
+ b[offset+3] = byte(identity.ObfuscatedTicketAge)
+ offset += 4
+ }
+
+ // binders length
+ bindersLength := 0
+ for _, binder := range binders {
+ // check if binder size is valid
+ bindersLength += len(binder) + 1 // binder length + binder
+ }
+ b[offset] = byte(bindersLength >> 8)
+ b[offset+1] = byte(bindersLength)
+ offset += 2
+
+ // binders
+ for _, binder := range binders {
+ b[offset] = byte(len(binder))
+ offset++
+ copy(b[offset:], binder)
+ offset += len(binder)
+ }
+
+ return extLen, io.EOF
+}
+
+func (e *UtlsPreSharedKeyExtension) SetOmitEmptyPsk(val bool) {
+ e.OmitEmptyPsk = val
+}
+
+func (e *UtlsPreSharedKeyExtension) Read(b []byte) (int, error) {
+ if !e.OmitEmptyPsk && e.Len() == 0 {
+ return 0, ErrEmptyPsk
+ }
+ return readPskIntoBytes(b, e.Identities, e.Binders)
+}
+
+func (e *UtlsPreSharedKeyExtension) PatchBuiltHello(hello *PubClientHelloMsg) error {
+ if e.Len() == 0 {
+ return nil
+ }
+ private := hello.getCachedPrivatePtr()
+ if private == nil {
+ private = hello.getPrivatePtr()
+ }
+ private.original = hello.Raw
+ private.pskBinders = e.Binders // set the placeholder to the private Hello
+
+ //--- mirror loadSession() begin ---//
+ transcript := e.cipherSuite.hash.New()
+ helloBytes, err := private.marshalWithoutBinders() // no marshal() will be actually called, as we have set the field `raw`
+ if err != nil {
+ return err
+ }
+ transcript.Write(helloBytes)
+ pskBinders := [][]byte{e.cipherSuite.finishedHash(e.BinderKey, transcript)}
+
+ if err := private.updateBinders(pskBinders); err != nil {
+ return err
+ }
+
+ // copied from handshake_messages.go in 1.22
+ lenWithoutBinders := len(helloBytes)
+ b := cryptobyte.NewFixedBuilder(private.original[:lenWithoutBinders])
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, binder := range private.pskBinders {
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(binder)
+ })
+ }
+ })
+ if out, err := b.Bytes(); err != nil || len(out) != len(private.original) {
+ return errors.New("tls: internal error: failed to update binders")
+ }
+
+ //--- mirror loadSession() end ---//
+ e.Binders = pskBinders
+
+ // no need to care about other PSK related fields, they will be handled separately
+
+ return io.EOF
+}
+
+func (e *UtlsPreSharedKeyExtension) Write(b []byte) (int, error) {
+ return len(b), nil // ignore the data
+}
+
+func (e *UtlsPreSharedKeyExtension) UnmarshalJSON(_ []byte) error {
+ return nil // ignore the data
+}
+
+// FakePreSharedKeyExtension is an extension used to set the PSK extension in the
+// ClientHello.
+//
+// It does not compute binders based on ClientHello, but uses the binders specified instead.
+// We still need to learn more of the safety
+// of hardcoding both Identities and Binders without recalculating the latter.
+type FakePreSharedKeyExtension struct {
+ UnimplementedPreSharedKeyExtension
+
+ Identities []PskIdentity `json:"identities"`
+ Binders [][]byte `json:"binders"`
+ // Deprecated: Set OmitEmptyPsk in Config instead.
+ OmitEmptyPsk bool
+}
+
+func (e *FakePreSharedKeyExtension) IsInitialized() bool {
+ return e.Identities != nil && e.Binders != nil
+}
+
+func (e *FakePreSharedKeyExtension) InitializeByUtls(session *SessionState, earlySecret []byte, binderKey []byte, identities []PskIdentity) {
+ panic("InitializeByUtls failed: don't let utls initialize FakePreSharedKeyExtension; provide your own identities and binders or use UtlsPreSharedKeyExtension")
+}
+
+func (e *FakePreSharedKeyExtension) writeToUConn(uc *UConn) error {
+ if uc.config.ClientSessionCache == nil {
+ return nil // don't write the extension if there is no session cache
+ }
+ if session, ok := uc.config.ClientSessionCache.Get(uc.clientSessionCacheKey()); !ok || session == nil {
+ return nil // don't write the extension if there is no session cache available for this session
+ }
+ uc.HandshakeState.Hello.PskIdentities = e.Identities
+ uc.HandshakeState.Hello.PskBinders = e.Binders
+ return nil
+}
+
+func (e *FakePreSharedKeyExtension) Len() int {
+ return pskExtLen(e.Identities, e.Binders)
+}
+
+func (e *FakePreSharedKeyExtension) SetOmitEmptyPsk(val bool) {
+ e.OmitEmptyPsk = val
+}
+
+func (e *FakePreSharedKeyExtension) Read(b []byte) (int, error) {
+ if !e.OmitEmptyPsk && e.Len() == 0 {
+ return 0, ErrEmptyPsk
+ }
+ for _, b := range e.Binders {
+ if !(anyTrue(validHashLen, func(_ int, valid *int) bool {
+ return len(b) == *valid
+ })) {
+ return 0, errors.New("tls: FakePreSharedKeyExtension.Read failed: invalid binder size")
+ }
+ }
+
+ return readPskIntoBytes(b, e.Identities, e.Binders)
+}
+
+func (e *FakePreSharedKeyExtension) GetPreSharedKeyCommon() PreSharedKeyCommon {
+ return PreSharedKeyCommon{
+ Identities: e.Identities,
+ Binders: e.Binders,
+ }
+}
+
+var validHashLen = mapSlice(cipherSuitesTLS13, func(c *cipherSuiteTLS13) int {
+ return c.hash.Size()
+})
+
+func (*FakePreSharedKeyExtension) PatchBuiltHello(*PubClientHelloMsg) error {
+ return nil // no need to patch the hello since we don't need to update binders
+}
+
+func (e *FakePreSharedKeyExtension) Write(b []byte) (n int, err error) {
+ fullLen := len(b)
+ s := cryptobyte.String(b)
+
+ var identitiesLength uint16
+ if !s.ReadUint16(&identitiesLength) {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+
+ // identities
+ for identitiesLength > 0 {
+ var identityLength uint16
+ if !s.ReadUint16(&identityLength) {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+ identitiesLength -= 2
+
+ if identityLength > identitiesLength {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+
+ var identity []byte
+ if !s.ReadBytes(&identity, int(identityLength)) {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+
+ identitiesLength -= identityLength // identity
+
+ var obfuscatedTicketAge uint32
+ if !s.ReadUint32(&obfuscatedTicketAge) {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+
+ e.Identities = append(e.Identities, PskIdentity{
+ Label: identity,
+ ObfuscatedTicketAge: obfuscatedTicketAge,
+ })
+
+ identitiesLength -= 4 // obfuscated ticket age
+ }
+
+ var bindersLength uint16
+ if !s.ReadUint16(&bindersLength) {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+
+ // binders
+ for bindersLength > 0 {
+ var binderLength uint8
+ if !s.ReadUint8(&binderLength) {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+ bindersLength -= 1
+
+ if uint16(binderLength) > bindersLength {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+
+ var binder []byte
+ if !s.ReadBytes(&binder, int(binderLength)) {
+ return 0, errors.New("tls: invalid PSK extension")
+ }
+
+ e.Binders = append(e.Binders, binder)
+
+ bindersLength -= uint16(binderLength)
+ }
+
+ return fullLen, nil
+}
+
+func (e *FakePreSharedKeyExtension) UnmarshalJSON(data []byte) error {
+ var pskAccepter struct {
+ PskIdentities []PskIdentity `json:"identities"`
+ PskBinders [][]byte `json:"binders"`
+ }
+
+ if err := json.Unmarshal(data, &pskAccepter); err != nil {
+ return err
+ }
+
+ e.Identities = pskAccepter.PskIdentities
+ e.Binders = pskAccepter.PskBinders
+ return nil
+}
+
+// type guard
+var (
+ _ PreSharedKeyExtension = (*UtlsPreSharedKeyExtension)(nil)
+ _ TLSExtensionJSON = (*UtlsPreSharedKeyExtension)(nil)
+ _ PreSharedKeyExtension = (*FakePreSharedKeyExtension)(nil)
+ _ TLSExtensionJSON = (*FakePreSharedKeyExtension)(nil)
+ _ TLSExtensionWriter = (*FakePreSharedKeyExtension)(nil)
+)
+
+// type ExternalPreSharedKeyExtension struct{} // TODO: wait for whoever cares about external PSK to implement it
diff --git a/vendor/github.com/refraction-networking/utls/u_prng.go b/vendor/github.com/refraction-networking/utls/u_prng.go
new file mode 100644
index 00000000..cbd84081
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_prng.go
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2019, Psiphon Inc.
+ * All rights reserved.
+ *
+ * Released under utls licence:
+ * https://github.com/refraction-networking/utls/blob/master/LICENSE
+ */
+
+// This code is a pared down version of:
+// https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/158caea562287284cc3fa5fcd1b3c97b1addf659/psiphon/common/prng/prng.go
+
+package tls
+
+import (
+ crypto_rand "crypto/rand"
+ "encoding/binary"
+ "io"
+ "math"
+ "math/rand"
+ "sync"
+
+ "golang.org/x/crypto/hkdf"
+ "golang.org/x/crypto/sha3"
+)
+
+const (
+ PRNGSeedLength = 32
+)
+
+// PRNGSeed is a PRNG seed.
+type PRNGSeed [PRNGSeedLength]byte
+
+// NewPRNGSeed creates a new PRNG seed using crypto/rand.Read.
+func NewPRNGSeed() (*PRNGSeed, error) {
+ seed := new(PRNGSeed)
+ _, err := crypto_rand.Read(seed[:])
+ if err != nil {
+ return nil, err
+ }
+ return seed, nil
+}
+
+// newSaltedPRNGSeed creates a new seed derived from an existing seed and a
+// salt. A HKDF is applied to the seed and salt.
+//
+// newSaltedPRNGSeed is intended for use cases where a single seed needs to be
+// used in distinct contexts to produce independent random streams.
+func newSaltedPRNGSeed(seed *PRNGSeed, salt string) (*PRNGSeed, error) {
+ saltedSeed := new(PRNGSeed)
+ _, err := io.ReadFull(
+ hkdf.New(sha3.New256, seed[:], []byte(salt), nil), saltedSeed[:])
+ if err != nil {
+ return nil, err
+ }
+ return saltedSeed, nil
+}
+
+// prng is a seeded, unbiased PRNG based on SHAKE256. that is suitable for use
+// cases such as obfuscation. Seeding is based on crypto/rand.Read.
+//
+// This PRNG is _not_ for security use cases including production cryptographic
+// key generation.
+//
+// It is safe to make concurrent calls to a PRNG instance.
+//
+// PRNG conforms to io.Reader and math/rand.Source, with additional helper
+// functions.
+type prng struct {
+ rand *rand.Rand
+ randomStreamMutex sync.Mutex
+ randomStream sha3.ShakeHash
+}
+
+// newPRNG generates a seed and creates a PRNG with that seed.
+func newPRNG() (*prng, error) {
+ seed, err := NewPRNGSeed()
+ if err != nil {
+ return nil, err
+ }
+ return newPRNGWithSeed(seed)
+}
+
+// newPRNGWithSeed initializes a new PRNG using an existing seed.
+func newPRNGWithSeed(seed *PRNGSeed) (*prng, error) {
+ shake := sha3.NewShake256()
+ _, err := shake.Write(seed[:])
+ if err != nil {
+ return nil, err
+ }
+ p := &prng{
+ randomStream: shake,
+ }
+ p.rand = rand.New(p)
+ return p, nil
+}
+
+// newPRNGWithSaltedSeed initializes a new PRNG using a seed derived from an
+// existing seed and a salt with NewSaltedSeed.
+func newPRNGWithSaltedSeed(seed *PRNGSeed, salt string) (*prng, error) {
+ saltedSeed, err := newSaltedPRNGSeed(seed, salt)
+ if err != nil {
+ return nil, err
+ }
+ return newPRNGWithSeed(saltedSeed)
+}
+
+// Read reads random bytes from the PRNG stream into b. Read conforms to
+// io.Reader and always returns len(p), nil.
+func (p *prng) Read(b []byte) (int, error) {
+ p.randomStreamMutex.Lock()
+ defer p.randomStreamMutex.Unlock()
+
+ // ShakeHash.Read never returns an error:
+ // https://godoc.org/golang.org/x/crypto/sha3#ShakeHash
+ _, _ = io.ReadFull(p.randomStream, b)
+
+ return len(b), nil
+}
+
+// Int63 is equivalent to math/read.Int63.
+func (p *prng) Int63() int64 {
+ i := p.Uint64()
+ return int64(i & (1<<63 - 1))
+}
+
+// Int63 is equivalent to math/read.Uint64.
+func (p *prng) Uint64() uint64 {
+ var b [8]byte
+ p.Read(b[:])
+ return binary.BigEndian.Uint64(b[:])
+}
+
+// Seed must exist in order to use a PRNG as a math/rand.Source. This call is
+// not supported and ignored.
+func (p *prng) Seed(_ int64) {
+}
+
+// FlipWeightedCoin returns the result of a weighted
+// random coin flip. If the weight is 0.5, the outcome
+// is equally likely to be true or false. If the weight
+// is 1.0, the outcome is always true, and if the
+// weight is 0.0, the outcome is always false.
+//
+// Input weights > 1.0 are treated as 1.0.
+func (p *prng) FlipWeightedCoin(weight float64) bool {
+ if weight > 1.0 {
+ weight = 1.0
+ }
+ f := float64(p.Int63()) / float64(math.MaxInt64)
+ return f > 1.0-weight
+}
+
+// Intn is equivalent to math/read.Intn, except it returns 0 if n <= 0
+// instead of panicking.
+func (p *prng) Intn(n int) int {
+ if n <= 0 {
+ return 0
+ }
+ return p.rand.Intn(n)
+}
+
+// Int63n is equivalent to math/read.Int63n, except it returns 0 if n <= 0
+// instead of panicking.
+func (p *prng) Int63n(n int64) int64 {
+ if n <= 0 {
+ return 0
+ }
+ return p.rand.Int63n(n)
+}
+
+// Intn is equivalent to math/read.Perm.
+func (p *prng) Perm(n int) []int {
+ return p.rand.Perm(n)
+}
+
+// Range selects a random integer in [min, max].
+// If min < 0, min is set to 0. If max < min, min is returned.
+func (p *prng) Range(min, max int) int {
+ if min < 0 {
+ min = 0
+ }
+ if max < min {
+ return min
+ }
+ n := p.Intn(max - min + 1)
+ n += min
+ return n
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_public.go b/vendor/github.com/refraction-networking/utls/u_public.go
new file mode 100644
index 00000000..7b2461c0
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_public.go
@@ -0,0 +1,925 @@
+// Copyright 2017 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto"
+ "crypto/ecdh"
+ "crypto/mlkem"
+ "crypto/x509"
+ "hash"
+ "time"
+)
+
+// ClientHandshakeState includes both TLS 1.3-only and TLS 1.2-only states,
+// only one of them will be used, depending on negotiated version.
+//
+// ClientHandshakeState will be converted into and from either
+// - clientHandshakeState (TLS 1.2)
+// - clientHandshakeStateTLS13 (TLS 1.3)
+//
+// uTLS will call .handshake() on one of these private internal states,
+// to perform TLS handshake using standard crypto/tls implementation.
+type PubClientHandshakeState struct {
+ C *Conn
+ ServerHello *PubServerHelloMsg
+ Hello *PubClientHelloMsg
+ MasterSecret []byte
+ Session *SessionState
+
+ State12 TLS12OnlyState
+ State13 TLS13OnlyState
+
+ uconn *UConn
+}
+
+// TLS 1.3 only
+type TLS13OnlyState struct {
+ // Deprecated: Use KeyShareKeys instead. KeyShareKeys will take precedence if both are set.
+ // Support may be removed in the future.
+ EcdheKey *ecdh.PrivateKey
+ // Deprecated: Use KeyShareKeys instead. This variable is no longer used.
+ // Will be removed in the future.
+ KeySharesParams *KeySharesParameters
+ // Deprecated: Use KeyShareKeys instead. This variable is no longer used.
+ // Will be removed in the future.
+ KEMKey *KemPrivateKey
+
+ KeyShareKeys *KeySharePrivateKeys
+ Suite *PubCipherSuiteTLS13
+ EarlySecret []byte
+ BinderKey []byte
+ CertReq *CertificateRequestMsgTLS13
+ UsingPSK bool // don't set this field when building client hello
+ SentDummyCCS bool
+ Transcript hash.Hash
+ TrafficSecret []byte // client_application_traffic_secret_0
+}
+
+// TLS 1.2 and before only
+type TLS12OnlyState struct {
+ FinishedHash FinishedHash
+ Suite PubCipherSuite
+}
+
+func (chs *TLS13OnlyState) private13KeyShareKeys() *keySharePrivateKeys {
+ if chs.KeyShareKeys != nil {
+ return chs.KeyShareKeys.ToPrivate()
+ }
+
+ if chs.EcdheKey != nil {
+ return &keySharePrivateKeys{
+ ecdhe: chs.EcdheKey,
+ }
+ }
+
+ return nil
+}
+
+// func kyberGoToCircl(kyberKey *mlkem768.DecapsulationKey, ecdhKey *ecdh.PrivateKey) (kem.PrivateKey, error) {
+// return hybrid.Kyber768X25519().UnmarshalBinaryPrivateKey(append(ecdhKey.Bytes(), kyberKey.Bytes()...))
+// }
+
+func (chs *PubClientHandshakeState) toPrivate13() *clientHandshakeStateTLS13 {
+ if chs == nil {
+ return nil
+ } else {
+ return &clientHandshakeStateTLS13{
+ c: chs.C,
+ serverHello: chs.ServerHello.getPrivatePtr(),
+ hello: chs.Hello.getPrivatePtr(),
+ keyShareKeys: chs.State13.private13KeyShareKeys(),
+
+ session: chs.Session,
+ binderKey: chs.State13.BinderKey,
+
+ certReq: chs.State13.CertReq.toPrivate(),
+ usingPSK: chs.State13.UsingPSK,
+ sentDummyCCS: chs.State13.SentDummyCCS,
+ suite: chs.State13.Suite.toPrivate(),
+ transcript: chs.State13.Transcript,
+ trafficSecret: chs.State13.TrafficSecret,
+
+ uconn: chs.uconn,
+ }
+ }
+}
+
+func (chs13 *clientHandshakeStateTLS13) toPublic13() *PubClientHandshakeState {
+ if chs13 == nil {
+ return nil
+ } else {
+ tls13State := TLS13OnlyState{
+ KeyShareKeys: chs13.keyShareKeys.ToPublic(),
+ EarlySecret: chs13.earlySecret.Secret(),
+ BinderKey: chs13.binderKey,
+ CertReq: chs13.certReq.toPublic(),
+ UsingPSK: chs13.usingPSK,
+ SentDummyCCS: chs13.sentDummyCCS,
+ Suite: chs13.suite.toPublic(),
+ TrafficSecret: chs13.trafficSecret,
+ Transcript: chs13.transcript,
+ }
+ return &PubClientHandshakeState{
+ C: chs13.c,
+ ServerHello: chs13.serverHello.getPublicPtr(),
+ Hello: chs13.hello.getPublicPtr(),
+
+ Session: chs13.session,
+
+ MasterSecret: chs13.masterSecret.Secret(),
+
+ State13: tls13State,
+
+ uconn: chs13.uconn,
+ }
+ }
+}
+
+func (chs *PubClientHandshakeState) toPrivate12() *clientHandshakeState {
+ if chs == nil {
+ return nil
+ } else {
+ return &clientHandshakeState{
+ c: chs.C,
+ serverHello: chs.ServerHello.getPrivatePtr(),
+ hello: chs.Hello.getPrivatePtr(),
+ suite: chs.State12.Suite.getPrivatePtr(),
+ session: chs.Session,
+
+ masterSecret: chs.MasterSecret,
+
+ finishedHash: chs.State12.FinishedHash.getPrivateObj(),
+
+ uconn: chs.uconn,
+ }
+ }
+}
+
+func (chs12 *clientHandshakeState) toPublic12() *PubClientHandshakeState {
+ if chs12 == nil {
+ return nil
+ } else {
+ tls12State := TLS12OnlyState{
+ Suite: chs12.suite.getPublicObj(),
+ FinishedHash: chs12.finishedHash.getPublicObj(),
+ }
+ return &PubClientHandshakeState{
+ C: chs12.c,
+ ServerHello: chs12.serverHello.getPublicPtr(),
+ Hello: chs12.hello.getPublicPtr(),
+
+ Session: chs12.session,
+
+ MasterSecret: chs12.masterSecret,
+
+ State12: tls12State,
+
+ uconn: chs12.uconn,
+ }
+ }
+}
+
+// type EcdheParameters interface {
+// ecdheParameters
+// }
+
+type CertificateRequestMsgTLS13 struct {
+ // Deprecated: crypto/tls no longer use this variable. This field won't be read or used by utls, but will still be populated.
+ // Support may be removed in the future.
+ Raw []byte
+
+ OcspStapling bool
+ Scts bool
+ SupportedSignatureAlgorithms []SignatureScheme
+ SupportedSignatureAlgorithmsCert []SignatureScheme
+ CertificateAuthorities [][]byte
+}
+
+func (crm *certificateRequestMsgTLS13) toPublic() *CertificateRequestMsgTLS13 {
+ if crm == nil {
+ return nil
+ } else {
+ rawBytes := []byte{}
+ if raw, err := crm.marshal(); err == nil {
+ rawBytes = raw
+ }
+
+ return &CertificateRequestMsgTLS13{
+ Raw: rawBytes,
+ OcspStapling: crm.ocspStapling,
+ Scts: crm.scts,
+ SupportedSignatureAlgorithms: crm.supportedSignatureAlgorithms,
+ SupportedSignatureAlgorithmsCert: crm.supportedSignatureAlgorithmsCert,
+ CertificateAuthorities: crm.certificateAuthorities,
+ }
+ }
+}
+
+func (crm *CertificateRequestMsgTLS13) toPrivate() *certificateRequestMsgTLS13 {
+ if crm == nil {
+ return nil
+ } else {
+ return &certificateRequestMsgTLS13{
+ ocspStapling: crm.OcspStapling,
+ scts: crm.Scts,
+ supportedSignatureAlgorithms: crm.SupportedSignatureAlgorithms,
+ supportedSignatureAlgorithmsCert: crm.SupportedSignatureAlgorithmsCert,
+ certificateAuthorities: crm.CertificateAuthorities,
+ }
+ }
+}
+
+type PubCipherSuiteTLS13 struct {
+ Id uint16
+ KeyLen int
+ Aead func(key, fixedNonce []byte) aead
+ Hash crypto.Hash
+}
+
+func (c *cipherSuiteTLS13) toPublic() *PubCipherSuiteTLS13 {
+ if c == nil {
+ return nil
+ } else {
+ return &PubCipherSuiteTLS13{
+ Id: c.id,
+ KeyLen: c.keyLen,
+ Aead: c.aead,
+ Hash: c.hash,
+ }
+ }
+}
+
+func (c *PubCipherSuiteTLS13) toPrivate() *cipherSuiteTLS13 {
+ if c == nil {
+ return nil
+ } else {
+ return &cipherSuiteTLS13{
+ id: c.Id,
+ keyLen: c.KeyLen,
+ aead: c.Aead,
+ hash: c.Hash,
+ }
+ }
+}
+
+type PubServerHelloMsg struct {
+ Raw []byte // renamed to serverHelloMsg.original in crypto/tls
+ Vers uint16
+ Random []byte
+ SessionId []byte
+ CipherSuite uint16
+ CompressionMethod uint8
+ NextProtoNeg bool
+ NextProtos []string
+ OcspStapling bool
+ Scts [][]byte
+ ExtendedMasterSecret bool
+ TicketSupported bool // used by go tls to determine whether to add the session ticket ext
+ SecureRenegotiation []byte
+ SecureRenegotiationSupported bool
+ AlpnProtocol string
+
+ // 1.3
+ SupportedVersion uint16
+ ServerShare KeyShare
+ SelectedIdentityPresent bool
+ SelectedIdentity uint16
+ Cookie []byte // HelloRetryRequest extension
+ SelectedGroup CurveID // HelloRetryRequest extension
+
+}
+
+func (shm *PubServerHelloMsg) getPrivatePtr() *serverHelloMsg {
+ if shm == nil {
+ return nil
+ } else {
+ return &serverHelloMsg{
+ original: shm.Raw,
+ vers: shm.Vers,
+ random: shm.Random,
+ sessionId: shm.SessionId,
+ cipherSuite: shm.CipherSuite,
+ compressionMethod: shm.CompressionMethod,
+ nextProtoNeg: shm.NextProtoNeg,
+ nextProtos: shm.NextProtos,
+ ocspStapling: shm.OcspStapling,
+ scts: shm.Scts,
+ extendedMasterSecret: shm.ExtendedMasterSecret,
+ ticketSupported: shm.TicketSupported,
+ secureRenegotiation: shm.SecureRenegotiation,
+ secureRenegotiationSupported: shm.SecureRenegotiationSupported,
+ alpnProtocol: shm.AlpnProtocol,
+ supportedVersion: shm.SupportedVersion,
+ serverShare: shm.ServerShare.ToPrivate(),
+ selectedIdentityPresent: shm.SelectedIdentityPresent,
+ selectedIdentity: shm.SelectedIdentity,
+ cookie: shm.Cookie,
+ selectedGroup: shm.SelectedGroup,
+ }
+ }
+}
+
+func (shm *serverHelloMsg) getPublicPtr() *PubServerHelloMsg {
+ if shm == nil {
+ return nil
+ } else {
+ return &PubServerHelloMsg{
+ Raw: shm.original,
+ Vers: shm.vers,
+ Random: shm.random,
+ SessionId: shm.sessionId,
+ CipherSuite: shm.cipherSuite,
+ CompressionMethod: shm.compressionMethod,
+ NextProtoNeg: shm.nextProtoNeg,
+ NextProtos: shm.nextProtos,
+ OcspStapling: shm.ocspStapling,
+ Scts: shm.scts,
+ ExtendedMasterSecret: shm.extendedMasterSecret,
+ TicketSupported: shm.ticketSupported,
+ SecureRenegotiation: shm.secureRenegotiation,
+ SecureRenegotiationSupported: shm.secureRenegotiationSupported,
+ AlpnProtocol: shm.alpnProtocol,
+ SupportedVersion: shm.supportedVersion,
+ ServerShare: shm.serverShare.ToPublic(),
+ SelectedIdentityPresent: shm.selectedIdentityPresent,
+ SelectedIdentity: shm.selectedIdentity,
+ Cookie: shm.cookie,
+ SelectedGroup: shm.selectedGroup,
+ }
+ }
+}
+
+type PubClientHelloMsg struct {
+ Raw []byte // renamed to clientHelloMsg.original in crypto/tls
+ Vers uint16
+ Random []byte
+ SessionId []byte
+ CipherSuites []uint16
+ CompressionMethods []uint8
+ NextProtoNeg bool
+ ServerName string
+ OcspStapling bool
+ Scts bool
+ Ems bool // [uTLS] actually implemented due to its prevalence
+ SupportedCurves []CurveID
+ SupportedPoints []uint8
+ TicketSupported bool
+ SessionTicket []uint8
+ SupportedSignatureAlgorithms []SignatureScheme
+ SecureRenegotiation []byte
+ SecureRenegotiationSupported bool
+ AlpnProtocols []string
+
+ // 1.3
+ SupportedSignatureAlgorithmsCert []SignatureScheme
+ SupportedVersions []uint16
+ Cookie []byte
+ KeyShares []KeyShare
+ EarlyData bool
+ PskModes []uint8
+ PskIdentities []PskIdentity
+ PskBinders [][]byte
+ QuicTransportParameters []byte
+
+ cachedPrivateHello *clientHelloMsg // todo: further optimize to reduce clientHelloMsg construction
+ encryptedClientHello []byte
+}
+
+func (chm *PubClientHelloMsg) getPrivatePtr() *clientHelloMsg {
+ if chm == nil {
+ return nil
+ } else {
+ private := &clientHelloMsg{
+ original: chm.Raw,
+ vers: chm.Vers,
+ random: chm.Random,
+ sessionId: chm.SessionId,
+ cipherSuites: chm.CipherSuites,
+ compressionMethods: chm.CompressionMethods,
+ serverName: chm.ServerName,
+ ocspStapling: chm.OcspStapling,
+ supportedCurves: chm.SupportedCurves,
+ supportedPoints: chm.SupportedPoints,
+ ticketSupported: chm.TicketSupported,
+ sessionTicket: chm.SessionTicket,
+ supportedSignatureAlgorithms: chm.SupportedSignatureAlgorithms,
+ supportedSignatureAlgorithmsCert: chm.SupportedSignatureAlgorithmsCert,
+ secureRenegotiationSupported: chm.SecureRenegotiationSupported,
+ secureRenegotiation: chm.SecureRenegotiation,
+ extendedMasterSecret: chm.Ems,
+ alpnProtocols: chm.AlpnProtocols,
+ scts: chm.Scts,
+
+ supportedVersions: chm.SupportedVersions,
+ cookie: chm.Cookie,
+ keyShares: KeyShares(chm.KeyShares).ToPrivate(),
+ earlyData: chm.EarlyData,
+ pskModes: chm.PskModes,
+ pskIdentities: PskIdentities(chm.PskIdentities).ToPrivate(),
+ pskBinders: chm.PskBinders,
+ quicTransportParameters: chm.QuicTransportParameters,
+ encryptedClientHello: chm.encryptedClientHello,
+
+ nextProtoNeg: chm.NextProtoNeg,
+ }
+ chm.cachedPrivateHello = private
+ return private
+ }
+}
+
+func (chm *PubClientHelloMsg) getCachedPrivatePtr() *clientHelloMsg {
+ if chm == nil {
+ return nil
+ } else {
+ return chm.cachedPrivateHello
+ }
+}
+
+func (chm *clientHelloMsg) getPublicPtr() *PubClientHelloMsg {
+ if chm == nil {
+ return nil
+ } else {
+ return &PubClientHelloMsg{
+ Raw: chm.original,
+ Vers: chm.vers,
+ Random: chm.random,
+ SessionId: chm.sessionId,
+ CipherSuites: chm.cipherSuites,
+ CompressionMethods: chm.compressionMethods,
+ NextProtoNeg: chm.nextProtoNeg,
+ ServerName: chm.serverName,
+ OcspStapling: chm.ocspStapling,
+ Scts: chm.scts,
+ Ems: chm.extendedMasterSecret,
+ SupportedCurves: chm.supportedCurves,
+ SupportedPoints: chm.supportedPoints,
+ TicketSupported: chm.ticketSupported,
+ SessionTicket: chm.sessionTicket,
+ SupportedSignatureAlgorithms: chm.supportedSignatureAlgorithms,
+ SecureRenegotiation: chm.secureRenegotiation,
+ SecureRenegotiationSupported: chm.secureRenegotiationSupported,
+ AlpnProtocols: chm.alpnProtocols,
+
+ SupportedSignatureAlgorithmsCert: chm.supportedSignatureAlgorithmsCert,
+ SupportedVersions: chm.supportedVersions,
+ Cookie: chm.cookie,
+ KeyShares: keyShares(chm.keyShares).ToPublic(),
+ EarlyData: chm.earlyData,
+ PskModes: chm.pskModes,
+ PskIdentities: pskIdentities(chm.pskIdentities).ToPublic(),
+ PskBinders: chm.pskBinders,
+ QuicTransportParameters: chm.quicTransportParameters,
+ cachedPrivateHello: chm,
+ encryptedClientHello: chm.encryptedClientHello,
+ }
+ }
+}
+
+// UnmarshalClientHello allows external code to parse raw client hellos.
+// It returns nil on failure.
+func UnmarshalClientHello(data []byte) *PubClientHelloMsg {
+ m := &clientHelloMsg{}
+ if m.unmarshal(data) {
+ return m.getPublicPtr()
+ }
+ return nil
+}
+
+// Marshal allows external code to convert a ClientHello object back into
+// raw bytes.
+func (chm *PubClientHelloMsg) Marshal() ([]byte, error) {
+ return chm.getPrivatePtr().marshal()
+}
+
+// A CipherSuite is a specific combination of key agreement, cipher and MAC
+// function. All cipher suites currently assume RSA key agreement.
+type PubCipherSuite struct {
+ Id uint16
+ // the lengths, in bytes, of the key material needed for each component.
+ KeyLen int
+ MacLen int
+ IvLen int
+ Ka func(version uint16) keyAgreement
+ // flags is a bitmask of the suite* values, above.
+ Flags int
+ Cipher func(key, iv []byte, isRead bool) interface{}
+ Mac func(macKey []byte) hash.Hash
+ Aead func(key, fixedNonce []byte) aead
+}
+
+func (cs *PubCipherSuite) getPrivatePtr() *cipherSuite {
+ if cs == nil {
+ return nil
+ } else {
+ return &cipherSuite{
+ id: cs.Id,
+ keyLen: cs.KeyLen,
+ macLen: cs.MacLen,
+ ivLen: cs.IvLen,
+ ka: cs.Ka,
+ flags: cs.Flags,
+ cipher: cs.Cipher,
+ mac: cs.Mac,
+ aead: cs.Aead,
+ }
+ }
+}
+
+func (cs *cipherSuite) getPublicObj() PubCipherSuite {
+ if cs == nil {
+ return PubCipherSuite{}
+ } else {
+ return PubCipherSuite{
+ Id: cs.id,
+ KeyLen: cs.keyLen,
+ MacLen: cs.macLen,
+ IvLen: cs.ivLen,
+ Ka: cs.ka,
+ Flags: cs.flags,
+ Cipher: cs.cipher,
+ Mac: cs.mac,
+ Aead: cs.aead,
+ }
+ }
+}
+
+// A FinishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type FinishedHash struct {
+ Client hash.Hash
+ Server hash.Hash
+
+ // Prior to TLS 1.2, an additional MD5 hash is required.
+ ClientMD5 hash.Hash
+ ServerMD5 hash.Hash
+
+ // In TLS 1.2, a full buffer is sadly required.
+ Buffer []byte
+
+ Version uint16
+ Prfv2 prfFunc
+
+ // Deprecated: Use Prfv2 instead. Prfv2 will be used if both are set.
+ Prf prfFuncOld
+}
+
+type prfFuncOld func(result, secret, label, seed []byte)
+
+func prfFuncV1ToV2(v1 prfFuncOld) prfFunc {
+ return func(secret []byte, label string, seed []byte, keyLen int) []byte {
+ res := make([]byte, keyLen)
+ v1(res, secret, []byte(label), seed)
+ return res
+ }
+}
+
+func prfFuncV2ToV1(v2 prfFunc) prfFuncOld {
+ return func(result, secret, label, seed []byte) {
+ copy(result, v2(secret, string(label), seed, len(result)))
+ }
+}
+
+func (fh *FinishedHash) getPrivateObj() finishedHash {
+ if fh == nil {
+ return finishedHash{}
+ } else {
+ res := finishedHash{
+ client: fh.Client,
+ server: fh.Server,
+ clientMD5: fh.ClientMD5,
+ serverMD5: fh.ServerMD5,
+ buffer: fh.Buffer,
+ version: fh.Version,
+ }
+
+ if fh.Prfv2 != nil {
+ res.prf = fh.Prfv2
+ } else if fh.Prf != nil {
+ res.prf = prfFuncV1ToV2(fh.Prf)
+ }
+
+ return res
+ }
+}
+
+func (fh *finishedHash) getPublicObj() FinishedHash {
+ if fh == nil {
+ return FinishedHash{}
+ } else {
+ res := FinishedHash{
+ Client: fh.client,
+ Server: fh.server,
+ ClientMD5: fh.clientMD5,
+ ServerMD5: fh.serverMD5,
+ Buffer: fh.buffer,
+ Version: fh.version,
+ }
+
+ res.Prfv2 = fh.prf
+ res.Prf = prfFuncV2ToV1(fh.prf)
+
+ return res
+ }
+}
+
+// TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
+type KeyShare struct {
+ Group CurveID `json:"group"`
+ Data []byte `json:"key_exchange,omitempty"` // optional
+}
+
+func (ks KeyShare) ToPrivate() keyShare {
+ return keyShare{group: ks.Group, data: ks.Data}
+}
+
+func (ks keyShare) ToPublic() KeyShare {
+ return KeyShare{Group: ks.group, Data: ks.data}
+}
+
+type KeyShares []KeyShare
+type keyShares []keyShare
+
+func (kss keyShares) ToPublic() []KeyShare {
+ var KSS []KeyShare
+ for _, ks := range kss {
+ KSS = append(KSS, ks.ToPublic())
+ }
+ return KSS
+}
+func (KSS KeyShares) ToPrivate() []keyShare {
+ var kss []keyShare
+ for _, KS := range KSS {
+ kss = append(kss, KS.ToPrivate())
+ }
+ return kss
+}
+
+// TLS 1.3 PSK Identity. Can be a Session Ticket, or a reference to a saved
+// session. See RFC 8446, Section 4.2.11.
+type PskIdentity struct {
+ Label []byte `json:"identity"`
+ ObfuscatedTicketAge uint32 `json:"obfuscated_ticket_age"`
+}
+
+type PskIdentities []PskIdentity
+type pskIdentities []pskIdentity
+
+func (pss pskIdentities) ToPublic() []PskIdentity {
+ var PSS []PskIdentity
+ for _, ps := range pss {
+ PSS = append(PSS, PskIdentity{Label: ps.label, ObfuscatedTicketAge: ps.obfuscatedTicketAge})
+ }
+ return PSS
+}
+
+func (PSS PskIdentities) ToPrivate() []pskIdentity {
+ var pss []pskIdentity
+ for _, PS := range PSS {
+ pss = append(pss, pskIdentity{label: PS.Label, obfuscatedTicketAge: PS.ObfuscatedTicketAge})
+ }
+ return pss
+}
+
+// ClientSessionState is public, but all its fields are private. Let's add setters, getters and constructor
+
+// ClientSessionState contains the state needed by clients to resume TLS sessions.
+func MakeClientSessionState(
+ SessionTicket []uint8,
+ Vers uint16,
+ CipherSuite uint16,
+ MasterSecret []byte,
+ ServerCertificates []*x509.Certificate,
+ VerifiedChains [][]*x509.Certificate) *ClientSessionState {
+ // TODO: Add EMS to this constructor in uTLS v2
+ css := &ClientSessionState{
+ session: &SessionState{
+ version: Vers,
+ cipherSuite: CipherSuite,
+ secret: MasterSecret,
+ peerCertificates: ServerCertificates,
+ verifiedChains: VerifiedChains,
+ ticket: SessionTicket,
+ },
+ }
+ return css
+}
+
+// Encrypted ticket used for session resumption with server
+func (css *ClientSessionState) SessionTicket() []uint8 {
+ return css.session.ticket
+}
+
+// SSL/TLS version negotiated for the session
+func (css *ClientSessionState) Vers() uint16 {
+ return css.session.version
+}
+
+// Ciphersuite negotiated for the session
+func (css *ClientSessionState) CipherSuite() uint16 {
+ return css.session.cipherSuite
+}
+
+// MasterSecret generated by client on a full handshake
+func (css *ClientSessionState) MasterSecret() []byte {
+ return css.session.secret
+}
+
+func (css *ClientSessionState) EMS() bool {
+ return css.session.extMasterSecret
+}
+
+// Certificate chain presented by the server
+func (css *ClientSessionState) ServerCertificates() []*x509.Certificate {
+ return css.session.peerCertificates
+}
+
+// Certificate chains we built for verification
+func (css *ClientSessionState) VerifiedChains() [][]*x509.Certificate {
+ return css.session.verifiedChains
+}
+
+func (css *ClientSessionState) SetSessionTicket(SessionTicket []uint8) {
+ css.session.ticket = SessionTicket
+}
+
+func (css *ClientSessionState) SetVers(Vers uint16) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.version = Vers
+}
+
+func (css *ClientSessionState) SetCipherSuite(CipherSuite uint16) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.cipherSuite = CipherSuite
+}
+
+func (css *ClientSessionState) SetCreatedAt(createdAt uint64) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.createdAt = createdAt
+}
+
+func (css *ClientSessionState) SetMasterSecret(MasterSecret []byte) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.secret = MasterSecret
+}
+
+func (css *ClientSessionState) SetEMS(ems bool) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.extMasterSecret = ems
+}
+
+func (css *ClientSessionState) SetServerCertificates(ServerCertificates []*x509.Certificate) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.peerCertificates = ServerCertificates
+}
+
+func (css *ClientSessionState) SetVerifiedChains(VerifiedChains [][]*x509.Certificate) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.verifiedChains = VerifiedChains
+}
+
+func (css *ClientSessionState) SetUseBy(useBy uint64) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.useBy = useBy
+}
+
+func (css *ClientSessionState) SetAgeAdd(ageAdd uint32) {
+ if css.session == nil {
+ css.session = &SessionState{}
+ }
+ css.session.ageAdd = ageAdd
+}
+
+// TicketKey is the internal representation of a session ticket key.
+type TicketKey struct {
+ AesKey [16]byte
+ HmacKey [16]byte
+ // created is the time at which this ticket key was created. See Config.ticketKeys.
+ Created time.Time
+}
+
+type TicketKeys []TicketKey
+type ticketKeys []ticketKey
+
+func TicketKeyFromBytes(b [32]byte) TicketKey {
+ // [uTLS]
+ // empty config is required
+ config := &Config{}
+ tk := config.ticketKeyFromBytes(b)
+ return tk.ToPublic()
+}
+
+func (tk ticketKey) ToPublic() TicketKey {
+ return TicketKey{
+ AesKey: tk.aesKey,
+ HmacKey: tk.hmacKey,
+ Created: tk.created,
+ }
+}
+
+func (TK TicketKey) ToPrivate() ticketKey {
+ return ticketKey{
+ aesKey: TK.AesKey,
+ hmacKey: TK.HmacKey,
+ created: TK.Created,
+ }
+}
+
+func (tks ticketKeys) ToPublic() []TicketKey {
+ var TKS []TicketKey
+ for _, ks := range tks {
+ TKS = append(TKS, ks.ToPublic())
+ }
+ return TKS
+}
+
+func (TKS TicketKeys) ToPrivate() []ticketKey {
+ var tks []ticketKey
+ for _, TK := range TKS {
+ tks = append(tks, TK.ToPrivate())
+ }
+ return tks
+}
+
+type kemPrivateKey struct {
+ secretKey any
+ curveID CurveID
+}
+
+// Deprecated: Use KeySharePrivateKeys instead. This type is no longer used.
+// Will be removed in the future.
+type KemPrivateKey struct {
+ SecretKey any
+ CurveID CurveID
+}
+
+func (kpk *KemPrivateKey) ToPrivate() *kemPrivateKey {
+ if kpk == nil {
+ return nil
+ } else {
+ return &kemPrivateKey{
+ secretKey: kpk.SecretKey,
+ curveID: kpk.CurveID,
+ }
+ }
+}
+
+func (kpk *kemPrivateKey) ToPublic() *KemPrivateKey {
+ if kpk == nil {
+ return nil
+ } else {
+ return &KemPrivateKey{
+ SecretKey: kpk.secretKey,
+ CurveID: kpk.curveID,
+ }
+ }
+}
+
+type KeySharePrivateKeys struct {
+ CurveID CurveID
+ Ecdhe *ecdh.PrivateKey
+ Mlkem *mlkem.DecapsulationKey768
+ MlkemEcdhe *ecdh.PrivateKey
+}
+
+func (ksp *KeySharePrivateKeys) ToPrivate() *keySharePrivateKeys {
+ if ksp == nil {
+ return nil
+ }
+ return &keySharePrivateKeys{
+ curveID: ksp.CurveID,
+ ecdhe: ksp.Ecdhe,
+ mlkem: ksp.Mlkem,
+ mlkemEcdhe: ksp.MlkemEcdhe,
+ }
+}
+
+func (ksp *keySharePrivateKeys) ToPublic() *KeySharePrivateKeys {
+ if ksp == nil {
+ return nil
+ }
+ return &KeySharePrivateKeys{
+ CurveID: ksp.curveID,
+ Ecdhe: ksp.ecdhe,
+ Mlkem: ksp.mlkem,
+ MlkemEcdhe: ksp.mlkemEcdhe,
+ }
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_quic.go b/vendor/github.com/refraction-networking/utls/u_quic.go
new file mode 100644
index 00000000..e985c820
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_quic.go
@@ -0,0 +1,212 @@
+// Copyright 2023 The uTLS 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 tls
+
+import (
+ "context"
+ "errors"
+ "fmt"
+)
+
+// A UQUICConn represents a connection which uses a QUIC implementation as the underlying
+// transport as described in RFC 9001.
+//
+// Methods of UQUICConn are not safe for concurrent use.
+type UQUICConn struct {
+ conn *UConn
+
+ sessionTicketSent bool
+}
+
+// QUICClient returns a new TLS client side connection using QUICTransport as the
+// underlying transport. The config cannot be nil.
+//
+// The config's MinVersion must be at least TLS 1.3.
+func UQUICClient(config *QUICConfig, clientHelloID ClientHelloID) *UQUICConn {
+ return newUQUICConn(UClient(nil, config.TLSConfig, clientHelloID))
+}
+
+func newUQUICConn(uconn *UConn) *UQUICConn {
+ uconn.quic = &quicState{
+ signalc: make(chan struct{}),
+ blockedc: make(chan struct{}),
+ }
+ uconn.quic.events = uconn.quic.eventArr[:0]
+ return &UQUICConn{
+ conn: uconn,
+ }
+}
+
+// Start starts the client or server handshake protocol.
+// It may produce connection events, which may be read with NextEvent.
+//
+// Start must be called at most once.
+func (q *UQUICConn) Start(ctx context.Context) error {
+ if q.conn.quic.started {
+ return quicError(errors.New("tls: Start called more than once"))
+ }
+ q.conn.quic.started = true
+ if q.conn.config.MinVersion < VersionTLS13 {
+ return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13"))
+ }
+ go q.conn.HandshakeContext(ctx)
+ if _, ok := <-q.conn.quic.blockedc; !ok {
+ return q.conn.handshakeErr
+ }
+ return nil
+}
+
+func (q *UQUICConn) ApplyPreset(p *ClientHelloSpec) error {
+ return q.conn.ApplyPreset(p)
+}
+
+// NextEvent returns the next event occurring on the connection.
+// It returns an event with a Kind of QUICNoEvent when no events are available.
+func (q *UQUICConn) NextEvent() QUICEvent {
+ qs := q.conn.quic
+ if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
+ // Write over some of the previous event's data,
+ // to catch callers erroniously retaining it.
+ qs.events[last].Data[0] = 0
+ }
+ if qs.nextEvent >= len(qs.events) {
+ qs.events = qs.events[:0]
+ qs.nextEvent = 0
+ return QUICEvent{Kind: QUICNoEvent}
+ }
+ e := qs.events[qs.nextEvent]
+ qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
+ qs.nextEvent++
+ return e
+}
+
+// Close closes the connection and stops any in-progress handshake.
+func (q *UQUICConn) Close() error {
+ if q.conn.quic.cancel == nil {
+ return nil // never started
+ }
+ q.conn.quic.cancel()
+ for range q.conn.quic.blockedc {
+ // Wait for the handshake goroutine to return.
+ }
+ return q.conn.handshakeErr
+}
+
+// HandleData handles handshake bytes received from the peer.
+// It may produce connection events, which may be read with NextEvent.
+func (q *UQUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
+ c := q.conn
+ if c.in.level != level {
+ return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
+ }
+ c.quic.readbuf = data
+ <-c.quic.signalc
+ _, ok := <-c.quic.blockedc
+ if ok {
+ // The handshake goroutine is waiting for more data.
+ return nil
+ }
+ // The handshake goroutine has exited.
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ c.hand.Write(c.quic.readbuf)
+ c.quic.readbuf = nil
+ for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
+ b := q.conn.hand.Bytes()
+ n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
+ if n > maxHandshake {
+ q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
+ break
+ }
+ if len(b) < 4+n {
+ return nil
+ }
+ if err := q.conn.handlePostHandshakeMessage(); err != nil {
+ q.conn.handshakeErr = err
+ }
+ }
+ if q.conn.handshakeErr != nil {
+ return quicError(q.conn.handshakeErr)
+ }
+ return nil
+}
+
+// SendSessionTicket sends a session ticket to the client.
+// It produces connection events, which may be read with NextEvent.
+// Currently, it can only be called once.
+func (q *UQUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
+ c := q.conn
+ if !c.isHandshakeComplete.Load() {
+ return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
+ }
+ if c.isClient {
+ return quicError(errors.New("tls: SendSessionTicket called on the client"))
+ }
+ if q.sessionTicketSent {
+ return quicError(errors.New("tls: SendSessionTicket called multiple times"))
+ }
+ q.sessionTicketSent = true
+ return quicError(c.sendSessionTicket(opts.EarlyData, opts.Extra))
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (q *UQUICConn) ConnectionState() ConnectionState {
+ return q.conn.ConnectionState()
+}
+
+// SetTransportParameters sets the transport parameters to send to the peer.
+//
+// Server connections may delay setting the transport parameters until after
+// receiving the client's transport parameters. See QUICTransportParametersRequired.
+func (q *UQUICConn) SetTransportParameters(params []byte) {
+ if params == nil {
+ params = []byte{}
+ }
+ q.conn.quic.transportParams = params // this won't be used for building ClientHello when using a preset
+
+ // // instead, we set the transport parameters hold by the ClientHello
+ // for _, ext := range q.conn.Extensions {
+ // if qtp, ok := ext.(*QUICTransportParametersExtension); ok {
+ // qtp.TransportParametersExtData = params
+ // }
+ // }
+
+ if q.conn.quic.started {
+ <-q.conn.quic.signalc
+ <-q.conn.quic.blockedc
+ }
+}
+
+func (uc *UConn) QUICSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
+ uc.quic.events = append(uc.quic.events, QUICEvent{
+ Kind: QUICSetReadSecret,
+ Level: level,
+ Suite: suite,
+ Data: secret,
+ })
+}
+
+func (uc *UConn) QUICSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
+ uc.quic.events = append(uc.quic.events, QUICEvent{
+ Kind: QUICSetWriteSecret,
+ Level: level,
+ Suite: suite,
+ Data: secret,
+ })
+}
+
+func (uc *UConn) QUICGetTransportParameters() ([]byte, error) {
+ if uc.quic.transportParams == nil {
+ uc.quic.events = append(uc.quic.events, QUICEvent{
+ Kind: QUICTransportParametersRequired,
+ })
+ }
+ for uc.quic.transportParams == nil {
+ if err := uc.quicWaitForSignal(); err != nil {
+ return nil, err
+ }
+ }
+ return uc.quic.transportParams, nil
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_quic_transport_parameters.go b/vendor/github.com/refraction-networking/utls/u_quic_transport_parameters.go
new file mode 100644
index 00000000..53b36cd7
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_quic_transport_parameters.go
@@ -0,0 +1,319 @@
+package tls
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "math"
+ "math/big"
+
+ "github.com/refraction-networking/utls/internal/quicvarint"
+)
+
+const (
+ // RFC IDs
+ max_idle_timeout uint64 = 0x1
+ max_udp_payload_size uint64 = 0x3
+ initial_max_data uint64 = 0x4
+ initial_max_stream_data_bidi_local uint64 = 0x5
+ initial_max_stream_data_bidi_remote uint64 = 0x6
+ initial_max_stream_data_uni uint64 = 0x7
+ initial_max_streams_bidi uint64 = 0x8
+ initial_max_streams_uni uint64 = 0x9
+ max_ack_delay uint64 = 0xb
+ disable_active_migration uint64 = 0xc
+ active_connection_id_limit uint64 = 0xe
+ initial_source_connection_id uint64 = 0xf
+ version_information uint64 = 0x11 // RFC 9368
+ padding uint64 = 0x15
+ max_datagram_frame_size uint64 = 0x20 // RFC 9221
+ grease_quic_bit uint64 = 0x2ab2
+
+ // Legacy IDs from draft
+ version_information_legacy uint64 = 0xff73db // draft-ietf-quic-version-negotiation-13 and early
+)
+
+type TransportParameters []TransportParameter
+
+func (tps TransportParameters) Marshal() []byte {
+ var b []byte
+ for _, tp := range tps {
+ b = quicvarint.Append(b, tp.ID())
+ b = quicvarint.Append(b, uint64(len(tp.Value())))
+ b = append(b, tp.Value()...)
+ }
+ return b
+}
+
+// TransportParameter represents a QUIC transport parameter.
+//
+// Caller will write the following to the wire:
+//
+// var b []byte
+// b = quicvarint.Append(b, ID())
+// b = quicvarint.Append(b, len(Value()))
+// b = append(b, Value())
+//
+// Therefore Value() should return the exact bytes to be written to the wire AFTER the length field,
+// i.e., the bytes MAY be a Variable Length Integer per RFC depending on the type of the transport
+// parameter, but MUST NOT including the length field unless the parameter is defined so.
+type TransportParameter interface {
+ ID() uint64
+ Value() []byte
+}
+
+type GREASETransportParameter struct {
+ IdOverride uint64 // if set to a valid GREASE ID, use this instead of randomly generated one.
+ Length uint16 // if len(ValueOverride) == 0, will generate random data of this size.
+ ValueOverride []byte // if len(ValueOverride) > 0, use this instead of random bytes.
+}
+
+const (
+ GREASE_MAX_MULTIPLIER = (0x3FFFFFFFFFFFFFFF - 27) / 31
+)
+
+// IsGREASEID returns true if id is a valid GREASE ID for
+// transport parameters.
+func (GREASETransportParameter) IsGREASEID(id uint64) bool {
+ return id >= 27 && (id-27)%31 == 0
+}
+
+// GetGREASEID returns a random valid GREASE ID for transport parameters.
+func (GREASETransportParameter) GetGREASEID() uint64 {
+ max := big.NewInt(GREASE_MAX_MULTIPLIER)
+
+ randMultiply, err := rand.Int(rand.Reader, max)
+ if err != nil {
+ return 27
+ }
+
+ return 27 + randMultiply.Uint64()*31
+}
+
+func (g *GREASETransportParameter) ID() uint64 {
+ if !g.IsGREASEID(g.IdOverride) {
+ g.IdOverride = g.GetGREASEID()
+ }
+ return g.IdOverride
+}
+
+func (g *GREASETransportParameter) Value() []byte {
+ if len(g.ValueOverride) == 0 {
+ g.ValueOverride = make([]byte, g.Length)
+ rand.Read(g.ValueOverride)
+ }
+ return g.ValueOverride
+}
+
+type MaxIdleTimeout uint64 // in milliseconds
+
+func (MaxIdleTimeout) ID() uint64 {
+ return max_idle_timeout
+}
+
+func (m MaxIdleTimeout) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(m))
+}
+
+type MaxUDPPayloadSize uint64
+
+func (MaxUDPPayloadSize) ID() uint64 {
+ return max_udp_payload_size
+}
+
+func (m MaxUDPPayloadSize) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(m))
+}
+
+type InitialMaxData uint64
+
+func (InitialMaxData) ID() uint64 {
+ return initial_max_data
+}
+
+func (i InitialMaxData) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(i))
+}
+
+type InitialMaxStreamDataBidiLocal uint64
+
+func (InitialMaxStreamDataBidiLocal) ID() uint64 {
+ return initial_max_stream_data_bidi_local
+}
+
+func (i InitialMaxStreamDataBidiLocal) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(i))
+}
+
+type InitialMaxStreamDataBidiRemote uint64
+
+func (InitialMaxStreamDataBidiRemote) ID() uint64 {
+ return initial_max_stream_data_bidi_remote
+}
+
+func (i InitialMaxStreamDataBidiRemote) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(i))
+}
+
+type InitialMaxStreamDataUni uint64
+
+func (InitialMaxStreamDataUni) ID() uint64 {
+ return initial_max_stream_data_uni
+}
+
+func (i InitialMaxStreamDataUni) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(i))
+}
+
+type InitialMaxStreamsBidi uint64
+
+func (InitialMaxStreamsBidi) ID() uint64 {
+ return initial_max_streams_bidi
+}
+
+func (i InitialMaxStreamsBidi) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(i))
+}
+
+type InitialMaxStreamsUni uint64
+
+func (InitialMaxStreamsUni) ID() uint64 {
+ return initial_max_streams_uni
+}
+
+func (i InitialMaxStreamsUni) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(i))
+}
+
+type MaxAckDelay uint64
+
+func (MaxAckDelay) ID() uint64 {
+ return max_ack_delay
+}
+
+func (m MaxAckDelay) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(m))
+}
+
+type DisableActiveMigration struct{}
+
+func (*DisableActiveMigration) ID() uint64 {
+ return disable_active_migration
+}
+
+// Its Value MUST ALWAYS be empty.
+func (*DisableActiveMigration) Value() []byte {
+ return []byte{}
+}
+
+type ActiveConnectionIDLimit uint64
+
+func (ActiveConnectionIDLimit) ID() uint64 {
+ return active_connection_id_limit
+}
+
+func (a ActiveConnectionIDLimit) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(a))
+}
+
+type InitialSourceConnectionID []byte // if empty, will be set to the Connection ID used for the Initial packet.
+
+func (InitialSourceConnectionID) ID() uint64 {
+ return initial_source_connection_id
+}
+
+func (i InitialSourceConnectionID) Value() []byte {
+ return []byte(i)
+}
+
+type VersionInformation struct {
+ ChoosenVersion uint32
+ AvailableVersions []uint32 // Also known as "Other Versions" in early drafts.
+
+ LegacyID bool // If true, use the legacy-assigned ID (0xff73db) instead of the RFC-assigned one (0x11).
+}
+
+const (
+ VERSION_NEGOTIATION uint32 = 0x00000000 // rfc9000
+ VERSION_1 uint32 = 0x00000001 // rfc9000
+ VERSION_2 uint32 = 0x6b3343cf // rfc9369
+
+ VERSION_GREASE uint32 = 0x0a0a0a0a // -> 0x?a?a?a?a
+)
+
+func (v *VersionInformation) ID() uint64 {
+ if v.LegacyID {
+ return version_information_legacy
+ }
+ return version_information
+}
+
+func (v *VersionInformation) Value() []byte {
+ var b []byte
+ b = binary.BigEndian.AppendUint32(b, v.ChoosenVersion)
+ for _, version := range v.AvailableVersions {
+ if version != VERSION_GREASE {
+ b = binary.BigEndian.AppendUint32(b, version)
+ } else {
+ b = binary.BigEndian.AppendUint32(b, v.GetGREASEVersion())
+ }
+ }
+ return b
+}
+
+func (*VersionInformation) GetGREASEVersion() uint32 {
+ // get a random uint32
+ max := big.NewInt(math.MaxUint32)
+ randVal, err := rand.Int(rand.Reader, max)
+ if err != nil {
+ return VERSION_GREASE
+ }
+
+ return uint32(randVal.Uint64()&math.MaxUint32) | 0x0a0a0a0a // all GREASE versions are in 0x?a?a?a?a
+}
+
+type PaddingTransportParameter []byte
+
+func (PaddingTransportParameter) ID() uint64 {
+ return padding
+}
+
+func (p PaddingTransportParameter) Value() []byte {
+ return p
+}
+
+type MaxDatagramFrameSize uint64
+
+func (MaxDatagramFrameSize) ID() uint64 {
+ return max_datagram_frame_size
+}
+
+func (m MaxDatagramFrameSize) Value() []byte {
+ return quicvarint.Append([]byte{}, uint64(m))
+}
+
+type GREASEQUICBit struct{}
+
+func (*GREASEQUICBit) ID() uint64 {
+ return grease_quic_bit
+}
+
+// Its Value MUST ALWAYS be empty.
+func (*GREASEQUICBit) Value() []byte {
+ return []byte{}
+}
+
+type FakeQUICTransportParameter struct {
+ Id uint64
+ Val []byte
+}
+
+func (f *FakeQUICTransportParameter) ID() uint64 {
+ if f.Id == 0 {
+ panic("it is not allowed to use a FakeQUICTransportParameter without setting the ID")
+ }
+ return f.Id
+}
+
+func (f *FakeQUICTransportParameter) Value() []byte {
+ return f.Val
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_roller.go b/vendor/github.com/refraction-networking/utls/u_roller.go
new file mode 100644
index 00000000..a1c52914
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_roller.go
@@ -0,0 +1,100 @@
+package tls
+
+import (
+ "net"
+ "sync"
+ "time"
+)
+
+type Roller struct {
+ HelloIDs []ClientHelloID
+ HelloIDMu sync.Mutex
+ WorkingHelloID *ClientHelloID
+ TcpDialTimeout time.Duration
+ TlsHandshakeTimeout time.Duration
+ r *prng
+}
+
+// NewRoller creates Roller object with default range of HelloIDs to cycle through until a
+// working/unblocked one is found.
+func NewRoller() (*Roller, error) {
+ r, err := newPRNG()
+ if err != nil {
+ return nil, err
+ }
+
+ tcpDialTimeoutInc := r.Intn(14)
+ tcpDialTimeoutInc = 7 + tcpDialTimeoutInc
+
+ tlsHandshakeTimeoutInc := r.Intn(20)
+ tlsHandshakeTimeoutInc = 11 + tlsHandshakeTimeoutInc
+
+ return &Roller{
+ HelloIDs: []ClientHelloID{
+ HelloChrome_Auto,
+ HelloFirefox_Auto,
+ HelloIOS_Auto,
+ HelloRandomized,
+ },
+ TcpDialTimeout: time.Second * time.Duration(tcpDialTimeoutInc),
+ TlsHandshakeTimeout: time.Second * time.Duration(tlsHandshakeTimeoutInc),
+ r: r,
+ }, nil
+}
+
+// Dial attempts to establish connection to given address using different HelloIDs.
+// If a working HelloID is found, it is used again for subsequent Dials.
+// If tcp connection fails or all HelloIDs are tried, returns with last error.
+//
+// Usage examples:
+// Dial("tcp4", "google.com:443", "google.com")
+// Dial("tcp", "10.23.144.22:443", "mywebserver.org")
+func (c *Roller) Dial(network, addr, serverName string) (*UConn, error) {
+ helloIDs := make([]ClientHelloID, len(c.HelloIDs))
+ copy(helloIDs, c.HelloIDs)
+ c.r.rand.Shuffle(len(c.HelloIDs), func(i, j int) {
+ helloIDs[i], helloIDs[j] = helloIDs[j], helloIDs[i]
+ })
+
+ c.HelloIDMu.Lock()
+ workingHelloId := c.WorkingHelloID // keep using same helloID, if it works
+ c.HelloIDMu.Unlock()
+ if workingHelloId != nil {
+ helloIDFound := false
+ for i, ID := range helloIDs {
+ if ID == *workingHelloId {
+ helloIDs[i] = helloIDs[0]
+ helloIDs[0] = *workingHelloId // push working hello ID first
+ helloIDFound = true
+ break
+ }
+ }
+ if !helloIDFound {
+ helloIDs = append([]ClientHelloID{*workingHelloId}, helloIDs...)
+ }
+ }
+
+ var tcpConn net.Conn
+ var err error
+ for _, helloID := range helloIDs {
+ tcpConn, err = net.DialTimeout(network, addr, c.TcpDialTimeout)
+ if err != nil {
+ return nil, err // on tcp Dial failure return with error right away
+ }
+
+ client := UClient(tcpConn, nil, helloID)
+ client.SetSNI(serverName)
+ client.SetDeadline(time.Now().Add(c.TlsHandshakeTimeout))
+ err = client.Handshake()
+ client.SetDeadline(time.Time{}) // unset timeout
+ if err != nil {
+ continue // on tls Dial error keep trying HelloIDs
+ }
+
+ c.HelloIDMu.Lock()
+ c.WorkingHelloID = &client.ClientHelloID
+ c.HelloIDMu.Unlock()
+ return client, err
+ }
+ return nil, err
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_session_controller.go b/vendor/github.com/refraction-networking/utls/u_session_controller.go
new file mode 100644
index 00000000..1ba87b81
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_session_controller.go
@@ -0,0 +1,361 @@
+package tls
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/refraction-networking/utls/internal/tls13"
+)
+
+// Tracking the state of calling conn.loadSession
+type LoadSessionTrackerState int
+
+const NeverCalled LoadSessionTrackerState = 0
+const UtlsAboutToCall LoadSessionTrackerState = 1
+const CalledByULoadSession LoadSessionTrackerState = 2
+const CalledByGoTLS LoadSessionTrackerState = 3
+
+// The state of the session controller
+type sessionControllerState int
+
+const NoSession sessionControllerState = 0
+const SessionTicketExtInitialized sessionControllerState = 1
+const SessionTicketExtAllSet sessionControllerState = 2
+const PskExtInitialized sessionControllerState = 3
+const PskExtAllSet sessionControllerState = 4
+
+// sessionController is responsible for managing and controlling all session related states. It manages the lifecycle of the session ticket extension and the psk extension, including initialization, removal if the client hello spec doesn't contain any of them, and setting the prepared state to the client hello.
+//
+// Users should never directly modify the underlying state. Violations will result in undefined behaviors.
+//
+// Users should never construct sessionController by themselves, use the function `newSessionController` instead.
+type sessionController struct {
+ // sessionTicketExt logically owns the session ticket extension
+ sessionTicketExt ISessionTicketExtension
+
+ // pskExtension logically owns the psk extension
+ pskExtension PreSharedKeyExtension
+
+ // uconnRef is a reference to the uconn
+ uconnRef *UConn
+
+ // state represents the internal state of the sessionController. Users are advised to modify the state only through designated methods and avoid direct manipulation, as doing so may result in undefined behavior.
+ state sessionControllerState
+
+ // loadSessionTracker keeps track of how the conn.loadSession method is being utilized.
+ loadSessionTracker LoadSessionTrackerState
+
+ // callingLoadSession is a boolean flag that indicates whether the `conn.loadSession` function is currently being invoked.
+ callingLoadSession bool
+
+ // locked is a boolean flag that becomes true once all states are appropriately set. Once `locked` is true, further modifications are disallowed, except for the binders.
+ locked bool
+}
+
+// newSessionController constructs a new SessionController
+func newSessionController(uconn *UConn) *sessionController {
+ return &sessionController{
+ uconnRef: uconn,
+ sessionTicketExt: nil,
+ pskExtension: nil,
+ state: NoSession,
+ locked: false,
+ callingLoadSession: false,
+ loadSessionTracker: NeverCalled,
+ }
+}
+
+func (s *sessionController) isSessionLocked() bool {
+ return s.locked
+}
+
+type shouldLoadSessionResult int
+
+const shouldReturn shouldLoadSessionResult = 0
+const shouldSetTicket shouldLoadSessionResult = 1
+const shouldSetPsk shouldLoadSessionResult = 2
+const shouldLoad shouldLoadSessionResult = 3
+
+// shouldLoadSession determines the appropriate action to take when it is time to load the session for the clientHello.
+// There are several possible scenarios:
+// - If a session ticket is already initialized, typically via the `initSessionTicketExt()` function, the ticket should be set in the client hello.
+// - If a pre-shared key (PSK) is already initialized, typically via the `overridePskExt()` function, the PSK should be set in the client hello.
+// - If both the `sessionTicketExt` and `pskExtension` are nil, which might occur if the client hello spec does not include them, we should skip the loadSession().
+// - In all other cases, the function proceeds to load the session.
+func (s *sessionController) shouldLoadSession() shouldLoadSessionResult {
+ if s.sessionTicketExt == nil && s.pskExtension == nil || s.uconnRef.clientHelloBuildStatus != NotBuilt {
+ // No need to load session since we don't have the related extensions.
+ return shouldReturn
+ }
+ if s.state == SessionTicketExtInitialized {
+ return shouldSetTicket
+ }
+ if s.state == PskExtInitialized {
+ return shouldSetPsk
+ }
+ return shouldLoad
+}
+
+// utlsAboutToLoadSession updates the loadSessionTracker to `UtlsAboutToCall` to signal the initiation of a session loading operation,
+// provided that the preconditions are met. If the preconditions are not met (due to incorrect utls implementation), this function triggers a panic.
+func (s *sessionController) utlsAboutToLoadSession() {
+ uAssert(s.state == NoSession && !s.locked, "tls: aboutToLoadSession failed: must only load session when the session of the client hello is not locked and when there's currently no session")
+ s.loadSessionTracker = UtlsAboutToCall
+}
+
+func (s *sessionController) assertHelloNotBuilt(caller string) {
+ if s.uconnRef.clientHelloBuildStatus != NotBuilt {
+ panic(fmt.Sprintf("tls: %s failed: we can't modify the session after the clientHello is built", caller))
+ }
+}
+
+func (s *sessionController) assertControllerState(caller string, desired sessionControllerState, moreDesiredStates ...sessionControllerState) {
+ if s.state != desired && !anyTrue(moreDesiredStates, func(_ int, state *sessionControllerState) bool {
+ return s.state == *state
+ }) {
+ panic(fmt.Sprintf("tls: %s failed: undesired controller state %d", caller, s.state))
+ }
+}
+
+func (s *sessionController) assertNotLocked(caller string) {
+ if s.locked {
+ panic(fmt.Sprintf("tls: %s failed: you must not modify the session after it's locked", caller))
+ }
+}
+
+func (s *sessionController) assertCanSkip(caller, extensionName string) {
+ if !s.uconnRef.skipResumptionOnNilExtension {
+ panic(fmt.Sprintf("tls: %s failed: session resumption is enabled, but there is no %s in the ClientHelloSpec; Please consider provide one in the ClientHelloSpec; If this is intentional, you may consider disable resumption by setting Config.SessionTicketsDisabled to true, or set Config.PreferSkipResumptionOnNilExtension to true to suppress this exception", caller, extensionName))
+ }
+}
+
+// finalCheck performs a comprehensive check on the updated state to ensure the correctness of the changes.
+// If the checks pass successfully, the sessionController's state will be locked.
+// Any failure in passing the tests indicates incorrect implementations in the utls, which will result in triggering a panic.
+// Refer to the documentation for the `locked` field for more detailed information.
+func (s *sessionController) finalCheck() {
+ s.assertControllerState("SessionController.finalCheck", PskExtAllSet, SessionTicketExtAllSet, NoSession)
+ s.locked = true
+}
+
+func initializationGuard[E Initializable, I func(E)](extension E, initializer I) {
+ uAssert(!extension.IsInitialized(), "tls: initialization failed: the extension is already initialized")
+ initializer(extension)
+ uAssert(extension.IsInitialized(), "tls: initialization failed: the extension is not initialized after initialization")
+}
+
+// initSessionTicketExt initializes the ticket and sets the state to `TicketInitialized`.
+func (s *sessionController) initSessionTicketExt(session *SessionState, ticket []byte) {
+ s.assertNotLocked("initSessionTicketExt")
+ s.assertHelloNotBuilt("initSessionTicketExt")
+ s.assertControllerState("initSessionTicketExt", NoSession)
+ panicOnNil("initSessionTicketExt", session, ticket)
+ if s.sessionTicketExt == nil {
+ s.assertCanSkip("initSessionTicketExt", "session ticket extension")
+ return
+ }
+ initializationGuard(s.sessionTicketExt, func(e ISessionTicketExtension) {
+ s.sessionTicketExt.InitializeByUtls(session, ticket)
+ })
+ s.state = SessionTicketExtInitialized
+}
+
+// initPSK initializes the PSK extension using a valid session. The PSK extension
+// should not be initialized previously, and the parameters must not be nil;
+// otherwise, this function will trigger a panic.
+func (s *sessionController) initPskExt(session *SessionState, earlySecret *tls13.EarlySecret, binderKey []byte, pskIdentities []pskIdentity) {
+ s.assertNotLocked("initPskExt")
+ s.assertHelloNotBuilt("initPskExt")
+ s.assertControllerState("initPskExt", NoSession)
+ panicOnNil("initPskExt", session, earlySecret, pskIdentities)
+ if s.pskExtension == nil {
+ s.assertCanSkip("initPskExt", "pre-shared key extension")
+ return
+ }
+ initializationGuard(s.pskExtension, func(e PreSharedKeyExtension) {
+ publicPskIdentities := mapSlice(pskIdentities, func(private pskIdentity) PskIdentity {
+ return PskIdentity{
+ Label: private.label,
+ ObfuscatedTicketAge: private.obfuscatedTicketAge,
+ }
+ })
+ e.InitializeByUtls(session, earlySecret.Secret(), binderKey, publicPskIdentities)
+ })
+
+ s.state = PskExtInitialized
+}
+
+// setSessionTicketToUConn write the ticket states from the session ticket extension to the client hello and handshake state.
+func (s *sessionController) setSessionTicketToUConn() {
+ uAssert(s.sessionTicketExt != nil && s.state == SessionTicketExtInitialized, "tls: setSessionTicketExt failed: invalid state")
+ s.uconnRef.HandshakeState.Session = s.sessionTicketExt.GetSession()
+ s.uconnRef.HandshakeState.Hello.SessionTicket = s.sessionTicketExt.GetTicket()
+ s.state = SessionTicketExtAllSet
+}
+
+// setPskToUConn sets the psk to the handshake state and client hello.
+func (s *sessionController) setPskToUConn() {
+ uAssert(s.pskExtension != nil && (s.state == PskExtInitialized || s.state == PskExtAllSet), "tls: setPskToUConn failed: invalid state")
+ pskCommon := s.pskExtension.GetPreSharedKeyCommon()
+ if s.state == PskExtInitialized {
+ s.uconnRef.HandshakeState.State13.EarlySecret = pskCommon.EarlySecret
+ s.uconnRef.HandshakeState.Session = pskCommon.Session
+ s.uconnRef.HandshakeState.Hello.PskIdentities = pskCommon.Identities
+ s.uconnRef.HandshakeState.Hello.PskBinders = pskCommon.Binders
+ } else if s.state == PskExtAllSet {
+ uAssert(s.uconnRef.HandshakeState.Session == pskCommon.Session && sliceEq(s.uconnRef.HandshakeState.State13.EarlySecret, pskCommon.EarlySecret) &&
+ allTrue(s.uconnRef.HandshakeState.Hello.PskIdentities, func(i int, psk *PskIdentity) bool {
+ return pskCommon.Identities[i].ObfuscatedTicketAge == psk.ObfuscatedTicketAge && sliceEq(pskCommon.Identities[i].Label, psk.Label)
+ }), "tls: setPskToUConn failed: only binders are allowed to change on state `PskAllSet`")
+ }
+ s.uconnRef.HandshakeState.State13.BinderKey = pskCommon.BinderKey
+ s.state = PskExtAllSet
+}
+
+// shouldUpdateBinders determines whether binders should be updated based on the presence of an initialized psk extension.
+// This function returns true if an initialized psk extension exists. Binders are allowed to be updated when the state is `PskAllSet`,
+// as the `BuildHandshakeState` function can be called multiple times in this case. However, it's important to note that
+// the session state, apart from binders, should not be altered more than once.
+func (s *sessionController) shouldUpdateBinders() bool {
+ if s.pskExtension == nil {
+ return false
+ }
+ return (s.state == PskExtInitialized || s.state == PskExtAllSet)
+}
+
+func (s *sessionController) updateBinders() {
+ uAssert(s.shouldUpdateBinders(), "tls: updateBinders failed: shouldn't update binders")
+ s.pskExtension.PatchBuiltHello(s.uconnRef.HandshakeState.Hello)
+}
+
+func (s *sessionController) overrideExtension(extension Initializable, override func(), initializedState sessionControllerState) error {
+ panicOnNil("overrideExtension", extension)
+ s.assertNotLocked("overrideExtension")
+ s.assertControllerState("overrideExtension", NoSession)
+ override()
+ if extension.IsInitialized() {
+ s.state = initializedState
+ }
+ return nil
+}
+
+// overridePskExt allows the user of utls to customize the psk extension.
+func (s *sessionController) overridePskExt(pskExt PreSharedKeyExtension) error {
+ return s.overrideExtension(pskExt, func() { s.pskExtension = pskExt }, PskExtInitialized)
+}
+
+// overridePskExt allows the user of utls to customize the session ticket extension.
+func (s *sessionController) overrideSessionTicketExt(sessionTicketExt ISessionTicketExtension) error {
+ return s.overrideExtension(sessionTicketExt, func() { s.sessionTicketExt = sessionTicketExt }, SessionTicketExtInitialized)
+}
+
+// syncSessionExts synchronizes the sessionController with the session-related
+// extensions from the extension list after applying client hello specs.
+//
+// - If the extension list is missing the session ticket extension or PSK
+// extension, owned extensions are dropped and states are reset.
+// - If the user provides a session ticket extension or PSK extension, the
+// corresponding extension from the extension list will be replaced.
+// - If the user doesn't provide session-related extensions, the extensions
+// from the extension list will be utilized.
+//
+// This function ensures that there is only one session ticket extension or PSK
+// extension, and that the PSK extension is the last extension in the extension
+// list.
+func (s *sessionController) syncSessionExts() error {
+ uAssert(s.uconnRef.clientHelloBuildStatus == NotBuilt, "tls: checkSessionExts failed: we can't modify the session after the clientHello is built")
+ s.assertNotLocked("checkSessionExts")
+ s.assertHelloNotBuilt("checkSessionExts")
+ s.assertControllerState("checkSessionExts", NoSession, SessionTicketExtInitialized, PskExtInitialized)
+ numSessionExt := 0
+ hasPskExt := false
+ for i, e := range s.uconnRef.Extensions {
+ switch ext := e.(type) {
+ case ISessionTicketExtension:
+ uAssert(numSessionExt == 0, "tls: checkSessionExts failed: multiple ISessionTicketExtensions in the extension list")
+ if s.sessionTicketExt == nil {
+ // If there isn't a user-provided session ticket extension, use the one from the spec
+ s.sessionTicketExt = ext
+ } else {
+ // Otherwise, replace the one in the extension list with the user-provided one
+ s.uconnRef.Extensions[i] = s.sessionTicketExt
+ }
+ numSessionExt += 1
+ case PreSharedKeyExtension:
+ uAssert(i == len(s.uconnRef.Extensions)-1, "tls: checkSessionExts failed: PreSharedKeyExtension must be the last extension")
+ if s.pskExtension == nil {
+ // If there isn't a user-provided psk extension, use the one from the spec
+ s.pskExtension = ext
+ } else {
+ // Otherwise, replace the one in the extension list with the user-provided one
+ s.uconnRef.Extensions[i] = s.pskExtension
+ }
+ s.pskExtension.SetOmitEmptyPsk(s.uconnRef.config.OmitEmptyPsk)
+ hasPskExt = true
+ }
+ }
+ if numSessionExt == 0 {
+ if s.state == SessionTicketExtInitialized {
+ return errors.New("tls: checkSessionExts failed: the user provided a session ticket, but the specification doesn't contain one")
+ }
+ s.sessionTicketExt = nil
+ s.uconnRef.HandshakeState.Session = nil
+ s.uconnRef.HandshakeState.Hello.SessionTicket = nil
+ }
+ if !hasPskExt {
+ if s.state == PskExtInitialized {
+ return errors.New("tls: checkSessionExts failed: the user provided a psk, but the specification doesn't contain one")
+ }
+ s.pskExtension = nil
+ s.uconnRef.HandshakeState.State13.BinderKey = nil
+ s.uconnRef.HandshakeState.State13.EarlySecret = nil
+ s.uconnRef.HandshakeState.Session = nil
+ s.uconnRef.HandshakeState.Hello.PskIdentities = nil
+ }
+ return nil
+}
+
+// onEnterLoadSessionCheck is intended to be invoked upon entering the `conn.loadSession` function.
+// It is designed to ensure the correctness of the utls implementation. If the utls implementation is found to be incorrect, this function will trigger a panic.
+func (s *sessionController) onEnterLoadSessionCheck() {
+ uAssert(!s.locked, "tls: LoadSessionCoordinator.onEnterLoadSessionCheck failed: session is set and locked, no call to loadSession is allowed")
+ switch s.loadSessionTracker {
+ case UtlsAboutToCall, NeverCalled:
+ s.callingLoadSession = true
+ case CalledByULoadSession, CalledByGoTLS:
+ panic("tls: LoadSessionCoordinator.onEnterLoadSessionCheck failed: you must not call loadSession() twice")
+ default:
+ panic("tls: LoadSessionCoordinator.onEnterLoadSessionCheck failed: unimplemented state")
+ }
+}
+
+// onLoadSessionReturn is intended to be invoked upon returning from the `conn.loadSession` function.
+// It serves as a validation step for the correctness of the underlying utls implementation.
+// If the utls implementation is incorrect, this function will trigger a panic.
+func (s *sessionController) onLoadSessionReturn() {
+ uAssert(s.callingLoadSession, "tls: LoadSessionCoordinator.onLoadSessionReturn failed: it's not loading sessions, perhaps this function is not being called by loadSession.")
+ switch s.loadSessionTracker {
+ case NeverCalled:
+ s.loadSessionTracker = CalledByGoTLS
+ case UtlsAboutToCall:
+ s.loadSessionTracker = CalledByULoadSession
+ default:
+ panic("tls: LoadSessionCoordinator.onLoadSessionReturn failed: unimplemented state")
+ }
+ s.callingLoadSession = false
+}
+
+// shouldLoadSessionWriteBinders checks if `conn.loadSession` should proceed to write binders and marshal the client hello. If the utls implementation
+// is incorrect, this function will trigger a panic.
+func (s *sessionController) shouldLoadSessionWriteBinders() bool {
+ uAssert(s.callingLoadSession, "tls: shouldWriteBinders failed: LoadSessionCoordinator isn't loading sessions, perhaps this function is not being called by loadSession.")
+
+ switch s.loadSessionTracker {
+ case NeverCalled:
+ return true
+ case UtlsAboutToCall:
+ return false
+ default:
+ panic("tls: shouldWriteBinders failed: unimplemented state")
+ }
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_session_ticket.go b/vendor/github.com/refraction-networking/utls/u_session_ticket.go
new file mode 100644
index 00000000..caefd065
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_session_ticket.go
@@ -0,0 +1,82 @@
+package tls
+
+import "io"
+
+type ISessionTicketExtension interface {
+ TLSExtension
+
+ // If false is returned, utls will invoke `InitializeByUtls()` for the necessary initialization.
+ Initializable
+
+ // InitializeByUtls is invoked when IsInitialized() returns false.
+ // It initializes the extension using a real and valid TLS 1.2 session.
+ InitializeByUtls(session *SessionState, ticket []byte)
+
+ GetSession() *SessionState
+
+ GetTicket() []byte
+}
+
+// SessionTicketExtension implements session_ticket (35)
+type SessionTicketExtension struct {
+ Session *SessionState
+ Ticket []byte
+ Initialized bool
+}
+
+func (e *SessionTicketExtension) writeToUConn(uc *UConn) error {
+ // session states are handled later. At this point tickets aren't
+ // being loaded by utls, so don't write anything to the UConn.
+ uc.HandshakeState.Hello.TicketSupported = true // This doesn't really matter, this field is only used to add session ticket ext in go tls.
+ return nil
+}
+
+func (e *SessionTicketExtension) Len() int {
+ return 4 + len(e.Ticket)
+}
+
+func (e *SessionTicketExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ extBodyLen := e.Len() - 4
+
+ b[0] = byte(extensionSessionTicket >> 8)
+ b[1] = byte(extensionSessionTicket)
+ b[2] = byte(extBodyLen >> 8)
+ b[3] = byte(extBodyLen)
+ if extBodyLen > 0 {
+ copy(b[4:], e.Ticket)
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *SessionTicketExtension) IsInitialized() bool {
+ return e.Initialized
+}
+
+func (e *SessionTicketExtension) InitializeByUtls(session *SessionState, ticket []byte) {
+ uAssert(!e.Initialized, "tls: InitializeByUtls failed: the SessionTicketExtension is initialized")
+ uAssert(session.version == VersionTLS12 && session != nil && ticket != nil, "tls: InitializeByUtls failed: the session is not a tls 1.2 session")
+ e.Session = session
+ e.Ticket = ticket
+ e.Initialized = true
+}
+
+func (e *SessionTicketExtension) UnmarshalJSON(_ []byte) error {
+ return nil // no-op
+}
+
+func (e *SessionTicketExtension) Write(_ []byte) (int, error) {
+ // RFC 5077, Section 3.2
+ return 0, nil
+}
+
+func (e *SessionTicketExtension) GetSession() *SessionState {
+ return e.Session
+}
+
+func (e *SessionTicketExtension) GetTicket() []byte {
+ return e.Ticket
+}
diff --git a/vendor/github.com/refraction-networking/utls/u_tls_extensions.go b/vendor/github.com/refraction-networking/utls/u_tls_extensions.go
new file mode 100644
index 00000000..c03fdb68
--- /dev/null
+++ b/vendor/github.com/refraction-networking/utls/u_tls_extensions.go
@@ -0,0 +1,1946 @@
+// Copyright 2017 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/refraction-networking/utls/dicttls"
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// ExtensionFromID returns a TLSExtension for the given extension ID.
+func ExtensionFromID(id uint16) TLSExtension {
+ // deep copy
+ switch id {
+ case extensionServerName:
+ return &SNIExtension{}
+ case extensionStatusRequest:
+ return &StatusRequestExtension{}
+ case extensionSupportedCurves:
+ return &SupportedCurvesExtension{}
+ case extensionSupportedPoints:
+ return &SupportedPointsExtension{}
+ case extensionSignatureAlgorithms:
+ return &SignatureAlgorithmsExtension{}
+ case extensionALPN:
+ return &ALPNExtension{}
+ case extensionStatusRequestV2:
+ return &StatusRequestV2Extension{}
+ case extensionSCT:
+ return &SCTExtension{}
+ case utlsExtensionPadding:
+ return &UtlsPaddingExtension{}
+ case extensionExtendedMasterSecret:
+ return &ExtendedMasterSecretExtension{}
+ case fakeExtensionTokenBinding:
+ return &FakeTokenBindingExtension{}
+ case utlsExtensionCompressCertificate:
+ return &UtlsCompressCertExtension{}
+ case fakeRecordSizeLimit:
+ return &FakeRecordSizeLimitExtension{}
+ case fakeExtensionDelegatedCredentials:
+ return &FakeDelegatedCredentialsExtension{}
+ case extensionSessionTicket:
+ return &SessionTicketExtension{}
+ case extensionPreSharedKey:
+ return (PreSharedKeyExtension)(&FakePreSharedKeyExtension{}) // To use the result, caller needs further inspection to decide between Fake or Utls.
+ // case extensionEarlyData:
+ // return &EarlyDataExtension{}
+ case extensionSupportedVersions:
+ return &SupportedVersionsExtension{}
+ // case extensionCookie:
+ // return &CookieExtension{}
+ case extensionPSKModes:
+ return &PSKKeyExchangeModesExtension{}
+ // case extensionCertificateAuthorities:
+ // return &CertificateAuthoritiesExtension{}
+ case extensionSignatureAlgorithmsCert:
+ return &SignatureAlgorithmsCertExtension{}
+ case extensionKeyShare:
+ return &KeyShareExtension{}
+ case extensionQUICTransportParameters:
+ return &QUICTransportParametersExtension{}
+ case extensionNextProtoNeg:
+ return &NPNExtension{}
+ case utlsExtensionApplicationSettings:
+ return &ApplicationSettingsExtension{}
+ case utlsExtensionApplicationSettingsNew:
+ return &ApplicationSettingsExtensionNew{}
+ case fakeOldExtensionChannelID:
+ return &FakeChannelIDExtension{true}
+ case fakeExtensionChannelID:
+ return &FakeChannelIDExtension{}
+ case utlsExtensionECH:
+ return &GREASEEncryptedClientHelloExtension{}
+ case extensionRenegotiationInfo:
+ return &RenegotiationInfoExtension{}
+ default:
+ if isGREASEUint16(id) {
+ return &UtlsGREASEExtension{}
+ }
+ return nil // not returning GenericExtension, it should be handled by caller
+ }
+}
+
+type TLSExtension interface {
+ writeToUConn(*UConn) error
+
+ Len() int // includes header
+
+ // Read reads up to len(p) bytes into p.
+ // It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
+ Read(p []byte) (n int, err error) // implements io.Reader
+}
+
+// TLSExtensionWriter is an interface allowing a TLS extension to be
+// auto-constucted/recovered by reading in a byte stream.
+type TLSExtensionWriter interface {
+ TLSExtension
+
+ // Write writes the extension data as a byte slice, up to len(b) bytes from b.
+ // It returns the number of bytes written (0 <= n <= len(b)) and any error encountered.
+ //
+ // The implementation MUST NOT silently drop data if consumed less than len(b) bytes,
+ // instead, it MUST return an error.
+ Write(b []byte) (n int, err error)
+}
+
+type TLSExtensionJSON interface {
+ TLSExtension
+
+ // UnmarshalJSON unmarshals the JSON-encoded data into the extension.
+ UnmarshalJSON([]byte) error
+}
+
+// SNIExtension implements server_name (0)
+type SNIExtension struct {
+ ServerName string // not an array because go crypto/tls doesn't support multiple SNIs
+}
+
+func (e *SNIExtension) Len() int {
+ // Literal IP addresses, absolute FQDNs, and empty strings are not permitted as SNI values.
+ // See RFC 6066, Section 3.
+ hostName := hostnameInSNI(e.ServerName)
+ if len(hostName) == 0 {
+ return 0
+ }
+ return 4 + 2 + 1 + 2 + len(hostName)
+}
+
+func (e *SNIExtension) Read(b []byte) (int, error) {
+ // Literal IP addresses, absolute FQDNs, and empty strings are not permitted as SNI values.
+ // See RFC 6066, Section 3.
+ hostName := hostnameInSNI(e.ServerName)
+ if len(hostName) == 0 {
+ return 0, io.EOF
+ }
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // RFC 3546, section 3.1
+ b[0] = byte(extensionServerName >> 8)
+ b[1] = byte(extensionServerName)
+ b[2] = byte((len(hostName) + 5) >> 8)
+ b[3] = byte(len(hostName) + 5)
+ b[4] = byte((len(hostName) + 3) >> 8)
+ b[5] = byte(len(hostName) + 3)
+ // b[6] Server Name Type: host_name (0)
+ b[7] = byte(len(hostName) >> 8)
+ b[8] = byte(len(hostName))
+ copy(b[9:], []byte(hostName))
+ return e.Len(), io.EOF
+}
+
+func (e *SNIExtension) UnmarshalJSON(_ []byte) error {
+ return nil // no-op
+}
+
+// Write is a no-op for StatusRequestExtension.
+// SNI should not be fingerprinted and is user controlled.
+func (e *SNIExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 6066, Section 3
+ var nameList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
+ return fullLen, errors.New("unable to read server name extension data")
+ }
+ var serverName string
+ for !nameList.Empty() {
+ var nameType uint8
+ var serverNameBytes cryptobyte.String
+ if !nameList.ReadUint8(&nameType) ||
+ !nameList.ReadUint16LengthPrefixed(&serverNameBytes) ||
+ serverNameBytes.Empty() {
+ return fullLen, errors.New("unable to read server name extension data")
+ }
+ if nameType != 0 {
+ continue
+ }
+ if len(serverName) != 0 {
+ return fullLen, errors.New("multiple names of the same name_type in server name extension are prohibited")
+ }
+ serverName = string(serverNameBytes)
+ if strings.HasSuffix(serverName, ".") {
+ return fullLen, errors.New("SNI value may not include a trailing dot")
+ }
+ }
+ // clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SNIExtension{}) // gaukas moved this line out from the loop.
+
+ // don't copy SNI from ClientHello to ClientHelloSpec!
+ return fullLen, nil
+}
+
+func (e *SNIExtension) writeToUConn(uc *UConn) error {
+ if uc.config.EncryptedClientHelloConfigList == nil { // with ech, e.ServerName is the outer public name and should not be copied
+ uc.config.ServerName = e.ServerName
+ }
+ hostName := hostnameInSNI(e.ServerName)
+ uc.HandshakeState.Hello.ServerName = hostName
+
+ return nil
+}
+
+// StatusRequestExtension implements status_request (5)
+type StatusRequestExtension struct {
+}
+
+func (e *StatusRequestExtension) Len() int {
+ return 9
+}
+
+func (e *StatusRequestExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // RFC 4366, section 3.6
+ b[0] = byte(extensionStatusRequest >> 8)
+ b[1] = byte(extensionStatusRequest)
+ b[2] = 0
+ b[3] = 5
+ b[4] = 1 // OCSP type
+ // Two zero valued uint16s for the two lengths.
+ return e.Len(), io.EOF
+}
+
+func (e *StatusRequestExtension) UnmarshalJSON(_ []byte) error {
+ return nil // no-op
+}
+
+// Write is a no-op for StatusRequestExtension. No data for this extension.
+func (e *StatusRequestExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 4366, Section 3.6
+ var statusType uint8
+ var ignored cryptobyte.String
+ if !extData.ReadUint8(&statusType) ||
+ !extData.ReadUint16LengthPrefixed(&ignored) ||
+ !extData.ReadUint16LengthPrefixed(&ignored) {
+ return fullLen, errors.New("unable to read status request extension data")
+ }
+
+ if statusType != statusTypeOCSP {
+ return fullLen, errors.New("status request extension statusType is not statusTypeOCSP(1)")
+ }
+
+ return fullLen, nil
+}
+
+func (e *StatusRequestExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.OcspStapling = true
+ return nil
+}
+
+// SupportedCurvesExtension implements supported_groups (renamed from "elliptic_curves") (10)
+type SupportedCurvesExtension struct {
+ Curves []CurveID
+}
+
+func (e *SupportedCurvesExtension) Len() int {
+ return 6 + 2*len(e.Curves)
+}
+
+func (e *SupportedCurvesExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ b[0] = byte(extensionSupportedCurves >> 8)
+ b[1] = byte(extensionSupportedCurves)
+ b[2] = byte((2 + 2*len(e.Curves)) >> 8)
+ b[3] = byte(2 + 2*len(e.Curves))
+ b[4] = byte((2 * len(e.Curves)) >> 8)
+ b[5] = byte(2 * len(e.Curves))
+ for i, curve := range e.Curves {
+ b[6+2*i] = byte(curve >> 8)
+ b[7+2*i] = byte(curve)
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *SupportedCurvesExtension) UnmarshalJSON(data []byte) error {
+ var namedGroups struct {
+ NamedGroupList []string `json:"named_group_list"`
+ }
+ if err := json.Unmarshal(data, &namedGroups); err != nil {
+ return err
+ }
+
+ for _, namedGroup := range namedGroups.NamedGroupList {
+ if namedGroup == "GREASE" {
+ e.Curves = append(e.Curves, GREASE_PLACEHOLDER)
+ continue
+ }
+
+ if group, ok := dicttls.DictSupportedGroupsNameIndexed[namedGroup]; ok {
+ e.Curves = append(e.Curves, CurveID(group))
+ } else {
+ return fmt.Errorf("unknown named group: %s", namedGroup)
+ }
+ }
+ return nil
+}
+
+func (e *SupportedCurvesExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+ var curvesBytes cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&curvesBytes) || curvesBytes.Empty() {
+ return 0, errors.New("unable to read supported curves extension data")
+ }
+ curves := []CurveID{}
+ for !curvesBytes.Empty() {
+ var curve uint16
+ if !curvesBytes.ReadUint16(&curve) {
+ return 0, errors.New("unable to read supported curves extension data")
+ }
+ curves = append(curves, CurveID(unGREASEUint16(curve)))
+ }
+ e.Curves = curves
+ return fullLen, nil
+}
+
+func (e *SupportedCurvesExtension) writeToUConn(uc *UConn) error {
+ uc.config.CurvePreferences = e.Curves
+ uc.HandshakeState.Hello.SupportedCurves = e.Curves
+ return nil
+}
+
+// SupportedPointsExtension implements ec_point_formats (11)
+type SupportedPointsExtension struct {
+ SupportedPoints []uint8
+}
+
+func (e *SupportedPointsExtension) Len() int {
+ return 5 + len(e.SupportedPoints)
+}
+
+func (e *SupportedPointsExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ b[0] = byte(extensionSupportedPoints >> 8)
+ b[1] = byte(extensionSupportedPoints)
+ b[2] = byte((1 + len(e.SupportedPoints)) >> 8)
+ b[3] = byte(1 + len(e.SupportedPoints))
+ b[4] = byte(len(e.SupportedPoints))
+ for i, pointFormat := range e.SupportedPoints {
+ b[5+i] = pointFormat
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *SupportedPointsExtension) UnmarshalJSON(data []byte) error {
+ var pointFormatList struct {
+ ECPointFormatList []string `json:"ec_point_format_list"`
+ }
+ if err := json.Unmarshal(data, &pointFormatList); err != nil {
+ return err
+ }
+
+ for _, pointFormat := range pointFormatList.ECPointFormatList {
+ if format, ok := dicttls.DictECPointFormatNameIndexed[pointFormat]; ok {
+ e.SupportedPoints = append(e.SupportedPoints, format)
+ } else {
+ return fmt.Errorf("unknown point format: %s", pointFormat)
+ }
+ }
+ return nil
+}
+
+func (e *SupportedPointsExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 4492, Section 5.1.2
+ supportedPoints := []uint8{}
+ if !readUint8LengthPrefixed(&extData, &supportedPoints) ||
+ len(supportedPoints) == 0 {
+ return 0, errors.New("unable to read supported points extension data")
+ }
+ e.SupportedPoints = supportedPoints
+ return fullLen, nil
+}
+
+func (e *SupportedPointsExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.SupportedPoints = e.SupportedPoints
+ return nil
+}
+
+// SignatureAlgorithmsExtension implements signature_algorithms (13)
+type SignatureAlgorithmsExtension struct {
+ SupportedSignatureAlgorithms []SignatureScheme
+}
+
+func (e *SignatureAlgorithmsExtension) Len() int {
+ return 6 + 2*len(e.SupportedSignatureAlgorithms)
+}
+
+func (e *SignatureAlgorithmsExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ b[0] = byte(extensionSignatureAlgorithms >> 8)
+ b[1] = byte(extensionSignatureAlgorithms)
+ b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
+ b[3] = byte(2 + 2*len(e.SupportedSignatureAlgorithms))
+ b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
+ b[5] = byte(2 * len(e.SupportedSignatureAlgorithms))
+ for i, sigScheme := range e.SupportedSignatureAlgorithms {
+ b[6+2*i] = byte(sigScheme >> 8)
+ b[7+2*i] = byte(sigScheme)
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *SignatureAlgorithmsExtension) UnmarshalJSON(data []byte) error {
+ var signatureAlgorithms struct {
+ Algorithms []string `json:"supported_signature_algorithms"`
+ }
+ if err := json.Unmarshal(data, &signatureAlgorithms); err != nil {
+ return err
+ }
+
+ for _, sigScheme := range signatureAlgorithms.Algorithms {
+ if sigScheme == "GREASE" {
+ e.SupportedSignatureAlgorithms = append(e.SupportedSignatureAlgorithms, GREASE_PLACEHOLDER)
+ continue
+ }
+
+ if scheme, ok := dicttls.DictSignatureSchemeNameIndexed[sigScheme]; ok {
+ e.SupportedSignatureAlgorithms = append(e.SupportedSignatureAlgorithms, SignatureScheme(scheme))
+ } else {
+ return fmt.Errorf("unknown signature scheme: %s", sigScheme)
+ }
+ }
+ return nil
+}
+
+func (e *SignatureAlgorithmsExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 5246, Section 7.4.1.4.1
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return 0, errors.New("unable to read signature algorithms extension data")
+ }
+ supportedSignatureAlgorithms := []SignatureScheme{}
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return 0, errors.New("unable to read signature algorithms extension data")
+ }
+ supportedSignatureAlgorithms = append(
+ supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+ }
+ e.SupportedSignatureAlgorithms = supportedSignatureAlgorithms
+ return fullLen, nil
+}
+
+func (e *SignatureAlgorithmsExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.SupportedSignatureAlgorithms = e.SupportedSignatureAlgorithms
+ return nil
+}
+
+// StatusRequestV2Extension implements status_request_v2 (17)
+type StatusRequestV2Extension struct {
+}
+
+func (e *StatusRequestV2Extension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.OcspStapling = true
+ return nil
+}
+
+func (e *StatusRequestV2Extension) Len() int {
+ return 13
+}
+
+func (e *StatusRequestV2Extension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // RFC 4366, section 3.6
+ b[0] = byte(extensionStatusRequestV2 >> 8)
+ b[1] = byte(extensionStatusRequestV2)
+ b[2] = 0
+ b[3] = 9
+ b[4] = 0
+ b[5] = 7
+ b[6] = 2 // OCSP type
+ b[7] = 0
+ b[8] = 4
+ // Two zero valued uint16s for the two lengths.
+ return e.Len(), io.EOF
+}
+
+// Write is a no-op for StatusRequestV2Extension. No data for this extension.
+func (e *StatusRequestV2Extension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 4366, Section 3.6
+ var statusType uint8
+ var ignored cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&ignored) || !ignored.ReadUint8(&statusType) {
+ return fullLen, errors.New("unable to read status request v2 extension data")
+ }
+
+ if statusType != statusV2TypeOCSP {
+ return fullLen, errors.New("status request v2 extension statusType is not statusV2TypeOCSP(2)")
+ }
+
+ return fullLen, nil
+}
+
+func (e *StatusRequestV2Extension) UnmarshalJSON(_ []byte) error {
+ return nil // no-op
+}
+
+// SignatureAlgorithmsCertExtension implements signature_algorithms_cert (50)
+type SignatureAlgorithmsCertExtension struct {
+ SupportedSignatureAlgorithms []SignatureScheme
+}
+
+func (e *SignatureAlgorithmsCertExtension) Len() int {
+ return 6 + 2*len(e.SupportedSignatureAlgorithms)
+}
+
+func (e *SignatureAlgorithmsCertExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ b[0] = byte(extensionSignatureAlgorithmsCert >> 8)
+ b[1] = byte(extensionSignatureAlgorithmsCert)
+ b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
+ b[3] = byte(2 + 2*len(e.SupportedSignatureAlgorithms))
+ b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
+ b[5] = byte(2 * len(e.SupportedSignatureAlgorithms))
+ for i, sigAndHash := range e.SupportedSignatureAlgorithms {
+ b[6+2*i] = byte(sigAndHash >> 8)
+ b[7+2*i] = byte(sigAndHash)
+ }
+ return e.Len(), io.EOF
+}
+
+// Copied from SignatureAlgorithmsExtension.UnmarshalJSON
+func (e *SignatureAlgorithmsCertExtension) UnmarshalJSON(data []byte) error {
+ var signatureAlgorithms struct {
+ Algorithms []string `json:"supported_signature_algorithms"`
+ }
+ if err := json.Unmarshal(data, &signatureAlgorithms); err != nil {
+ return err
+ }
+
+ for _, sigScheme := range signatureAlgorithms.Algorithms {
+ if sigScheme == "GREASE" {
+ e.SupportedSignatureAlgorithms = append(e.SupportedSignatureAlgorithms, GREASE_PLACEHOLDER)
+ continue
+ }
+
+ if scheme, ok := dicttls.DictSignatureSchemeNameIndexed[sigScheme]; ok {
+ e.SupportedSignatureAlgorithms = append(e.SupportedSignatureAlgorithms, SignatureScheme(scheme))
+ } else {
+ return fmt.Errorf("unknown cert signature scheme: %s", sigScheme)
+ }
+ }
+ return nil
+}
+
+// Write implementation copied from SignatureAlgorithmsExtension.Write
+//
+// Warning: not tested.
+func (e *SignatureAlgorithmsCertExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 8446, Section 4.2.3
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return 0, errors.New("unable to read signature algorithms extension data")
+ }
+ supportedSignatureAlgorithms := []SignatureScheme{}
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return 0, errors.New("unable to read signature algorithms extension data")
+ }
+ supportedSignatureAlgorithms = append(
+ supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+ }
+ e.SupportedSignatureAlgorithms = supportedSignatureAlgorithms
+ return fullLen, nil
+}
+
+func (e *SignatureAlgorithmsCertExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.SupportedSignatureAlgorithms = e.SupportedSignatureAlgorithms
+ return nil
+}
+
+// ALPNExtension implements application_layer_protocol_negotiation (16)
+type ALPNExtension struct {
+ AlpnProtocols []string
+}
+
+func (e *ALPNExtension) writeToUConn(uc *UConn) error {
+ uc.config.NextProtos = e.AlpnProtocols
+ uc.HandshakeState.Hello.AlpnProtocols = e.AlpnProtocols
+ return nil
+}
+
+func (e *ALPNExtension) Len() int {
+ bLen := 2 + 2 + 2
+ for _, s := range e.AlpnProtocols {
+ bLen += 1 + len(s)
+ }
+ return bLen
+}
+
+func (e *ALPNExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ b[0] = byte(extensionALPN >> 8)
+ b[1] = byte(extensionALPN & 0xff)
+ lengths := b[2:]
+ b = b[6:]
+
+ stringsLength := 0
+ for _, s := range e.AlpnProtocols {
+ l := len(s)
+ b[0] = byte(l)
+ copy(b[1:], s)
+ b = b[1+l:]
+ stringsLength += 1 + l
+ }
+
+ lengths[2] = byte(stringsLength >> 8)
+ lengths[3] = byte(stringsLength)
+ stringsLength += 2
+ lengths[0] = byte(stringsLength >> 8)
+ lengths[1] = byte(stringsLength)
+
+ return e.Len(), io.EOF
+}
+
+func (e *ALPNExtension) UnmarshalJSON(b []byte) error {
+ var protocolNames struct {
+ ProtocolNameList []string `json:"protocol_name_list"`
+ }
+
+ if err := json.Unmarshal(b, &protocolNames); err != nil {
+ return err
+ }
+
+ e.AlpnProtocols = protocolNames.ProtocolNameList
+ return nil
+}
+
+func (e *ALPNExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 7301, Section 3.1
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return 0, errors.New("unable to read ALPN extension data")
+ }
+ alpnProtocols := []string{}
+ for !protoList.Empty() {
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
+ return 0, errors.New("unable to read ALPN extension data")
+ }
+ alpnProtocols = append(alpnProtocols, string(proto))
+
+ }
+ e.AlpnProtocols = alpnProtocols
+ return fullLen, nil
+}
+
+// applicationSettingsExtension represents the TLS ALPS extension.
+// At the time of this writing, this extension is currently a draft:
+// https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01
+type applicationSettingsExtension struct {
+ codePoint uint16
+}
+
+func (e *applicationSettingsExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *applicationSettingsExtension) Len(supportedProtocols []string) int {
+ bLen := 2 + 2 + 2 // Type + Length + ALPS Extension length
+ for _, s := range supportedProtocols {
+ bLen += 1 + len(s) // Supported ALPN Length + actual length of protocol
+ }
+ return bLen
+}
+
+func (e *applicationSettingsExtension) Read(b []byte, supportedProtocols []string) (int, error) {
+ if len(b) < e.Len(supportedProtocols) {
+ return 0, io.ErrShortBuffer
+ }
+
+ // Read Type.
+ b[0] = byte(e.codePoint >> 8) // hex: 44 dec: 68
+ b[1] = byte(e.codePoint & 0xff) // hex: 69 dec: 105
+
+ lengths := b[2:] // get the remaining buffer without Type
+ b = b[6:] // set the buffer to the buffer without Type, Length and ALPS Extension Length (so only the Supported ALPN list remains)
+
+ stringsLength := 0
+ for _, s := range supportedProtocols {
+ l := len(s) // Supported ALPN Length
+ b[0] = byte(l) // Supported ALPN Length in bytes hex: 02 dec: 2
+ copy(b[1:], s) // copy the Supported ALPN as bytes to the buffer
+ b = b[1+l:] // set the buffer to the buffer without the Supported ALPN Length and Supported ALPN (so we can continue to the next protocol in this loop)
+ stringsLength += 1 + l // Supported ALPN Length (the field itself) + Supported ALPN Length (the value)
+ }
+
+ lengths[2] = byte(stringsLength >> 8) // ALPS Extension Length hex: 00 dec: 0
+ lengths[3] = byte(stringsLength) // ALPS Extension Length hex: 03 dec: 3
+ stringsLength += 2 // plus ALPS Extension Length field length
+ lengths[0] = byte(stringsLength >> 8) // Length hex:00 dec: 0
+ lengths[1] = byte(stringsLength) // Length hex: 05 dec: 5
+
+ return e.Len(supportedProtocols), io.EOF
+}
+
+// Write implementation copied from ALPNExtension.Write
+func (e *applicationSettingsExtension) Write(b []byte) ([]string, int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps-01
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return nil, 0, errors.New("unable to read ALPN extension data")
+ }
+ alpnProtocols := []string{}
+ for !protoList.Empty() {
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
+ return nil, 0, errors.New("unable to read ALPN extension data")
+ }
+ alpnProtocols = append(alpnProtocols, string(proto))
+
+ }
+ return alpnProtocols, fullLen, nil
+}
+
+// ApplicationSettingsExtension embeds applicationSettingsExtension to implement the TLS ALPS extension on codepoint 17513
+type ApplicationSettingsExtension struct {
+ applicationSettingsExtension
+ SupportedProtocols []string
+}
+
+func (e *ApplicationSettingsExtension) Len() int {
+ return e.applicationSettingsExtension.Len(e.SupportedProtocols)
+}
+
+func (e *ApplicationSettingsExtension) Read(b []byte) (int, error) {
+ e.applicationSettingsExtension.codePoint = utlsExtensionApplicationSettings
+ return e.applicationSettingsExtension.Read(b, e.SupportedProtocols)
+}
+
+func (e *ApplicationSettingsExtension) UnmarshalJSON(b []byte) error {
+ var applicationSettingsSupport struct {
+ SupportedProtocols []string `json:"supported_protocols"`
+ }
+
+ if err := json.Unmarshal(b, &applicationSettingsSupport); err != nil {
+ return err
+ }
+
+ e.SupportedProtocols = applicationSettingsSupport.SupportedProtocols
+ return nil
+}
+
+// Write implementation copied from ALPNExtension.Write
+func (e *ApplicationSettingsExtension) Write(b []byte) (int, error) {
+ var (
+ fullLen int
+ err error
+ )
+ e.SupportedProtocols, fullLen, err = e.applicationSettingsExtension.Write(b)
+ return fullLen, err
+}
+
+// ApplicationSettingsExtensionNew embeds applicationSettingsExtension to implement the TLS ALPS extension on codepoint 17613
+// More information can be found here: https://chromestatus.com/feature/5149147365900288
+type ApplicationSettingsExtensionNew struct {
+ applicationSettingsExtension
+ SupportedProtocols []string
+}
+
+func (e *ApplicationSettingsExtensionNew) Len() int {
+ return e.applicationSettingsExtension.Len(e.SupportedProtocols)
+}
+
+func (e *ApplicationSettingsExtensionNew) Read(b []byte) (int, error) {
+ e.applicationSettingsExtension.codePoint = utlsExtensionApplicationSettingsNew
+ return e.applicationSettingsExtension.Read(b, e.SupportedProtocols)
+}
+
+func (e *ApplicationSettingsExtensionNew) UnmarshalJSON(b []byte) error {
+ var applicationSettingsSupport struct {
+ SupportedProtocols []string `json:"supported_protocols"`
+ }
+
+ if err := json.Unmarshal(b, &applicationSettingsSupport); err != nil {
+ return err
+ }
+
+ e.SupportedProtocols = applicationSettingsSupport.SupportedProtocols
+ return nil
+}
+
+// Write implementation copied from ALPNExtension.Write
+func (e *ApplicationSettingsExtensionNew) Write(b []byte) (int, error) {
+ var (
+ fullLen int
+ err error
+ )
+ e.SupportedProtocols, fullLen, err = e.applicationSettingsExtension.Write(b)
+ return fullLen, err
+}
+
+// SCTExtension implements signed_certificate_timestamp (18)
+type SCTExtension struct {
+}
+
+func (e *SCTExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.Scts = true
+ return nil
+}
+
+func (e *SCTExtension) Len() int {
+ return 4
+}
+
+func (e *SCTExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // https://tools.ietf.org/html/rfc6962#section-3.3.1
+ b[0] = byte(extensionSCT >> 8)
+ b[1] = byte(extensionSCT)
+ // zero uint16 for the zero-length extension_data
+ return e.Len(), io.EOF
+}
+
+func (e *SCTExtension) UnmarshalJSON(_ []byte) error {
+ return nil // no-op
+}
+
+func (e *SCTExtension) Write(_ []byte) (int, error) {
+ return 0, nil
+}
+
+// GenericExtension allows to include in ClientHello arbitrary unsupported extensions.
+// It is not defined in TLS RFCs nor by IANA.
+// If a server echoes this extension back, the handshake will likely fail due to no further support.
+type GenericExtension struct {
+ Id uint16
+ Data []byte
+}
+
+func (e *GenericExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *GenericExtension) Len() int {
+ return 4 + len(e.Data)
+}
+
+func (e *GenericExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ b[0] = byte(e.Id >> 8)
+ b[1] = byte(e.Id)
+ b[2] = byte(len(e.Data) >> 8)
+ b[3] = byte(len(e.Data))
+ if len(e.Data) > 0 {
+ copy(b[4:], e.Data)
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *GenericExtension) UnmarshalJSON(b []byte) error {
+ var genericExtension struct {
+ Name string `json:"name"`
+ Data []byte `json:"data"`
+ }
+ if err := json.Unmarshal(b, &genericExtension); err != nil {
+ return err
+ }
+
+ // lookup extension ID by name
+ if id, ok := dicttls.DictExtTypeNameIndexed[genericExtension.Name]; ok {
+ e.Id = id
+ } else {
+ return fmt.Errorf("unknown extension name %s", genericExtension.Name)
+ }
+ e.Data = genericExtension.Data
+ return nil
+}
+
+// ExtendedMasterSecretExtension implements extended_master_secret (23)
+//
+// Was named as ExtendedMasterSecretExtension, renamed due to crypto/tls
+// implemented this extension's support.
+type ExtendedMasterSecretExtension struct {
+}
+
+// TODO: update when this extension is implemented in crypto/tls
+// but we probably won't have to enable it in Config
+func (e *ExtendedMasterSecretExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.Ems = true
+ return nil
+}
+
+func (e *ExtendedMasterSecretExtension) Len() int {
+ return 4
+}
+
+func (e *ExtendedMasterSecretExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // https://tools.ietf.org/html/rfc7627
+ b[0] = byte(extensionExtendedMasterSecret >> 8)
+ b[1] = byte(extensionExtendedMasterSecret)
+ // The length is 0
+ return e.Len(), io.EOF
+}
+
+func (e *ExtendedMasterSecretExtension) UnmarshalJSON(_ []byte) error {
+ return nil // no-op
+}
+
+func (e *ExtendedMasterSecretExtension) Write(_ []byte) (int, error) {
+ // https://tools.ietf.org/html/rfc7627
+ return 0, nil
+}
+
+// GREASE stinks with dead parrots, have to be super careful, and, if possible, not include GREASE
+// https://github.com/google/boringssl/blob/1c68fa2350936ca5897a66b430ebaf333a0e43f5/ssl/internal.h
+const (
+ ssl_grease_cipher = iota
+ ssl_grease_group
+ ssl_grease_extension1
+ ssl_grease_extension2
+ ssl_grease_version
+ ssl_grease_ticket_extension
+ ssl_grease_last_index = ssl_grease_ticket_extension
+)
+
+// it is responsibility of user not to generate multiple grease extensions with same value
+type UtlsGREASEExtension struct {
+ Value uint16
+ Body []byte // in Chrome first grease has empty body, second grease has a single zero byte
+}
+
+func (e *UtlsGREASEExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+// will panic if ssl_grease_last_index[index] is out of bounds.
+func GetBoringGREASEValue(greaseSeed [ssl_grease_last_index]uint16, index int) uint16 {
+ // GREASE value is back from deterministic to random.
+ // https://github.com/google/boringssl/blob/a365138ac60f38b64bfc608b493e0f879845cb88/ssl/handshake_client.c#L530
+ ret := uint16(greaseSeed[index])
+ /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
+ ret = (ret & 0xf0) | 0x0a
+ ret |= ret << 8
+ return ret
+}
+
+func (e *UtlsGREASEExtension) Len() int {
+ return 4 + len(e.Body)
+}
+
+func (e *UtlsGREASEExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ b[0] = byte(e.Value >> 8)
+ b[1] = byte(e.Value)
+ b[2] = byte(len(e.Body) >> 8)
+ b[3] = byte(len(e.Body))
+ if len(e.Body) > 0 {
+ copy(b[4:], e.Body)
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *UtlsGREASEExtension) Write(b []byte) (int, error) {
+ e.Value = GREASE_PLACEHOLDER
+ e.Body = make([]byte, len(b))
+ n := copy(e.Body, b)
+ return n, nil
+}
+
+func (e *UtlsGREASEExtension) UnmarshalJSON(b []byte) error {
+ var jsonObj struct {
+ Id uint16 `json:"id"`
+ Data []byte `json:"data"`
+ KeepID bool `json:"keep_id"`
+ KeepData bool `json:"keep_data"`
+ }
+
+ if err := json.Unmarshal(b, &jsonObj); err != nil {
+ return err
+ }
+
+ if jsonObj.Id == 0 {
+ return nil
+ }
+
+ if isGREASEUint16(jsonObj.Id) {
+ if jsonObj.KeepID {
+ e.Value = jsonObj.Id
+ }
+ if jsonObj.KeepData {
+ e.Body = jsonObj.Data
+ }
+ return nil
+ } else {
+ return errors.New("GREASE extension id must be a GREASE value")
+ }
+}
+
+// UtlsPaddingExtension implements padding (21)
+type UtlsPaddingExtension struct {
+ PaddingLen int
+ WillPad bool // set to false to disable extension
+
+ // Functor for deciding on padding length based on unpadded ClientHello length.
+ // If willPad is false, then this extension should not be included.
+ GetPaddingLen func(clientHelloUnpaddedLen int) (paddingLen int, willPad bool)
+}
+
+func (e *UtlsPaddingExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *UtlsPaddingExtension) Len() int {
+ if e.WillPad {
+ return 4 + e.PaddingLen
+ } else {
+ return 0
+ }
+}
+
+func (e *UtlsPaddingExtension) Update(clientHelloUnpaddedLen int) {
+ if e.GetPaddingLen != nil {
+ e.PaddingLen, e.WillPad = e.GetPaddingLen(clientHelloUnpaddedLen)
+ }
+}
+
+func (e *UtlsPaddingExtension) Read(b []byte) (int, error) {
+ if !e.WillPad {
+ return 0, io.EOF
+ }
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // https://tools.ietf.org/html/rfc7627
+ b[0] = byte(utlsExtensionPadding >> 8)
+ b[1] = byte(utlsExtensionPadding)
+ b[2] = byte(e.PaddingLen >> 8)
+ b[3] = byte(e.PaddingLen)
+ return e.Len(), io.EOF
+}
+
+func (e *UtlsPaddingExtension) UnmarshalJSON(b []byte) error {
+ var jsonObj struct {
+ Length uint `json:"len"`
+ }
+ if err := json.Unmarshal(b, &jsonObj); err != nil {
+ return err
+ }
+
+ if jsonObj.Length == 0 {
+ e.GetPaddingLen = BoringPaddingStyle
+ } else {
+ e.PaddingLen = int(jsonObj.Length)
+ e.WillPad = true
+ }
+
+ return nil
+}
+
+func (e *UtlsPaddingExtension) Write(_ []byte) (int, error) {
+ e.GetPaddingLen = BoringPaddingStyle
+ return 0, nil
+}
+
+// https://github.com/google/boringssl/blob/7d7554b6b3c79e707e25521e61e066ce2b996e4c/ssl/t1_lib.c#L2803
+func BoringPaddingStyle(unpaddedLen int) (int, bool) {
+ if unpaddedLen > 0xff && unpaddedLen < 0x200 {
+ paddingLen := 0x200 - unpaddedLen
+ if paddingLen >= 4+1 {
+ paddingLen -= 4
+ } else {
+ paddingLen = 1
+ }
+ return paddingLen, true
+ }
+ return 0, false
+}
+
+// AlwaysPadToLen could be used for parsed ClientHello, since some fingerprints
+// might not use BoringSSL padding style and we want to pad to a the same length.
+func AlwaysPadToLen(padToLen int) func(int) (int, bool) {
+ return func(unpaddedLen int) (int, bool) {
+ if unpaddedLen < padToLen {
+ paddingLen := padToLen - unpaddedLen
+ if paddingLen >= 4+1 {
+ paddingLen -= 4
+ } else {
+ paddingLen = 1
+ }
+ return paddingLen, true
+ }
+ return 0, false
+ }
+}
+
+// UtlsCompressCertExtension implements compress_certificate (27) and is only implemented client-side
+// for server certificates. Alternate certificate message formats
+// (https://datatracker.ietf.org/doc/html/rfc7250) are not supported.
+//
+// See https://datatracker.ietf.org/doc/html/rfc8879#section-3
+type UtlsCompressCertExtension struct {
+ Algorithms []CertCompressionAlgo
+}
+
+func (e *UtlsCompressCertExtension) writeToUConn(uc *UConn) error {
+ uc.certCompressionAlgs = e.Algorithms
+ return nil
+}
+
+func (e *UtlsCompressCertExtension) Len() int {
+ return 4 + 1 + (2 * len(e.Algorithms))
+}
+
+func (e *UtlsCompressCertExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ b[0] = byte(utlsExtensionCompressCertificate >> 8)
+ b[1] = byte(utlsExtensionCompressCertificate & 0xff)
+
+ extLen := 2 * len(e.Algorithms)
+ if extLen > 255 {
+ return 0, errors.New("too many certificate compression methods")
+ }
+
+ // Extension data length.
+ b[2] = byte((extLen + 1) >> 8)
+ b[3] = byte((extLen + 1) & 0xff)
+
+ // Methods length.
+ b[4] = byte(extLen)
+
+ i := 5
+ for _, compMethod := range e.Algorithms {
+ b[i] = byte(compMethod >> 8)
+ b[i+1] = byte(compMethod)
+ i += 2
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *UtlsCompressCertExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ methods := []CertCompressionAlgo{}
+ methodsRaw := new(cryptobyte.String)
+ if !extData.ReadUint8LengthPrefixed(methodsRaw) {
+ return 0, errors.New("unable to read cert compression algorithms extension data")
+ }
+ for !methodsRaw.Empty() {
+ var method uint16
+ if !methodsRaw.ReadUint16(&method) {
+ return 0, errors.New("unable to read cert compression algorithms extension data")
+ }
+ methods = append(methods, CertCompressionAlgo(method))
+ }
+
+ e.Algorithms = methods
+ return fullLen, nil
+}
+
+func (e *UtlsCompressCertExtension) UnmarshalJSON(b []byte) error {
+ var certificateCompressionAlgorithms struct {
+ Algorithms []string `json:"algorithms"`
+ }
+ if err := json.Unmarshal(b, &certificateCompressionAlgorithms); err != nil {
+ return err
+ }
+
+ for _, algorithm := range certificateCompressionAlgorithms.Algorithms {
+ if alg, ok := dicttls.DictCertificateCompressionAlgorithmNameIndexed[algorithm]; ok {
+ e.Algorithms = append(e.Algorithms, CertCompressionAlgo(alg))
+ } else {
+ return fmt.Errorf("unknown certificate compression algorithm %s", algorithm)
+ }
+ }
+ return nil
+}
+
+// KeyShareExtension implements key_share (51) and is for TLS 1.3 only.
+type KeyShareExtension struct {
+ KeyShares []KeyShare
+}
+
+func (e *KeyShareExtension) Len() int {
+ return 4 + 2 + e.keySharesLen()
+}
+
+func (e *KeyShareExtension) keySharesLen() int {
+ extLen := 0
+ for _, ks := range e.KeyShares {
+ extLen += 4 + len(ks.Data)
+ }
+ return extLen
+}
+
+func (e *KeyShareExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ b[0] = byte(extensionKeyShare >> 8)
+ b[1] = byte(extensionKeyShare)
+ keySharesLen := e.keySharesLen()
+ b[2] = byte((keySharesLen + 2) >> 8)
+ b[3] = byte(keySharesLen + 2)
+ b[4] = byte((keySharesLen) >> 8)
+ b[5] = byte(keySharesLen)
+
+ i := 6
+ for _, ks := range e.KeyShares {
+ b[i] = byte(ks.Group >> 8)
+ b[i+1] = byte(ks.Group)
+ b[i+2] = byte(len(ks.Data) >> 8)
+ b[i+3] = byte(len(ks.Data))
+ copy(b[i+4:], ks.Data)
+ i += 4 + len(ks.Data)
+ }
+
+ return e.Len(), io.EOF
+}
+
+func (e *KeyShareExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 8446, Section 4.2.8
+ var clientShares cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&clientShares) {
+ return 0, errors.New("unable to read key share extension data")
+ }
+ keyShares := []KeyShare{}
+ for !clientShares.Empty() {
+ var ks KeyShare
+ var group uint16
+ if !clientShares.ReadUint16(&group) ||
+ !readUint16LengthPrefixed(&clientShares, &ks.Data) ||
+ len(ks.Data) == 0 {
+ return 0, errors.New("unable to read key share extension data")
+ }
+ ks.Group = CurveID(unGREASEUint16(group))
+ // if not GREASE, key share data will be discarded as it should
+ // be generated per connection
+ if ks.Group != GREASE_PLACEHOLDER {
+ ks.Data = nil
+ }
+ keyShares = append(keyShares, ks)
+ }
+ e.KeyShares = keyShares
+ return fullLen, nil
+}
+
+func (e *KeyShareExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.KeyShares = e.KeyShares
+ return nil
+}
+
+func (e *KeyShareExtension) UnmarshalJSON(b []byte) error {
+ var keyShareClientHello struct {
+ ClientShares []struct {
+ Group string `json:"group"`
+ KeyExchange []uint8 `json:"key_exchange"`
+ } `json:"client_shares"`
+ }
+ if err := json.Unmarshal(b, &keyShareClientHello); err != nil {
+ return err
+ }
+
+ for _, clientShare := range keyShareClientHello.ClientShares {
+ if clientShare.Group == "GREASE" {
+ e.KeyShares = append(e.KeyShares, KeyShare{
+ Group: GREASE_PLACEHOLDER,
+ Data: clientShare.KeyExchange,
+ })
+ continue
+ }
+
+ if groupID, ok := dicttls.DictSupportedGroupsNameIndexed[clientShare.Group]; ok {
+ ks := KeyShare{
+ Group: CurveID(groupID),
+ Data: clientShare.KeyExchange,
+ }
+ e.KeyShares = append(e.KeyShares, ks)
+ } else {
+ return fmt.Errorf("unknown group %s", clientShare.Group)
+ }
+ }
+ return nil
+}
+
+// QUICTransportParametersExtension implements quic_transport_parameters (57).
+//
+// Currently, it works as a fake extension and does not support parsing, since
+// the QUICConn provided by this package does not really understand these
+// parameters.
+type QUICTransportParametersExtension struct {
+ TransportParameters TransportParameters
+
+ marshalResult []byte // TransportParameters will be marshaled into this slice
+}
+
+func (e *QUICTransportParametersExtension) Len() int {
+ if e.marshalResult == nil {
+ e.marshalResult = e.TransportParameters.Marshal()
+ }
+ return 4 + len(e.marshalResult)
+}
+
+func (e *QUICTransportParametersExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ b[0] = byte(extensionQUICTransportParameters >> 8)
+ b[1] = byte(extensionQUICTransportParameters)
+ // e.Len() is called before so that e.marshalResult is set
+ b[2] = byte((len(e.marshalResult)) >> 8)
+ b[3] = byte(len(e.marshalResult))
+ copy(b[4:], e.marshalResult)
+
+ return e.Len(), io.EOF
+}
+
+func (e *QUICTransportParametersExtension) writeToUConn(*UConn) error {
+ // no need to set *UConn.quic.transportParams, since it is unused
+ return nil
+}
+
+// PSKKeyExchangeModesExtension implements psk_key_exchange_modes (45).
+type PSKKeyExchangeModesExtension struct {
+ Modes []uint8
+}
+
+func (e *PSKKeyExchangeModesExtension) Len() int {
+ return 4 + 1 + len(e.Modes)
+}
+
+func (e *PSKKeyExchangeModesExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ if len(e.Modes) > 255 {
+ return 0, errors.New("too many PSK Key Exchange modes")
+ }
+
+ b[0] = byte(extensionPSKModes >> 8)
+ b[1] = byte(extensionPSKModes)
+
+ modesLen := len(e.Modes)
+ b[2] = byte((modesLen + 1) >> 8)
+ b[3] = byte(modesLen + 1)
+ b[4] = byte(modesLen)
+
+ if len(e.Modes) > 0 {
+ copy(b[5:], e.Modes)
+ }
+
+ return e.Len(), io.EOF
+}
+
+func (e *PSKKeyExchangeModesExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 8446, Section 4.2.9
+ // TODO: PSK Modes have their own form of GREASE-ing which is not currently implemented
+ // the current functionality will NOT re-GREASE/re-randomize these values when using a fingerprinted spec
+ // https://github.com/refraction-networking/utls/pull/58#discussion_r522354105
+ // https://tools.ietf.org/html/draft-ietf-tls-grease-01#section-2
+ pskModes := []uint8{}
+ if !readUint8LengthPrefixed(&extData, &pskModes) {
+ return 0, errors.New("unable to read PSK extension data")
+ }
+ e.Modes = pskModes
+ return fullLen, nil
+}
+
+func (e *PSKKeyExchangeModesExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.PskModes = e.Modes
+ return nil
+}
+
+func (e *PSKKeyExchangeModesExtension) UnmarshalJSON(b []byte) error {
+ var pskKeyExchangeModes struct {
+ Modes []string `json:"ke_modes"`
+ }
+ if err := json.Unmarshal(b, &pskKeyExchangeModes); err != nil {
+ return err
+ }
+
+ for _, mode := range pskKeyExchangeModes.Modes {
+ if modeID, ok := dicttls.DictPSKKeyExchangeModeNameIndexed[mode]; ok {
+ e.Modes = append(e.Modes, modeID)
+ } else {
+ return fmt.Errorf("unknown PSK Key Exchange Mode %s", mode)
+ }
+ }
+ return nil
+}
+
+// SupportedVersionsExtension implements supported_versions (43).
+type SupportedVersionsExtension struct {
+ Versions []uint16
+}
+
+func (e *SupportedVersionsExtension) writeToUConn(uc *UConn) error {
+ uc.HandshakeState.Hello.SupportedVersions = e.Versions
+ return nil
+}
+
+func (e *SupportedVersionsExtension) Len() int {
+ return 4 + 1 + (2 * len(e.Versions))
+}
+
+func (e *SupportedVersionsExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ extLen := 2 * len(e.Versions)
+ if extLen > 255 {
+ return 0, errors.New("too many supported versions")
+ }
+
+ b[0] = byte(extensionSupportedVersions >> 8)
+ b[1] = byte(extensionSupportedVersions)
+ b[2] = byte((extLen + 1) >> 8)
+ b[3] = byte(extLen + 1)
+ b[4] = byte(extLen)
+
+ i := 5
+ for _, sv := range e.Versions {
+ b[i] = byte(sv >> 8)
+ b[i+1] = byte(sv)
+ i += 2
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *SupportedVersionsExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ // RFC 8446, Section 4.2.1
+ var versList cryptobyte.String
+ if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
+ return 0, errors.New("unable to read supported versions extension data")
+ }
+ supportedVersions := []uint16{}
+ for !versList.Empty() {
+ var vers uint16
+ if !versList.ReadUint16(&vers) {
+ return 0, errors.New("unable to read supported versions extension data")
+ }
+ supportedVersions = append(supportedVersions, unGREASEUint16(vers))
+ }
+ e.Versions = supportedVersions
+ return fullLen, nil
+}
+
+func (e *SupportedVersionsExtension) UnmarshalJSON(b []byte) error {
+ var supportedVersions struct {
+ Versions []string `json:"versions"`
+ }
+ if err := json.Unmarshal(b, &supportedVersions); err != nil {
+ return err
+ }
+
+ for _, version := range supportedVersions.Versions {
+ switch version {
+ case "GREASE":
+ e.Versions = append(e.Versions, GREASE_PLACEHOLDER)
+ case "TLS 1.3":
+ e.Versions = append(e.Versions, VersionTLS13)
+ case "TLS 1.2":
+ e.Versions = append(e.Versions, VersionTLS12)
+ case "TLS 1.1":
+ e.Versions = append(e.Versions, VersionTLS11)
+ case "TLS 1.0":
+ e.Versions = append(e.Versions, VersionTLS10)
+ case "SSL 3.0": // deprecated
+ // e.Versions = append(e.Versions, VersionSSL30)
+ return fmt.Errorf("SSL 3.0 is deprecated")
+ default:
+ return fmt.Errorf("unknown version %s", version)
+ }
+ }
+ return nil
+}
+
+// CookieExtension implements cookie (44).
+// MUST NOT be part of initial ClientHello
+type CookieExtension struct {
+ Cookie []byte
+}
+
+func (e *CookieExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *CookieExtension) Len() int {
+ // The total length of the Cookie extension is:
+ // 2 bytes for ExtensionType (extensionCookie)
+ // 2 bytes for OuterExtensionDataLength
+ // 2 bytes for InnerCookieLength (len(e.Cookie))
+ // N bytes for the Cookie data itself (e.Cookie)
+ // So, total = 6 + len(e.Cookie)
+ return 6 + len(e.Cookie)
+}
+
+func (e *CookieExtension) Read(b []byte) (int, error) {
+ cookieLen := len(e.Cookie)
+
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ // Extension type
+ b[0] = byte(extensionCookie >> 8)
+ b[1] = byte(extensionCookie)
+
+ // Copied from BoringSSL https://boringssl.googlesource.com/boringssl.git/%2B/chromium-stable/ssl/extensions.cc#2465
+ // Total extension_data length
+ extDataLen := 2 + cookieLen // 2 bytes for cookie length + cookie
+ b[2] = byte(extDataLen >> 8)
+ b[3] = byte(extDataLen)
+
+ // Cookie length
+ b[4] = byte(cookieLen >> 8)
+ b[5] = byte(cookieLen)
+
+ // Cookie value
+ copy(b[6:], e.Cookie)
+
+ return e.Len(), io.EOF
+}
+
+func (e *CookieExtension) UnmarshalJSON(data []byte) error {
+ var cookie struct {
+ Cookie []uint8 `json:"cookie"`
+ }
+ if err := json.Unmarshal(data, &cookie); err != nil {
+ return err
+ }
+ e.Cookie = []byte(cookie.Cookie)
+ return nil
+}
+
+// NPNExtension implements next_protocol_negotiation (Not IANA assigned)
+type NPNExtension struct {
+ NextProtos []string
+}
+
+func (e *NPNExtension) writeToUConn(uc *UConn) error {
+ uc.config.NextProtos = e.NextProtos
+ uc.HandshakeState.Hello.NextProtoNeg = true
+ return nil
+}
+
+func (e *NPNExtension) Len() int {
+ return 4
+}
+
+func (e *NPNExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ b[0] = byte(extensionNextProtoNeg >> 8)
+ b[1] = byte(extensionNextProtoNeg & 0xff)
+ // The length is always 0
+ return e.Len(), io.EOF
+}
+
+// Write is a no-op for NPNExtension. NextProtos are not included in the
+// ClientHello.
+func (e *NPNExtension) Write(_ []byte) (int, error) {
+ return 0, nil
+}
+
+// draft-agl-tls-nextprotoneg-04:
+// The "extension_data" field of a "next_protocol_negotiation" extension
+// in a "ClientHello" MUST be empty.
+func (e *NPNExtension) UnmarshalJSON(_ []byte) error {
+ return nil
+}
+
+// RenegotiationInfoExtension implements renegotiation_info (65281)
+type RenegotiationInfoExtension struct {
+ // Renegotiation field limits how many times client will perform renegotiation: no limit, once, or never.
+ // The extension still will be sent, even if Renegotiation is set to RenegotiateNever.
+ Renegotiation RenegotiationSupport // [UTLS] added for internal use only
+
+ // RenegotiatedConnection is not yet properly handled, now we
+ // are just copying it to the client hello.
+ //
+ // If this is the initial handshake for a connection, then the
+ // "renegotiated_connection" field is of zero length in both the
+ // ClientHello and the ServerHello.
+ RenegotiatedConnection []byte
+}
+
+func (e *RenegotiationInfoExtension) Len() int {
+ return 5 + len(e.RenegotiatedConnection)
+}
+
+func (e *RenegotiationInfoExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+
+ dataLen := len(e.RenegotiatedConnection)
+ extBodyLen := 1 + dataLen
+
+ b[0] = byte(extensionRenegotiationInfo >> 8)
+ b[1] = byte(extensionRenegotiationInfo & 0xff)
+ b[2] = byte(extBodyLen >> 8)
+ b[3] = byte(extBodyLen)
+ b[4] = byte(dataLen)
+ copy(b[5:], e.RenegotiatedConnection)
+
+ return e.Len(), io.EOF
+}
+
+func (e *RenegotiationInfoExtension) UnmarshalJSON(_ []byte) error {
+ e.Renegotiation = RenegotiateOnceAsClient
+ return nil
+}
+
+func (e *RenegotiationInfoExtension) Write(b []byte) (int, error) {
+ e.Renegotiation = RenegotiateOnceAsClient // none empty or other modes are unsupported
+ // extData := cryptobyte.String(b)
+ // var renegotiatedConnection cryptobyte.String
+ // if !extData.ReadUint8LengthPrefixed(&renegotiatedConnection) || !extData.Empty() {
+ // return 0, errors.New("unable to read renegotiation info extension data")
+ // }
+ // e.RenegotiatedConnection = make([]byte, len(renegotiatedConnection))
+ // copy(e.RenegotiatedConnection, renegotiatedConnection)
+
+ // we don't really want to parse it at all.
+
+ return len(b), nil
+}
+
+func (e *RenegotiationInfoExtension) writeToUConn(uc *UConn) error {
+ uc.config.Renegotiation = e.Renegotiation
+ switch e.Renegotiation {
+ case RenegotiateOnceAsClient:
+ fallthrough
+ case RenegotiateFreelyAsClient:
+ uc.HandshakeState.Hello.SecureRenegotiationSupported = true
+ // TODO: don't do backward propagation here
+ if uc.handshakes > 0 {
+ e.RenegotiatedConnection = uc.clientFinished[:]
+ }
+ case RenegotiateNever:
+ default:
+ }
+ return nil
+}
+
+/*
+FAKE EXTENSIONS
+*/
+
+type FakeChannelIDExtension struct {
+ // The extension ID changed from 30031 to 30032. Set to true to use the old extension ID.
+ OldExtensionID bool
+}
+
+func (e *FakeChannelIDExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *FakeChannelIDExtension) Len() int {
+ return 4
+}
+
+func (e *FakeChannelIDExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ extensionID := fakeExtensionChannelID
+ if e.OldExtensionID {
+ extensionID = fakeOldExtensionChannelID
+ }
+ // https://tools.ietf.org/html/draft-balfanz-tls-channelid-00
+ b[0] = byte(extensionID >> 8)
+ b[1] = byte(extensionID & 0xff)
+ // The length is 0
+ return e.Len(), io.EOF
+}
+
+func (e *FakeChannelIDExtension) Write(_ []byte) (int, error) {
+ return 0, nil
+}
+
+func (e *FakeChannelIDExtension) UnmarshalJSON(_ []byte) error {
+ return nil
+}
+
+// FakeRecordSizeLimitExtension implements record_size_limit (28)
+// but with no support.
+type FakeRecordSizeLimitExtension struct {
+ Limit uint16
+}
+
+func (e *FakeRecordSizeLimitExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *FakeRecordSizeLimitExtension) Len() int {
+ return 6
+}
+
+func (e *FakeRecordSizeLimitExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // https://tools.ietf.org/html/draft-balfanz-tls-channelid-00
+ b[0] = byte(fakeRecordSizeLimit >> 8)
+ b[1] = byte(fakeRecordSizeLimit & 0xff)
+
+ b[2] = byte(0)
+ b[3] = byte(2)
+
+ b[4] = byte(e.Limit >> 8)
+ b[5] = byte(e.Limit & 0xff)
+ return e.Len(), io.EOF
+}
+
+func (e *FakeRecordSizeLimitExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ if !extData.ReadUint16(&e.Limit) {
+ return 0, errors.New("unable to read record size limit extension data")
+ }
+ return fullLen, nil
+}
+
+func (e *FakeRecordSizeLimitExtension) UnmarshalJSON(data []byte) error {
+ var limitAccepter struct {
+ Limit uint16 `json:"record_size_limit"`
+ }
+ if err := json.Unmarshal(data, &limitAccepter); err != nil {
+ return err
+ }
+
+ e.Limit = limitAccepter.Limit
+ return nil
+}
+
+type DelegatedCredentialsExtension = FakeDelegatedCredentialsExtension
+
+// https://tools.ietf.org/html/rfc8472#section-2
+type FakeTokenBindingExtension struct {
+ MajorVersion, MinorVersion uint8
+ KeyParameters []uint8
+}
+
+func (e *FakeTokenBindingExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *FakeTokenBindingExtension) Len() int {
+ // extension ID + data length + versions + key parameters length + key parameters
+ return 2 + 2 + 2 + 1 + len(e.KeyParameters)
+}
+
+func (e *FakeTokenBindingExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ dataLen := e.Len() - 4
+ b[0] = byte(fakeExtensionTokenBinding >> 8)
+ b[1] = byte(fakeExtensionTokenBinding & 0xff)
+ b[2] = byte(dataLen >> 8)
+ b[3] = byte(dataLen & 0xff)
+ b[4] = e.MajorVersion
+ b[5] = e.MinorVersion
+ b[6] = byte(len(e.KeyParameters))
+ if len(e.KeyParameters) > 0 {
+ copy(b[7:], e.KeyParameters)
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *FakeTokenBindingExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ var keyParameters cryptobyte.String
+ if !extData.ReadUint8(&e.MajorVersion) ||
+ !extData.ReadUint8(&e.MinorVersion) ||
+ !extData.ReadUint8LengthPrefixed(&keyParameters) {
+ return 0, errors.New("unable to read token binding extension data")
+ }
+ e.KeyParameters = keyParameters
+ return fullLen, nil
+}
+
+func (e *FakeTokenBindingExtension) UnmarshalJSON(data []byte) error {
+ var tokenBindingAccepter struct {
+ TB_ProtocolVersion struct {
+ Major uint8 `json:"major"`
+ Minor uint8 `json:"minor"`
+ } `json:"token_binding_version"`
+ TokenBindingKeyParameters []string `json:"key_parameters_list"`
+ }
+ if err := json.Unmarshal(data, &tokenBindingAccepter); err != nil {
+ return err
+ }
+
+ e.MajorVersion = tokenBindingAccepter.TB_ProtocolVersion.Major
+ e.MinorVersion = tokenBindingAccepter.TB_ProtocolVersion.Minor
+ for _, param := range tokenBindingAccepter.TokenBindingKeyParameters {
+ switch param {
+ case "rsa2048_pkcs1.5":
+ e.KeyParameters = append(e.KeyParameters, 0)
+ case "rsa2048_pss":
+ e.KeyParameters = append(e.KeyParameters, 1)
+ case "ecdsap256":
+ e.KeyParameters = append(e.KeyParameters, 2)
+ default:
+ return fmt.Errorf("unknown token binding key parameter: %s", param)
+ }
+ }
+ return nil
+}
+
+// https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
+
+type FakeDelegatedCredentialsExtension struct {
+ SupportedSignatureAlgorithms []SignatureScheme
+}
+
+func (e *FakeDelegatedCredentialsExtension) writeToUConn(uc *UConn) error {
+ return nil
+}
+
+func (e *FakeDelegatedCredentialsExtension) Len() int {
+ return 6 + 2*len(e.SupportedSignatureAlgorithms)
+}
+
+func (e *FakeDelegatedCredentialsExtension) Read(b []byte) (int, error) {
+ if len(b) < e.Len() {
+ return 0, io.ErrShortBuffer
+ }
+ // https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
+ b[0] = byte(fakeExtensionDelegatedCredentials >> 8)
+ b[1] = byte(fakeExtensionDelegatedCredentials)
+ b[2] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)) >> 8)
+ b[3] = byte((2 + 2*len(e.SupportedSignatureAlgorithms)))
+ b[4] = byte((2 * len(e.SupportedSignatureAlgorithms)) >> 8)
+ b[5] = byte((2 * len(e.SupportedSignatureAlgorithms)))
+ for i, sigAndHash := range e.SupportedSignatureAlgorithms {
+ b[6+2*i] = byte(sigAndHash >> 8)
+ b[7+2*i] = byte(sigAndHash)
+ }
+ return e.Len(), io.EOF
+}
+
+func (e *FakeDelegatedCredentialsExtension) Write(b []byte) (int, error) {
+ fullLen := len(b)
+ extData := cryptobyte.String(b)
+ //https://datatracker.ietf.org/doc/html/draft-ietf-tls-subcerts-15#section-4.1.1
+ var supportedAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&supportedAlgs) || supportedAlgs.Empty() {
+ return 0, errors.New("unable to read signature algorithms extension data")
+ }
+ supportedSignatureAlgorithms := []SignatureScheme{}
+ for !supportedAlgs.Empty() {
+ var sigAndAlg uint16
+ if !supportedAlgs.ReadUint16(&sigAndAlg) {
+ return 0, errors.New("unable to read signature algorithms extension data")
+ }
+ supportedSignatureAlgorithms = append(
+ supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+ }
+ e.SupportedSignatureAlgorithms = supportedSignatureAlgorithms
+ return fullLen, nil
+}
+
+// Implementation copied from SignatureAlgorithmsExtension.UnmarshalJSON
+func (e *FakeDelegatedCredentialsExtension) UnmarshalJSON(data []byte) error {
+ var signatureAlgorithms struct {
+ Algorithms []string `json:"supported_signature_algorithms"`
+ }
+ if err := json.Unmarshal(data, &signatureAlgorithms); err != nil {
+ return err
+ }
+
+ for _, sigScheme := range signatureAlgorithms.Algorithms {
+ if sigScheme == "GREASE" {
+ e.SupportedSignatureAlgorithms = append(e.SupportedSignatureAlgorithms, GREASE_PLACEHOLDER)
+ continue
+ }
+
+ if scheme, ok := dicttls.DictSignatureSchemeNameIndexed[sigScheme]; ok {
+ e.SupportedSignatureAlgorithms = append(e.SupportedSignatureAlgorithms, SignatureScheme(scheme))
+ } else {
+ return fmt.Errorf("unknown delegated credentials signature scheme: %s", sigScheme)
+ }
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/LICENSE b/vendor/golang.org/x/crypto/LICENSE
new file mode 100644
index 00000000..2a7cf70d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/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/crypto/PATENTS b/vendor/golang.org/x/crypto/PATENTS
new file mode 100644
index 00000000..73309904
--- /dev/null
+++ b/vendor/golang.org/x/crypto/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/crypto/chacha20/chacha_arm64.go b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go
new file mode 100644
index 00000000..661ea132
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go
@@ -0,0 +1,16 @@
+// 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 && !purego
+
+package chacha20
+
+const bufSize = 256
+
+//go:noescape
+func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
+
+func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
+ xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
+}
diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s
new file mode 100644
index 00000000..769af387
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s
@@ -0,0 +1,307 @@
+// 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 && !purego
+
+#include "textflag.h"
+
+#define NUM_ROUNDS 10
+
+// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
+TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
+ MOVD dst+0(FP), R1
+ MOVD src+24(FP), R2
+ MOVD src_len+32(FP), R3
+ MOVD key+48(FP), R4
+ MOVD nonce+56(FP), R6
+ MOVD counter+64(FP), R7
+
+ MOVD $·constants(SB), R10
+ MOVD $·incRotMatrix(SB), R11
+
+ MOVW (R7), R20
+
+ AND $~255, R3, R13
+ ADD R2, R13, R12 // R12 for block end
+ AND $255, R3, R13
+loop:
+ MOVD $NUM_ROUNDS, R21
+ VLD1 (R11), [V30.S4, V31.S4]
+
+ // load constants
+ // VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4]
+ WORD $0x4D60E940
+
+ // load keys
+ // VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4]
+ WORD $0x4DFFE884
+ // VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4]
+ WORD $0x4DFFE888
+ SUB $32, R4
+
+ // load counter + nonce
+ // VLD1R (R7), [V12.S4]
+ WORD $0x4D40C8EC
+
+ // VLD3R (R6), [V13.S4, V14.S4, V15.S4]
+ WORD $0x4D40E8CD
+
+ // update counter
+ VADD V30.S4, V12.S4, V12.S4
+
+chacha:
+ // V0..V3 += V4..V7
+ // V12..V15 <<<= ((V12..V15 XOR V0..V3), 16)
+ VADD V0.S4, V4.S4, V0.S4
+ VADD V1.S4, V5.S4, V1.S4
+ VADD V2.S4, V6.S4, V2.S4
+ VADD V3.S4, V7.S4, V3.S4
+ VEOR V12.B16, V0.B16, V12.B16
+ VEOR V13.B16, V1.B16, V13.B16
+ VEOR V14.B16, V2.B16, V14.B16
+ VEOR V15.B16, V3.B16, V15.B16
+ VREV32 V12.H8, V12.H8
+ VREV32 V13.H8, V13.H8
+ VREV32 V14.H8, V14.H8
+ VREV32 V15.H8, V15.H8
+ // V8..V11 += V12..V15
+ // V4..V7 <<<= ((V4..V7 XOR V8..V11), 12)
+ VADD V8.S4, V12.S4, V8.S4
+ VADD V9.S4, V13.S4, V9.S4
+ VADD V10.S4, V14.S4, V10.S4
+ VADD V11.S4, V15.S4, V11.S4
+ VEOR V8.B16, V4.B16, V16.B16
+ VEOR V9.B16, V5.B16, V17.B16
+ VEOR V10.B16, V6.B16, V18.B16
+ VEOR V11.B16, V7.B16, V19.B16
+ VSHL $12, V16.S4, V4.S4
+ VSHL $12, V17.S4, V5.S4
+ VSHL $12, V18.S4, V6.S4
+ VSHL $12, V19.S4, V7.S4
+ VSRI $20, V16.S4, V4.S4
+ VSRI $20, V17.S4, V5.S4
+ VSRI $20, V18.S4, V6.S4
+ VSRI $20, V19.S4, V7.S4
+
+ // V0..V3 += V4..V7
+ // V12..V15 <<<= ((V12..V15 XOR V0..V3), 8)
+ VADD V0.S4, V4.S4, V0.S4
+ VADD V1.S4, V5.S4, V1.S4
+ VADD V2.S4, V6.S4, V2.S4
+ VADD V3.S4, V7.S4, V3.S4
+ VEOR V12.B16, V0.B16, V12.B16
+ VEOR V13.B16, V1.B16, V13.B16
+ VEOR V14.B16, V2.B16, V14.B16
+ VEOR V15.B16, V3.B16, V15.B16
+ VTBL V31.B16, [V12.B16], V12.B16
+ VTBL V31.B16, [V13.B16], V13.B16
+ VTBL V31.B16, [V14.B16], V14.B16
+ VTBL V31.B16, [V15.B16], V15.B16
+
+ // V8..V11 += V12..V15
+ // V4..V7 <<<= ((V4..V7 XOR V8..V11), 7)
+ VADD V12.S4, V8.S4, V8.S4
+ VADD V13.S4, V9.S4, V9.S4
+ VADD V14.S4, V10.S4, V10.S4
+ VADD V15.S4, V11.S4, V11.S4
+ VEOR V8.B16, V4.B16, V16.B16
+ VEOR V9.B16, V5.B16, V17.B16
+ VEOR V10.B16, V6.B16, V18.B16
+ VEOR V11.B16, V7.B16, V19.B16
+ VSHL $7, V16.S4, V4.S4
+ VSHL $7, V17.S4, V5.S4
+ VSHL $7, V18.S4, V6.S4
+ VSHL $7, V19.S4, V7.S4
+ VSRI $25, V16.S4, V4.S4
+ VSRI $25, V17.S4, V5.S4
+ VSRI $25, V18.S4, V6.S4
+ VSRI $25, V19.S4, V7.S4
+
+ // V0..V3 += V5..V7, V4
+ // V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16)
+ VADD V0.S4, V5.S4, V0.S4
+ VADD V1.S4, V6.S4, V1.S4
+ VADD V2.S4, V7.S4, V2.S4
+ VADD V3.S4, V4.S4, V3.S4
+ VEOR V15.B16, V0.B16, V15.B16
+ VEOR V12.B16, V1.B16, V12.B16
+ VEOR V13.B16, V2.B16, V13.B16
+ VEOR V14.B16, V3.B16, V14.B16
+ VREV32 V12.H8, V12.H8
+ VREV32 V13.H8, V13.H8
+ VREV32 V14.H8, V14.H8
+ VREV32 V15.H8, V15.H8
+
+ // V10 += V15; V5 <<<= ((V10 XOR V5), 12)
+ // ...
+ VADD V15.S4, V10.S4, V10.S4
+ VADD V12.S4, V11.S4, V11.S4
+ VADD V13.S4, V8.S4, V8.S4
+ VADD V14.S4, V9.S4, V9.S4
+ VEOR V10.B16, V5.B16, V16.B16
+ VEOR V11.B16, V6.B16, V17.B16
+ VEOR V8.B16, V7.B16, V18.B16
+ VEOR V9.B16, V4.B16, V19.B16
+ VSHL $12, V16.S4, V5.S4
+ VSHL $12, V17.S4, V6.S4
+ VSHL $12, V18.S4, V7.S4
+ VSHL $12, V19.S4, V4.S4
+ VSRI $20, V16.S4, V5.S4
+ VSRI $20, V17.S4, V6.S4
+ VSRI $20, V18.S4, V7.S4
+ VSRI $20, V19.S4, V4.S4
+
+ // V0 += V5; V15 <<<= ((V0 XOR V15), 8)
+ // ...
+ VADD V5.S4, V0.S4, V0.S4
+ VADD V6.S4, V1.S4, V1.S4
+ VADD V7.S4, V2.S4, V2.S4
+ VADD V4.S4, V3.S4, V3.S4
+ VEOR V0.B16, V15.B16, V15.B16
+ VEOR V1.B16, V12.B16, V12.B16
+ VEOR V2.B16, V13.B16, V13.B16
+ VEOR V3.B16, V14.B16, V14.B16
+ VTBL V31.B16, [V12.B16], V12.B16
+ VTBL V31.B16, [V13.B16], V13.B16
+ VTBL V31.B16, [V14.B16], V14.B16
+ VTBL V31.B16, [V15.B16], V15.B16
+
+ // V10 += V15; V5 <<<= ((V10 XOR V5), 7)
+ // ...
+ VADD V15.S4, V10.S4, V10.S4
+ VADD V12.S4, V11.S4, V11.S4
+ VADD V13.S4, V8.S4, V8.S4
+ VADD V14.S4, V9.S4, V9.S4
+ VEOR V10.B16, V5.B16, V16.B16
+ VEOR V11.B16, V6.B16, V17.B16
+ VEOR V8.B16, V7.B16, V18.B16
+ VEOR V9.B16, V4.B16, V19.B16
+ VSHL $7, V16.S4, V5.S4
+ VSHL $7, V17.S4, V6.S4
+ VSHL $7, V18.S4, V7.S4
+ VSHL $7, V19.S4, V4.S4
+ VSRI $25, V16.S4, V5.S4
+ VSRI $25, V17.S4, V6.S4
+ VSRI $25, V18.S4, V7.S4
+ VSRI $25, V19.S4, V4.S4
+
+ SUB $1, R21
+ CBNZ R21, chacha
+
+ // VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4]
+ WORD $0x4D60E950
+
+ // VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4]
+ WORD $0x4DFFE894
+ VADD V30.S4, V12.S4, V12.S4
+ VADD V16.S4, V0.S4, V0.S4
+ VADD V17.S4, V1.S4, V1.S4
+ VADD V18.S4, V2.S4, V2.S4
+ VADD V19.S4, V3.S4, V3.S4
+ // VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4]
+ WORD $0x4DFFE898
+ // restore R4
+ SUB $32, R4
+
+ // load counter + nonce
+ // VLD1R (R7), [V28.S4]
+ WORD $0x4D40C8FC
+ // VLD3R (R6), [V29.S4, V30.S4, V31.S4]
+ WORD $0x4D40E8DD
+
+ VADD V20.S4, V4.S4, V4.S4
+ VADD V21.S4, V5.S4, V5.S4
+ VADD V22.S4, V6.S4, V6.S4
+ VADD V23.S4, V7.S4, V7.S4
+ VADD V24.S4, V8.S4, V8.S4
+ VADD V25.S4, V9.S4, V9.S4
+ VADD V26.S4, V10.S4, V10.S4
+ VADD V27.S4, V11.S4, V11.S4
+ VADD V28.S4, V12.S4, V12.S4
+ VADD V29.S4, V13.S4, V13.S4
+ VADD V30.S4, V14.S4, V14.S4
+ VADD V31.S4, V15.S4, V15.S4
+
+ VZIP1 V1.S4, V0.S4, V16.S4
+ VZIP2 V1.S4, V0.S4, V17.S4
+ VZIP1 V3.S4, V2.S4, V18.S4
+ VZIP2 V3.S4, V2.S4, V19.S4
+ VZIP1 V5.S4, V4.S4, V20.S4
+ VZIP2 V5.S4, V4.S4, V21.S4
+ VZIP1 V7.S4, V6.S4, V22.S4
+ VZIP2 V7.S4, V6.S4, V23.S4
+ VZIP1 V9.S4, V8.S4, V24.S4
+ VZIP2 V9.S4, V8.S4, V25.S4
+ VZIP1 V11.S4, V10.S4, V26.S4
+ VZIP2 V11.S4, V10.S4, V27.S4
+ VZIP1 V13.S4, V12.S4, V28.S4
+ VZIP2 V13.S4, V12.S4, V29.S4
+ VZIP1 V15.S4, V14.S4, V30.S4
+ VZIP2 V15.S4, V14.S4, V31.S4
+ VZIP1 V18.D2, V16.D2, V0.D2
+ VZIP2 V18.D2, V16.D2, V4.D2
+ VZIP1 V19.D2, V17.D2, V8.D2
+ VZIP2 V19.D2, V17.D2, V12.D2
+ VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16]
+
+ VZIP1 V22.D2, V20.D2, V1.D2
+ VZIP2 V22.D2, V20.D2, V5.D2
+ VZIP1 V23.D2, V21.D2, V9.D2
+ VZIP2 V23.D2, V21.D2, V13.D2
+ VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16]
+ VZIP1 V26.D2, V24.D2, V2.D2
+ VZIP2 V26.D2, V24.D2, V6.D2
+ VZIP1 V27.D2, V25.D2, V10.D2
+ VZIP2 V27.D2, V25.D2, V14.D2
+ VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16]
+ VZIP1 V30.D2, V28.D2, V3.D2
+ VZIP2 V30.D2, V28.D2, V7.D2
+ VZIP1 V31.D2, V29.D2, V11.D2
+ VZIP2 V31.D2, V29.D2, V15.D2
+ VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16]
+ VEOR V0.B16, V16.B16, V16.B16
+ VEOR V1.B16, V17.B16, V17.B16
+ VEOR V2.B16, V18.B16, V18.B16
+ VEOR V3.B16, V19.B16, V19.B16
+ VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1)
+ VEOR V4.B16, V20.B16, V20.B16
+ VEOR V5.B16, V21.B16, V21.B16
+ VEOR V6.B16, V22.B16, V22.B16
+ VEOR V7.B16, V23.B16, V23.B16
+ VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1)
+ VEOR V8.B16, V24.B16, V24.B16
+ VEOR V9.B16, V25.B16, V25.B16
+ VEOR V10.B16, V26.B16, V26.B16
+ VEOR V11.B16, V27.B16, V27.B16
+ VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1)
+ VEOR V12.B16, V28.B16, V28.B16
+ VEOR V13.B16, V29.B16, V29.B16
+ VEOR V14.B16, V30.B16, V30.B16
+ VEOR V15.B16, V31.B16, V31.B16
+ VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1)
+
+ ADD $4, R20
+ MOVW R20, (R7) // update counter
+
+ CMP R2, R12
+ BGT loop
+
+ RET
+
+
+DATA ·constants+0x00(SB)/4, $0x61707865
+DATA ·constants+0x04(SB)/4, $0x3320646e
+DATA ·constants+0x08(SB)/4, $0x79622d32
+DATA ·constants+0x0c(SB)/4, $0x6b206574
+GLOBL ·constants(SB), NOPTR|RODATA, $32
+
+DATA ·incRotMatrix+0x00(SB)/4, $0x00000000
+DATA ·incRotMatrix+0x04(SB)/4, $0x00000001
+DATA ·incRotMatrix+0x08(SB)/4, $0x00000002
+DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003
+DATA ·incRotMatrix+0x10(SB)/4, $0x02010003
+DATA ·incRotMatrix+0x14(SB)/4, $0x06050407
+DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B
+DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F
+GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32
diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/chacha20/chacha_generic.go
new file mode 100644
index 00000000..93eb5ae6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_generic.go
@@ -0,0 +1,398 @@
+// 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 chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms
+// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
+package chacha20
+
+import (
+ "crypto/cipher"
+ "encoding/binary"
+ "errors"
+ "math/bits"
+
+ "golang.org/x/crypto/internal/alias"
+)
+
+const (
+ // KeySize is the size of the key used by this cipher, in bytes.
+ KeySize = 32
+
+ // NonceSize is the size of the nonce used with the standard variant of this
+ // cipher, in bytes.
+ //
+ // Note that this is too short to be safely generated at random if the same
+ // key is reused more than 2³² times.
+ NonceSize = 12
+
+ // NonceSizeX is the size of the nonce used with the XChaCha20 variant of
+ // this cipher, in bytes.
+ NonceSizeX = 24
+)
+
+// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
+// and nonce. A *Cipher implements the cipher.Stream interface.
+type Cipher struct {
+ // The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
+ // (incremented after each block), and 3 of nonce.
+ key [8]uint32
+ counter uint32
+ nonce [3]uint32
+
+ // The last len bytes of buf are leftover key stream bytes from the previous
+ // XORKeyStream invocation. The size of buf depends on how many blocks are
+ // computed at a time by xorKeyStreamBlocks.
+ buf [bufSize]byte
+ len int
+
+ // overflow is set when the counter overflowed, no more blocks can be
+ // generated, and the next XORKeyStream call should panic.
+ overflow bool
+
+ // The counter-independent results of the first round are cached after they
+ // are computed the first time.
+ precompDone bool
+ p1, p5, p9, p13 uint32
+ p2, p6, p10, p14 uint32
+ p3, p7, p11, p15 uint32
+}
+
+var _ cipher.Stream = (*Cipher)(nil)
+
+// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
+// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
+// the XChaCha20 construction will be used. It returns an error if key or nonce
+// have any other length.
+//
+// Note that ChaCha20, like all stream ciphers, is not authenticated and allows
+// attackers to silently tamper with the plaintext. For this reason, it is more
+// appropriate as a building block than as a standalone encryption mechanism.
+// Instead, consider using package golang.org/x/crypto/chacha20poly1305.
+func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
+ // This function is split into a wrapper so that the Cipher allocation will
+ // be inlined, and depending on how the caller uses the return value, won't
+ // escape to the heap.
+ c := &Cipher{}
+ return newUnauthenticatedCipher(c, key, nonce)
+}
+
+func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
+ if len(key) != KeySize {
+ return nil, errors.New("chacha20: wrong key size")
+ }
+ if len(nonce) == NonceSizeX {
+ // XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
+ // derived key, allowing it to operate on a nonce of 24 bytes. See
+ // draft-irtf-cfrg-xchacha-01, Section 2.3.
+ key, _ = HChaCha20(key, nonce[0:16])
+ cNonce := make([]byte, NonceSize)
+ copy(cNonce[4:12], nonce[16:24])
+ nonce = cNonce
+ } else if len(nonce) != NonceSize {
+ return nil, errors.New("chacha20: wrong nonce size")
+ }
+
+ key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint
+ c.key = [8]uint32{
+ binary.LittleEndian.Uint32(key[0:4]),
+ binary.LittleEndian.Uint32(key[4:8]),
+ binary.LittleEndian.Uint32(key[8:12]),
+ binary.LittleEndian.Uint32(key[12:16]),
+ binary.LittleEndian.Uint32(key[16:20]),
+ binary.LittleEndian.Uint32(key[20:24]),
+ binary.LittleEndian.Uint32(key[24:28]),
+ binary.LittleEndian.Uint32(key[28:32]),
+ }
+ c.nonce = [3]uint32{
+ binary.LittleEndian.Uint32(nonce[0:4]),
+ binary.LittleEndian.Uint32(nonce[4:8]),
+ binary.LittleEndian.Uint32(nonce[8:12]),
+ }
+ return c, nil
+}
+
+// The constant first 4 words of the ChaCha20 state.
+const (
+ j0 uint32 = 0x61707865 // expa
+ j1 uint32 = 0x3320646e // nd 3
+ j2 uint32 = 0x79622d32 // 2-by
+ j3 uint32 = 0x6b206574 // te k
+)
+
+const blockSize = 64
+
+// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
+// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
+// words each round, in columnar or diagonal groups of 4 at a time.
+func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
+ a += b
+ d ^= a
+ d = bits.RotateLeft32(d, 16)
+ c += d
+ b ^= c
+ b = bits.RotateLeft32(b, 12)
+ a += b
+ d ^= a
+ d = bits.RotateLeft32(d, 8)
+ c += d
+ b ^= c
+ b = bits.RotateLeft32(b, 7)
+ return a, b, c, d
+}
+
+// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
+// behave as if (64 * counter) bytes had been encrypted so far.
+//
+// To prevent accidental counter reuse, SetCounter panics if counter is less
+// than the current value.
+//
+// Note that the execution time of XORKeyStream is not independent of the
+// counter value.
+func (s *Cipher) SetCounter(counter uint32) {
+ // Internally, s may buffer multiple blocks, which complicates this
+ // implementation slightly. When checking whether the counter has rolled
+ // back, we must use both s.counter and s.len to determine how many blocks
+ // we have already output.
+ outputCounter := s.counter - uint32(s.len)/blockSize
+ if s.overflow || counter < outputCounter {
+ panic("chacha20: SetCounter attempted to rollback counter")
+ }
+
+ // In the general case, we set the new counter value and reset s.len to 0,
+ // causing the next call to XORKeyStream to refill the buffer. However, if
+ // we're advancing within the existing buffer, we can save work by simply
+ // setting s.len.
+ if counter < s.counter {
+ s.len = int(s.counter-counter) * blockSize
+ } else {
+ s.counter = counter
+ s.len = 0
+ }
+}
+
+// XORKeyStream XORs each byte in the given slice with a byte from the
+// cipher's key stream. Dst and src must overlap entirely or not at all.
+//
+// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
+// to pass a dst bigger than src, and in that case, XORKeyStream will
+// only update dst[:len(src)] and will not touch the rest of dst.
+//
+// Multiple calls to XORKeyStream behave as if the concatenation of
+// the src buffers was passed in a single run. That is, Cipher
+// maintains state and does not reset at each XORKeyStream call.
+func (s *Cipher) XORKeyStream(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+ if len(dst) < len(src) {
+ panic("chacha20: output smaller than input")
+ }
+ dst = dst[:len(src)]
+ if alias.InexactOverlap(dst, src) {
+ panic("chacha20: invalid buffer overlap")
+ }
+
+ // First, drain any remaining key stream from a previous XORKeyStream.
+ if s.len != 0 {
+ keyStream := s.buf[bufSize-s.len:]
+ if len(src) < len(keyStream) {
+ keyStream = keyStream[:len(src)]
+ }
+ _ = src[len(keyStream)-1] // bounds check elimination hint
+ for i, b := range keyStream {
+ dst[i] = src[i] ^ b
+ }
+ s.len -= len(keyStream)
+ dst, src = dst[len(keyStream):], src[len(keyStream):]
+ }
+ if len(src) == 0 {
+ return
+ }
+
+ // If we'd need to let the counter overflow and keep generating output,
+ // panic immediately. If instead we'd only reach the last block, remember
+ // not to generate any more output after the buffer is drained.
+ numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize
+ if s.overflow || uint64(s.counter)+numBlocks > 1<<32 {
+ panic("chacha20: counter overflow")
+ } else if uint64(s.counter)+numBlocks == 1<<32 {
+ s.overflow = true
+ }
+
+ // xorKeyStreamBlocks implementations expect input lengths that are a
+ // multiple of bufSize. Platform-specific ones process multiple blocks at a
+ // time, so have bufSizes that are a multiple of blockSize.
+
+ full := len(src) - len(src)%bufSize
+ if full > 0 {
+ s.xorKeyStreamBlocks(dst[:full], src[:full])
+ }
+ dst, src = dst[full:], src[full:]
+
+ // If using a multi-block xorKeyStreamBlocks would overflow, use the generic
+ // one that does one block at a time.
+ const blocksPerBuf = bufSize / blockSize
+ if uint64(s.counter)+blocksPerBuf > 1<<32 {
+ s.buf = [bufSize]byte{}
+ numBlocks := (len(src) + blockSize - 1) / blockSize
+ buf := s.buf[bufSize-numBlocks*blockSize:]
+ copy(buf, src)
+ s.xorKeyStreamBlocksGeneric(buf, buf)
+ s.len = len(buf) - copy(dst, buf)
+ return
+ }
+
+ // If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
+ // keep the leftover keystream for the next XORKeyStream invocation.
+ if len(src) > 0 {
+ s.buf = [bufSize]byte{}
+ copy(s.buf[:], src)
+ s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
+ s.len = bufSize - copy(dst, s.buf[:])
+ }
+}
+
+func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
+ if len(dst) != len(src) || len(dst)%blockSize != 0 {
+ panic("chacha20: internal error: wrong dst and/or src length")
+ }
+
+ // To generate each block of key stream, the initial cipher state
+ // (represented below) is passed through 20 rounds of shuffling,
+ // alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
+ // or by diagonals (like 1, 6, 11, 12).
+ //
+ // 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc
+ // 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk
+ // 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk
+ // 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn
+ //
+ // c=constant k=key b=blockcount n=nonce
+ var (
+ c0, c1, c2, c3 = j0, j1, j2, j3
+ c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3]
+ c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7]
+ _, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2]
+ )
+
+ // Three quarters of the first round don't depend on the counter, so we can
+ // calculate them here, and reuse them for multiple blocks in the loop, and
+ // for future XORKeyStream invocations.
+ if !s.precompDone {
+ s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13)
+ s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14)
+ s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15)
+ s.precompDone = true
+ }
+
+ // A condition of len(src) > 0 would be sufficient, but this also
+ // acts as a bounds check elimination hint.
+ for len(src) >= 64 && len(dst) >= 64 {
+ // The remainder of the first column round.
+ fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)
+
+ // The second diagonal round.
+ x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15)
+ x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12)
+ x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13)
+ x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14)
+
+ // The remaining 18 rounds.
+ for i := 0; i < 9; i++ {
+ // Column round.
+ x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
+ x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
+ x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
+ x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
+
+ // Diagonal round.
+ x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
+ x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
+ x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
+ x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
+ }
+
+ // Add back the initial state to generate the key stream, then
+ // XOR the key stream with the source and write out the result.
+ addXor(dst[0:4], src[0:4], x0, c0)
+ addXor(dst[4:8], src[4:8], x1, c1)
+ addXor(dst[8:12], src[8:12], x2, c2)
+ addXor(dst[12:16], src[12:16], x3, c3)
+ addXor(dst[16:20], src[16:20], x4, c4)
+ addXor(dst[20:24], src[20:24], x5, c5)
+ addXor(dst[24:28], src[24:28], x6, c6)
+ addXor(dst[28:32], src[28:32], x7, c7)
+ addXor(dst[32:36], src[32:36], x8, c8)
+ addXor(dst[36:40], src[36:40], x9, c9)
+ addXor(dst[40:44], src[40:44], x10, c10)
+ addXor(dst[44:48], src[44:48], x11, c11)
+ addXor(dst[48:52], src[48:52], x12, s.counter)
+ addXor(dst[52:56], src[52:56], x13, c13)
+ addXor(dst[56:60], src[56:60], x14, c14)
+ addXor(dst[60:64], src[60:64], x15, c15)
+
+ s.counter += 1
+
+ src, dst = src[blockSize:], dst[blockSize:]
+ }
+}
+
+// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
+// key and a 16 bytes nonce. It returns an error if key or nonce have any other
+// length. It is used as part of the XChaCha20 construction.
+func HChaCha20(key, nonce []byte) ([]byte, error) {
+ // This function is split into a wrapper so that the slice allocation will
+ // be inlined, and depending on how the caller uses the return value, won't
+ // escape to the heap.
+ out := make([]byte, 32)
+ return hChaCha20(out, key, nonce)
+}
+
+func hChaCha20(out, key, nonce []byte) ([]byte, error) {
+ if len(key) != KeySize {
+ return nil, errors.New("chacha20: wrong HChaCha20 key size")
+ }
+ if len(nonce) != 16 {
+ return nil, errors.New("chacha20: wrong HChaCha20 nonce size")
+ }
+
+ x0, x1, x2, x3 := j0, j1, j2, j3
+ x4 := binary.LittleEndian.Uint32(key[0:4])
+ x5 := binary.LittleEndian.Uint32(key[4:8])
+ x6 := binary.LittleEndian.Uint32(key[8:12])
+ x7 := binary.LittleEndian.Uint32(key[12:16])
+ x8 := binary.LittleEndian.Uint32(key[16:20])
+ x9 := binary.LittleEndian.Uint32(key[20:24])
+ x10 := binary.LittleEndian.Uint32(key[24:28])
+ x11 := binary.LittleEndian.Uint32(key[28:32])
+ x12 := binary.LittleEndian.Uint32(nonce[0:4])
+ x13 := binary.LittleEndian.Uint32(nonce[4:8])
+ x14 := binary.LittleEndian.Uint32(nonce[8:12])
+ x15 := binary.LittleEndian.Uint32(nonce[12:16])
+
+ for i := 0; i < 10; i++ {
+ // Diagonal round.
+ x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
+ x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
+ x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
+ x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
+
+ // Column round.
+ x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
+ x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
+ x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
+ x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
+ }
+
+ _ = out[31] // bounds check elimination hint
+ binary.LittleEndian.PutUint32(out[0:4], x0)
+ binary.LittleEndian.PutUint32(out[4:8], x1)
+ binary.LittleEndian.PutUint32(out[8:12], x2)
+ binary.LittleEndian.PutUint32(out[12:16], x3)
+ binary.LittleEndian.PutUint32(out[16:20], x12)
+ binary.LittleEndian.PutUint32(out[20:24], x13)
+ binary.LittleEndian.PutUint32(out[24:28], x14)
+ binary.LittleEndian.PutUint32(out[28:32], x15)
+ return out, nil
+}
diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go
new file mode 100644
index 00000000..c709b728
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.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 (!arm64 && !s390x && !ppc64 && !ppc64le) || !gc || purego
+
+package chacha20
+
+const bufSize = blockSize
+
+func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {
+ s.xorKeyStreamBlocksGeneric(dst, src)
+}
diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.go b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.go
new file mode 100644
index 00000000..bd183d9b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.go
@@ -0,0 +1,16 @@
+// 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 && !purego && (ppc64 || ppc64le)
+
+package chacha20
+
+const bufSize = 256
+
+//go:noescape
+func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
+
+func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
+ chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
+}
diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.s b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.s
new file mode 100644
index 00000000..a660b411
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64x.s
@@ -0,0 +1,501 @@
+// 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.
+
+// Based on CRYPTOGAMS code with the following comment:
+// # ====================================================================
+// # Written by Andy Polyakov for the OpenSSL
+// # project. The module is, however, dual licensed under OpenSSL and
+// # CRYPTOGAMS licenses depending on where you obtain it. For further
+// # details see http://www.openssl.org/~appro/cryptogams/.
+// # ====================================================================
+
+// Code for the perl script that generates the ppc64 assembler
+// can be found in the cryptogams repository at the link below. It is based on
+// the original from openssl.
+
+// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91
+
+// The differences in this and the original implementation are
+// due to the calling conventions and initialization of constants.
+
+//go:build gc && !purego && (ppc64 || ppc64le)
+
+#include "textflag.h"
+
+#define OUT R3
+#define INP R4
+#define LEN R5
+#define KEY R6
+#define CNT R7
+#define TMP R15
+
+#define CONSTBASE R16
+#define BLOCKS R17
+
+// for VPERMXOR
+#define MASK R18
+
+DATA consts<>+0x00(SB)/4, $0x61707865
+DATA consts<>+0x04(SB)/4, $0x3320646e
+DATA consts<>+0x08(SB)/4, $0x79622d32
+DATA consts<>+0x0c(SB)/4, $0x6b206574
+DATA consts<>+0x10(SB)/4, $0x00000001
+DATA consts<>+0x14(SB)/4, $0x00000000
+DATA consts<>+0x18(SB)/4, $0x00000000
+DATA consts<>+0x1c(SB)/4, $0x00000000
+DATA consts<>+0x20(SB)/4, $0x00000004
+DATA consts<>+0x24(SB)/4, $0x00000000
+DATA consts<>+0x28(SB)/4, $0x00000000
+DATA consts<>+0x2c(SB)/4, $0x00000000
+DATA consts<>+0x30(SB)/4, $0x0e0f0c0d
+DATA consts<>+0x34(SB)/4, $0x0a0b0809
+DATA consts<>+0x38(SB)/4, $0x06070405
+DATA consts<>+0x3c(SB)/4, $0x02030001
+DATA consts<>+0x40(SB)/4, $0x0d0e0f0c
+DATA consts<>+0x44(SB)/4, $0x090a0b08
+DATA consts<>+0x48(SB)/4, $0x05060704
+DATA consts<>+0x4c(SB)/4, $0x01020300
+DATA consts<>+0x50(SB)/4, $0x61707865
+DATA consts<>+0x54(SB)/4, $0x61707865
+DATA consts<>+0x58(SB)/4, $0x61707865
+DATA consts<>+0x5c(SB)/4, $0x61707865
+DATA consts<>+0x60(SB)/4, $0x3320646e
+DATA consts<>+0x64(SB)/4, $0x3320646e
+DATA consts<>+0x68(SB)/4, $0x3320646e
+DATA consts<>+0x6c(SB)/4, $0x3320646e
+DATA consts<>+0x70(SB)/4, $0x79622d32
+DATA consts<>+0x74(SB)/4, $0x79622d32
+DATA consts<>+0x78(SB)/4, $0x79622d32
+DATA consts<>+0x7c(SB)/4, $0x79622d32
+DATA consts<>+0x80(SB)/4, $0x6b206574
+DATA consts<>+0x84(SB)/4, $0x6b206574
+DATA consts<>+0x88(SB)/4, $0x6b206574
+DATA consts<>+0x8c(SB)/4, $0x6b206574
+DATA consts<>+0x90(SB)/4, $0x00000000
+DATA consts<>+0x94(SB)/4, $0x00000001
+DATA consts<>+0x98(SB)/4, $0x00000002
+DATA consts<>+0x9c(SB)/4, $0x00000003
+DATA consts<>+0xa0(SB)/4, $0x11223300
+DATA consts<>+0xa4(SB)/4, $0x55667744
+DATA consts<>+0xa8(SB)/4, $0x99aabb88
+DATA consts<>+0xac(SB)/4, $0xddeeffcc
+DATA consts<>+0xb0(SB)/4, $0x22330011
+DATA consts<>+0xb4(SB)/4, $0x66774455
+DATA consts<>+0xb8(SB)/4, $0xaabb8899
+DATA consts<>+0xbc(SB)/4, $0xeeffccdd
+GLOBL consts<>(SB), RODATA, $0xc0
+
+#ifdef GOARCH_ppc64
+#define BE_XXBRW_INIT() \
+ LVSL (R0)(R0), V24 \
+ VSPLTISB $3, V25 \
+ VXOR V24, V25, V24 \
+
+#define BE_XXBRW(vr) VPERM vr, vr, V24, vr
+#else
+#define BE_XXBRW_INIT()
+#define BE_XXBRW(vr)
+#endif
+
+//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
+TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
+ MOVD out+0(FP), OUT
+ MOVD inp+8(FP), INP
+ MOVD len+16(FP), LEN
+ MOVD key+24(FP), KEY
+ MOVD counter+32(FP), CNT
+
+ // Addressing for constants
+ MOVD $consts<>+0x00(SB), CONSTBASE
+ MOVD $16, R8
+ MOVD $32, R9
+ MOVD $48, R10
+ MOVD $64, R11
+ SRD $6, LEN, BLOCKS
+ // for VPERMXOR
+ MOVD $consts<>+0xa0(SB), MASK
+ MOVD $16, R20
+ // V16
+ LXVW4X (CONSTBASE)(R0), VS48
+ ADD $80,CONSTBASE
+
+ // Load key into V17,V18
+ LXVW4X (KEY)(R0), VS49
+ LXVW4X (KEY)(R8), VS50
+
+ // Load CNT, NONCE into V19
+ LXVW4X (CNT)(R0), VS51
+
+ // Clear V27
+ VXOR V27, V27, V27
+
+ BE_XXBRW_INIT()
+
+ // V28
+ LXVW4X (CONSTBASE)(R11), VS60
+
+ // Load mask constants for VPERMXOR
+ LXVW4X (MASK)(R0), V20
+ LXVW4X (MASK)(R20), V21
+
+ // splat slot from V19 -> V26
+ VSPLTW $0, V19, V26
+
+ VSLDOI $4, V19, V27, V19
+ VSLDOI $12, V27, V19, V19
+
+ VADDUWM V26, V28, V26
+
+ MOVD $10, R14
+ MOVD R14, CTR
+ PCALIGN $16
+loop_outer_vsx:
+ // V0, V1, V2, V3
+ LXVW4X (R0)(CONSTBASE), VS32
+ LXVW4X (R8)(CONSTBASE), VS33
+ LXVW4X (R9)(CONSTBASE), VS34
+ LXVW4X (R10)(CONSTBASE), VS35
+
+ // splat values from V17, V18 into V4-V11
+ VSPLTW $0, V17, V4
+ VSPLTW $1, V17, V5
+ VSPLTW $2, V17, V6
+ VSPLTW $3, V17, V7
+ VSPLTW $0, V18, V8
+ VSPLTW $1, V18, V9
+ VSPLTW $2, V18, V10
+ VSPLTW $3, V18, V11
+
+ // VOR
+ VOR V26, V26, V12
+
+ // splat values from V19 -> V13, V14, V15
+ VSPLTW $1, V19, V13
+ VSPLTW $2, V19, V14
+ VSPLTW $3, V19, V15
+
+ // splat const values
+ VSPLTISW $-16, V27
+ VSPLTISW $12, V28
+ VSPLTISW $8, V29
+ VSPLTISW $7, V30
+ PCALIGN $16
+loop_vsx:
+ VADDUWM V0, V4, V0
+ VADDUWM V1, V5, V1
+ VADDUWM V2, V6, V2
+ VADDUWM V3, V7, V3
+
+ VPERMXOR V12, V0, V21, V12
+ VPERMXOR V13, V1, V21, V13
+ VPERMXOR V14, V2, V21, V14
+ VPERMXOR V15, V3, V21, V15
+
+ VADDUWM V8, V12, V8
+ VADDUWM V9, V13, V9
+ VADDUWM V10, V14, V10
+ VADDUWM V11, V15, V11
+
+ VXOR V4, V8, V4
+ VXOR V5, V9, V5
+ VXOR V6, V10, V6
+ VXOR V7, V11, V7
+
+ VRLW V4, V28, V4
+ VRLW V5, V28, V5
+ VRLW V6, V28, V6
+ VRLW V7, V28, V7
+
+ VADDUWM V0, V4, V0
+ VADDUWM V1, V5, V1
+ VADDUWM V2, V6, V2
+ VADDUWM V3, V7, V3
+
+ VPERMXOR V12, V0, V20, V12
+ VPERMXOR V13, V1, V20, V13
+ VPERMXOR V14, V2, V20, V14
+ VPERMXOR V15, V3, V20, V15
+
+ VADDUWM V8, V12, V8
+ VADDUWM V9, V13, V9
+ VADDUWM V10, V14, V10
+ VADDUWM V11, V15, V11
+
+ VXOR V4, V8, V4
+ VXOR V5, V9, V5
+ VXOR V6, V10, V6
+ VXOR V7, V11, V7
+
+ VRLW V4, V30, V4
+ VRLW V5, V30, V5
+ VRLW V6, V30, V6
+ VRLW V7, V30, V7
+
+ VADDUWM V0, V5, V0
+ VADDUWM V1, V6, V1
+ VADDUWM V2, V7, V2
+ VADDUWM V3, V4, V3
+
+ VPERMXOR V15, V0, V21, V15
+ VPERMXOR V12, V1, V21, V12
+ VPERMXOR V13, V2, V21, V13
+ VPERMXOR V14, V3, V21, V14
+
+ VADDUWM V10, V15, V10
+ VADDUWM V11, V12, V11
+ VADDUWM V8, V13, V8
+ VADDUWM V9, V14, V9
+
+ VXOR V5, V10, V5
+ VXOR V6, V11, V6
+ VXOR V7, V8, V7
+ VXOR V4, V9, V4
+
+ VRLW V5, V28, V5
+ VRLW V6, V28, V6
+ VRLW V7, V28, V7
+ VRLW V4, V28, V4
+
+ VADDUWM V0, V5, V0
+ VADDUWM V1, V6, V1
+ VADDUWM V2, V7, V2
+ VADDUWM V3, V4, V3
+
+ VPERMXOR V15, V0, V20, V15
+ VPERMXOR V12, V1, V20, V12
+ VPERMXOR V13, V2, V20, V13
+ VPERMXOR V14, V3, V20, V14
+
+ VADDUWM V10, V15, V10
+ VADDUWM V11, V12, V11
+ VADDUWM V8, V13, V8
+ VADDUWM V9, V14, V9
+
+ VXOR V5, V10, V5
+ VXOR V6, V11, V6
+ VXOR V7, V8, V7
+ VXOR V4, V9, V4
+
+ VRLW V5, V30, V5
+ VRLW V6, V30, V6
+ VRLW V7, V30, V7
+ VRLW V4, V30, V4
+ BDNZ loop_vsx
+
+ VADDUWM V12, V26, V12
+
+ VMRGEW V0, V1, V27
+ VMRGEW V2, V3, V28
+
+ VMRGOW V0, V1, V0
+ VMRGOW V2, V3, V2
+
+ VMRGEW V4, V5, V29
+ VMRGEW V6, V7, V30
+
+ XXPERMDI VS32, VS34, $0, VS33
+ XXPERMDI VS32, VS34, $3, VS35
+ XXPERMDI VS59, VS60, $0, VS32
+ XXPERMDI VS59, VS60, $3, VS34
+
+ VMRGOW V4, V5, V4
+ VMRGOW V6, V7, V6
+
+ VMRGEW V8, V9, V27
+ VMRGEW V10, V11, V28
+
+ XXPERMDI VS36, VS38, $0, VS37
+ XXPERMDI VS36, VS38, $3, VS39
+ XXPERMDI VS61, VS62, $0, VS36
+ XXPERMDI VS61, VS62, $3, VS38
+
+ VMRGOW V8, V9, V8
+ VMRGOW V10, V11, V10
+
+ VMRGEW V12, V13, V29
+ VMRGEW V14, V15, V30
+
+ XXPERMDI VS40, VS42, $0, VS41
+ XXPERMDI VS40, VS42, $3, VS43
+ XXPERMDI VS59, VS60, $0, VS40
+ XXPERMDI VS59, VS60, $3, VS42
+
+ VMRGOW V12, V13, V12
+ VMRGOW V14, V15, V14
+
+ VSPLTISW $4, V27
+ VADDUWM V26, V27, V26
+
+ XXPERMDI VS44, VS46, $0, VS45
+ XXPERMDI VS44, VS46, $3, VS47
+ XXPERMDI VS61, VS62, $0, VS44
+ XXPERMDI VS61, VS62, $3, VS46
+
+ VADDUWM V0, V16, V0
+ VADDUWM V4, V17, V4
+ VADDUWM V8, V18, V8
+ VADDUWM V12, V19, V12
+
+ BE_XXBRW(V0)
+ BE_XXBRW(V4)
+ BE_XXBRW(V8)
+ BE_XXBRW(V12)
+
+ CMPU LEN, $64
+ BLT tail_vsx
+
+ // Bottom of loop
+ LXVW4X (INP)(R0), VS59
+ LXVW4X (INP)(R8), VS60
+ LXVW4X (INP)(R9), VS61
+ LXVW4X (INP)(R10), VS62
+
+ VXOR V27, V0, V27
+ VXOR V28, V4, V28
+ VXOR V29, V8, V29
+ VXOR V30, V12, V30
+
+ STXVW4X VS59, (OUT)(R0)
+ STXVW4X VS60, (OUT)(R8)
+ ADD $64, INP
+ STXVW4X VS61, (OUT)(R9)
+ ADD $-64, LEN
+ STXVW4X VS62, (OUT)(R10)
+ ADD $64, OUT
+ BEQ done_vsx
+
+ VADDUWM V1, V16, V0
+ VADDUWM V5, V17, V4
+ VADDUWM V9, V18, V8
+ VADDUWM V13, V19, V12
+
+ BE_XXBRW(V0)
+ BE_XXBRW(V4)
+ BE_XXBRW(V8)
+ BE_XXBRW(V12)
+
+ CMPU LEN, $64
+ BLT tail_vsx
+
+ LXVW4X (INP)(R0), VS59
+ LXVW4X (INP)(R8), VS60
+ LXVW4X (INP)(R9), VS61
+ LXVW4X (INP)(R10), VS62
+
+ VXOR V27, V0, V27
+ VXOR V28, V4, V28
+ VXOR V29, V8, V29
+ VXOR V30, V12, V30
+
+ STXVW4X VS59, (OUT)(R0)
+ STXVW4X VS60, (OUT)(R8)
+ ADD $64, INP
+ STXVW4X VS61, (OUT)(R9)
+ ADD $-64, LEN
+ STXVW4X VS62, (OUT)(V10)
+ ADD $64, OUT
+ BEQ done_vsx
+
+ VADDUWM V2, V16, V0
+ VADDUWM V6, V17, V4
+ VADDUWM V10, V18, V8
+ VADDUWM V14, V19, V12
+
+ BE_XXBRW(V0)
+ BE_XXBRW(V4)
+ BE_XXBRW(V8)
+ BE_XXBRW(V12)
+
+ CMPU LEN, $64
+ BLT tail_vsx
+
+ LXVW4X (INP)(R0), VS59
+ LXVW4X (INP)(R8), VS60
+ LXVW4X (INP)(R9), VS61
+ LXVW4X (INP)(R10), VS62
+
+ VXOR V27, V0, V27
+ VXOR V28, V4, V28
+ VXOR V29, V8, V29
+ VXOR V30, V12, V30
+
+ STXVW4X VS59, (OUT)(R0)
+ STXVW4X VS60, (OUT)(R8)
+ ADD $64, INP
+ STXVW4X VS61, (OUT)(R9)
+ ADD $-64, LEN
+ STXVW4X VS62, (OUT)(R10)
+ ADD $64, OUT
+ BEQ done_vsx
+
+ VADDUWM V3, V16, V0
+ VADDUWM V7, V17, V4
+ VADDUWM V11, V18, V8
+ VADDUWM V15, V19, V12
+
+ BE_XXBRW(V0)
+ BE_XXBRW(V4)
+ BE_XXBRW(V8)
+ BE_XXBRW(V12)
+
+ CMPU LEN, $64
+ BLT tail_vsx
+
+ LXVW4X (INP)(R0), VS59
+ LXVW4X (INP)(R8), VS60
+ LXVW4X (INP)(R9), VS61
+ LXVW4X (INP)(R10), VS62
+
+ VXOR V27, V0, V27
+ VXOR V28, V4, V28
+ VXOR V29, V8, V29
+ VXOR V30, V12, V30
+
+ STXVW4X VS59, (OUT)(R0)
+ STXVW4X VS60, (OUT)(R8)
+ ADD $64, INP
+ STXVW4X VS61, (OUT)(R9)
+ ADD $-64, LEN
+ STXVW4X VS62, (OUT)(R10)
+ ADD $64, OUT
+
+ MOVD $10, R14
+ MOVD R14, CTR
+ BNE loop_outer_vsx
+
+done_vsx:
+ // Increment counter by number of 64 byte blocks
+ MOVWZ (CNT), R14
+ ADD BLOCKS, R14
+ MOVWZ R14, (CNT)
+ RET
+
+tail_vsx:
+ ADD $32, R1, R11
+ MOVD LEN, CTR
+
+ // Save values on stack to copy from
+ STXVW4X VS32, (R11)(R0)
+ STXVW4X VS36, (R11)(R8)
+ STXVW4X VS40, (R11)(R9)
+ STXVW4X VS44, (R11)(R10)
+ ADD $-1, R11, R12
+ ADD $-1, INP
+ ADD $-1, OUT
+ PCALIGN $16
+looptail_vsx:
+ // Copying the result to OUT
+ // in bytes.
+ MOVBZU 1(R12), KEY
+ MOVBZU 1(INP), TMP
+ XOR KEY, TMP, KEY
+ MOVBU KEY, 1(OUT)
+ BDNZ looptail_vsx
+
+ // Clear the stack values
+ STXVW4X VS48, (R11)(R0)
+ STXVW4X VS48, (R11)(R8)
+ STXVW4X VS48, (R11)(R9)
+ STXVW4X VS48, (R11)(R10)
+ BR done_vsx
diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go
new file mode 100644
index 00000000..683ccfd1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go
@@ -0,0 +1,27 @@
+// 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 && !purego
+
+package chacha20
+
+import "golang.org/x/sys/cpu"
+
+var haveAsm = cpu.S390X.HasVX
+
+const bufSize = 256
+
+// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
+// be called when the vector facility is available. Implementation in asm_s390x.s.
+//
+//go:noescape
+func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
+
+func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
+ if cpu.S390X.HasVX {
+ xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
+ } else {
+ c.xorKeyStreamBlocksGeneric(dst, src)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s
new file mode 100644
index 00000000..1eda91a3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s
@@ -0,0 +1,224 @@
+// 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 && !purego
+
+#include "go_asm.h"
+#include "textflag.h"
+
+// This is an implementation of the ChaCha20 encryption algorithm as
+// specified in RFC 7539. It uses vector instructions to compute
+// 4 keystream blocks in parallel (256 bytes) which are then XORed
+// with the bytes in the input slice.
+
+GLOBL ·constants<>(SB), RODATA|NOPTR, $32
+// BSWAP: swap bytes in each 4-byte element
+DATA ·constants<>+0x00(SB)/4, $0x03020100
+DATA ·constants<>+0x04(SB)/4, $0x07060504
+DATA ·constants<>+0x08(SB)/4, $0x0b0a0908
+DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c
+// J0: [j0, j1, j2, j3]
+DATA ·constants<>+0x10(SB)/4, $0x61707865
+DATA ·constants<>+0x14(SB)/4, $0x3320646e
+DATA ·constants<>+0x18(SB)/4, $0x79622d32
+DATA ·constants<>+0x1c(SB)/4, $0x6b206574
+
+#define BSWAP V5
+#define J0 V6
+#define KEY0 V7
+#define KEY1 V8
+#define NONCE V9
+#define CTR V10
+#define M0 V11
+#define M1 V12
+#define M2 V13
+#define M3 V14
+#define INC V15
+#define X0 V16
+#define X1 V17
+#define X2 V18
+#define X3 V19
+#define X4 V20
+#define X5 V21
+#define X6 V22
+#define X7 V23
+#define X8 V24
+#define X9 V25
+#define X10 V26
+#define X11 V27
+#define X12 V28
+#define X13 V29
+#define X14 V30
+#define X15 V31
+
+#define NUM_ROUNDS 20
+
+#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \
+ VAF a1, a0, a0 \
+ VAF b1, b0, b0 \
+ VAF c1, c0, c0 \
+ VAF d1, d0, d0 \
+ VX a0, a2, a2 \
+ VX b0, b2, b2 \
+ VX c0, c2, c2 \
+ VX d0, d2, d2 \
+ VERLLF $16, a2, a2 \
+ VERLLF $16, b2, b2 \
+ VERLLF $16, c2, c2 \
+ VERLLF $16, d2, d2 \
+ VAF a2, a3, a3 \
+ VAF b2, b3, b3 \
+ VAF c2, c3, c3 \
+ VAF d2, d3, d3 \
+ VX a3, a1, a1 \
+ VX b3, b1, b1 \
+ VX c3, c1, c1 \
+ VX d3, d1, d1 \
+ VERLLF $12, a1, a1 \
+ VERLLF $12, b1, b1 \
+ VERLLF $12, c1, c1 \
+ VERLLF $12, d1, d1 \
+ VAF a1, a0, a0 \
+ VAF b1, b0, b0 \
+ VAF c1, c0, c0 \
+ VAF d1, d0, d0 \
+ VX a0, a2, a2 \
+ VX b0, b2, b2 \
+ VX c0, c2, c2 \
+ VX d0, d2, d2 \
+ VERLLF $8, a2, a2 \
+ VERLLF $8, b2, b2 \
+ VERLLF $8, c2, c2 \
+ VERLLF $8, d2, d2 \
+ VAF a2, a3, a3 \
+ VAF b2, b3, b3 \
+ VAF c2, c3, c3 \
+ VAF d2, d3, d3 \
+ VX a3, a1, a1 \
+ VX b3, b1, b1 \
+ VX c3, c1, c1 \
+ VX d3, d1, d1 \
+ VERLLF $7, a1, a1 \
+ VERLLF $7, b1, b1 \
+ VERLLF $7, c1, c1 \
+ VERLLF $7, d1, d1
+
+#define PERMUTE(mask, v0, v1, v2, v3) \
+ VPERM v0, v0, mask, v0 \
+ VPERM v1, v1, mask, v1 \
+ VPERM v2, v2, mask, v2 \
+ VPERM v3, v3, mask, v3
+
+#define ADDV(x, v0, v1, v2, v3) \
+ VAF x, v0, v0 \
+ VAF x, v1, v1 \
+ VAF x, v2, v2 \
+ VAF x, v3, v3
+
+#define XORV(off, dst, src, v0, v1, v2, v3) \
+ VLM off(src), M0, M3 \
+ PERMUTE(BSWAP, v0, v1, v2, v3) \
+ VX v0, M0, M0 \
+ VX v1, M1, M1 \
+ VX v2, M2, M2 \
+ VX v3, M3, M3 \
+ VSTM M0, M3, off(dst)
+
+#define SHUFFLE(a, b, c, d, t, u, v, w) \
+ VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]}
+ VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]}
+ VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]}
+ VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]}
+ VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]}
+ VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]}
+ VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]}
+ VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]}
+
+// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
+TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
+ MOVD $·constants<>(SB), R1
+ MOVD dst+0(FP), R2 // R2=&dst[0]
+ LMG src+24(FP), R3, R4 // R3=&src[0] R4=len(src)
+ MOVD key+48(FP), R5 // R5=key
+ MOVD nonce+56(FP), R6 // R6=nonce
+ MOVD counter+64(FP), R7 // R7=counter
+
+ // load BSWAP and J0
+ VLM (R1), BSWAP, J0
+
+ // setup
+ MOVD $95, R0
+ VLM (R5), KEY0, KEY1
+ VLL R0, (R6), NONCE
+ VZERO M0
+ VLEIB $7, $32, M0
+ VSRLB M0, NONCE, NONCE
+
+ // initialize counter values
+ VLREPF (R7), CTR
+ VZERO INC
+ VLEIF $1, $1, INC
+ VLEIF $2, $2, INC
+ VLEIF $3, $3, INC
+ VAF INC, CTR, CTR
+ VREPIF $4, INC
+
+chacha:
+ VREPF $0, J0, X0
+ VREPF $1, J0, X1
+ VREPF $2, J0, X2
+ VREPF $3, J0, X3
+ VREPF $0, KEY0, X4
+ VREPF $1, KEY0, X5
+ VREPF $2, KEY0, X6
+ VREPF $3, KEY0, X7
+ VREPF $0, KEY1, X8
+ VREPF $1, KEY1, X9
+ VREPF $2, KEY1, X10
+ VREPF $3, KEY1, X11
+ VLR CTR, X12
+ VREPF $1, NONCE, X13
+ VREPF $2, NONCE, X14
+ VREPF $3, NONCE, X15
+
+ MOVD $(NUM_ROUNDS/2), R1
+
+loop:
+ ROUND4(X0, X4, X12, X8, X1, X5, X13, X9, X2, X6, X14, X10, X3, X7, X15, X11)
+ ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8, X3, X4, X14, X9)
+
+ ADD $-1, R1
+ BNE loop
+
+ // decrement length
+ ADD $-256, R4
+
+ // rearrange vectors
+ SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3)
+ ADDV(J0, X0, X1, X2, X3)
+ SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3)
+ ADDV(KEY0, X4, X5, X6, X7)
+ SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3)
+ ADDV(KEY1, X8, X9, X10, X11)
+ VAF CTR, X12, X12
+ SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3)
+ ADDV(NONCE, X12, X13, X14, X15)
+
+ // increment counters
+ VAF INC, CTR, CTR
+
+ // xor keystream with plaintext
+ XORV(0*64, R2, R3, X0, X4, X8, X12)
+ XORV(1*64, R2, R3, X1, X5, X9, X13)
+ XORV(2*64, R2, R3, X2, X6, X10, X14)
+ XORV(3*64, R2, R3, X3, X7, X11, X15)
+
+ // increment pointers
+ MOVD $256(R2), R2
+ MOVD $256(R3), R3
+
+ CMPBNE R4, $0, chacha
+
+ VSTEF $0, CTR, (R7)
+ RET
diff --git a/vendor/golang.org/x/crypto/chacha20/xor.go b/vendor/golang.org/x/crypto/chacha20/xor.go
new file mode 100644
index 00000000..c2d04851
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20/xor.go
@@ -0,0 +1,42 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found src the LICENSE file.
+
+package chacha20
+
+import "runtime"
+
+// Platforms that have fast unaligned 32-bit little endian accesses.
+const unaligned = runtime.GOARCH == "386" ||
+ runtime.GOARCH == "amd64" ||
+ runtime.GOARCH == "arm64" ||
+ runtime.GOARCH == "ppc64le" ||
+ runtime.GOARCH == "s390x"
+
+// addXor reads a little endian uint32 from src, XORs it with (a + b) and
+// places the result in little endian byte order in dst.
+func addXor(dst, src []byte, a, b uint32) {
+ _, _ = src[3], dst[3] // bounds check elimination hint
+ if unaligned {
+ // The compiler should optimize this code into
+ // 32-bit unaligned little endian loads and stores.
+ // TODO: delete once the compiler does a reliably
+ // good job with the generic code below.
+ // See issue #25111 for more details.
+ v := uint32(src[0])
+ v |= uint32(src[1]) << 8
+ v |= uint32(src[2]) << 16
+ v |= uint32(src[3]) << 24
+ v ^= a + b
+ dst[0] = byte(v)
+ dst[1] = byte(v >> 8)
+ dst[2] = byte(v >> 16)
+ dst[3] = byte(v >> 24)
+ } else {
+ a += b
+ dst[0] = src[0] ^ byte(a)
+ dst[1] = src[1] ^ byte(a>>8)
+ dst[2] = src[2] ^ byte(a>>16)
+ dst[3] = src[3] ^ byte(a>>24)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
new file mode 100644
index 00000000..95679552
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
@@ -0,0 +1,101 @@
+// 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 chacha20poly1305 implements the ChaCha20-Poly1305 AEAD and its
+// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
+// draft-irtf-cfrg-xchacha-01.
+package chacha20poly1305
+
+import (
+ "crypto/cipher"
+ "errors"
+)
+
+const (
+ // KeySize is the size of the key used by this AEAD, in bytes.
+ KeySize = 32
+
+ // NonceSize is the size of the nonce used with the standard variant of this
+ // AEAD, in bytes.
+ //
+ // Note that this is too short to be safely generated at random if the same
+ // key is reused more than 2³² times.
+ NonceSize = 12
+
+ // NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
+ // variant of this AEAD, in bytes.
+ NonceSizeX = 24
+
+ // Overhead is the size of the Poly1305 authentication tag, and the
+ // difference between a ciphertext length and its plaintext.
+ Overhead = 16
+)
+
+type chacha20poly1305 struct {
+ key [KeySize]byte
+}
+
+// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
+func New(key []byte) (cipher.AEAD, error) {
+ if fips140Enforced() {
+ return nil, errors.New("chacha20poly1305: use of ChaCha20Poly1305 is not allowed in FIPS 140-only mode")
+ }
+ if len(key) != KeySize {
+ return nil, errors.New("chacha20poly1305: bad key length")
+ }
+ ret := new(chacha20poly1305)
+ copy(ret.key[:], key)
+ return ret, nil
+}
+
+func (c *chacha20poly1305) NonceSize() int {
+ return NonceSize
+}
+
+func (c *chacha20poly1305) Overhead() int {
+ return Overhead
+}
+
+func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if len(nonce) != NonceSize {
+ panic("chacha20poly1305: bad nonce length passed to Seal")
+ }
+
+ if uint64(len(plaintext)) > (1<<38)-64 {
+ panic("chacha20poly1305: plaintext too large")
+ }
+
+ return c.seal(dst, nonce, plaintext, additionalData)
+}
+
+var errOpen = errors.New("chacha20poly1305: message authentication failed")
+
+func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if len(nonce) != NonceSize {
+ panic("chacha20poly1305: bad nonce length passed to Open")
+ }
+ if len(ciphertext) < 16 {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > (1<<38)-48 {
+ panic("chacha20poly1305: ciphertext too large")
+ }
+
+ return c.open(dst, nonce, ciphertext, additionalData)
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
new file mode 100644
index 00000000..bfe546b6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
@@ -0,0 +1,92 @@
+// 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 gc && !purego
+
+package chacha20poly1305
+
+import (
+ "encoding/binary"
+
+ "golang.org/x/crypto/internal/alias"
+ "golang.org/x/sys/cpu"
+)
+
+//go:noescape
+func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
+
+//go:noescape
+func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
+
+var (
+ useAVX2 = cpu.X86.HasSSSE3 && cpu.X86.HasAVX2 && cpu.X86.HasBMI2
+)
+
+// setupState writes a ChaCha20 input matrix to state. See
+// https://tools.ietf.org/html/rfc7539#section-2.3.
+func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
+ state[0] = 0x61707865
+ state[1] = 0x3320646e
+ state[2] = 0x79622d32
+ state[3] = 0x6b206574
+
+ state[4] = binary.LittleEndian.Uint32(key[0:4])
+ state[5] = binary.LittleEndian.Uint32(key[4:8])
+ state[6] = binary.LittleEndian.Uint32(key[8:12])
+ state[7] = binary.LittleEndian.Uint32(key[12:16])
+ state[8] = binary.LittleEndian.Uint32(key[16:20])
+ state[9] = binary.LittleEndian.Uint32(key[20:24])
+ state[10] = binary.LittleEndian.Uint32(key[24:28])
+ state[11] = binary.LittleEndian.Uint32(key[28:32])
+
+ state[12] = 0
+ state[13] = binary.LittleEndian.Uint32(nonce[0:4])
+ state[14] = binary.LittleEndian.Uint32(nonce[4:8])
+ state[15] = binary.LittleEndian.Uint32(nonce[8:12])
+}
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if !useAVX2 {
+ return c.sealGeneric(dst, nonce, plaintext, additionalData)
+ }
+
+ var state [16]uint32
+ setupState(&state, &c.key, nonce)
+
+ ret, out := sliceForAppend(dst, len(plaintext)+16)
+ if alias.InexactOverlap(out, plaintext) {
+ panic("chacha20poly1305: invalid buffer overlap of output and input")
+ }
+ if alias.AnyOverlap(out, additionalData) {
+ panic("chacha20poly1305: invalid buffer overlap of output and additional data")
+ }
+ chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
+ return ret
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if !useAVX2 {
+ return c.openGeneric(dst, nonce, ciphertext, additionalData)
+ }
+
+ var state [16]uint32
+ setupState(&state, &c.key, nonce)
+
+ ciphertext = ciphertext[:len(ciphertext)-16]
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if alias.InexactOverlap(out, ciphertext) {
+ panic("chacha20poly1305: invalid buffer overlap of output and input")
+ }
+ if alias.AnyOverlap(out, additionalData) {
+ panic("chacha20poly1305: invalid buffer overlap of output and additional data")
+ }
+ if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ return ret, nil
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
new file mode 100644
index 00000000..c703c134
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
@@ -0,0 +1,5230 @@
+// Code generated by command: go run chacha20poly1305_amd64_asm.go -out ../chacha20poly1305_amd64.s -pkg chacha20poly1305. DO NOT EDIT.
+
+//go:build gc && !purego
+
+#include "textflag.h"
+
+// func polyHashADInternal<>()
+TEXT polyHashADInternal<>(SB), NOSPLIT, $0
+ XORQ R10, R10
+ XORQ R11, R11
+ XORQ R12, R12
+ CMPQ R9, $0x0d
+ JNE hashADLoop
+ MOVQ (CX), R10
+ MOVQ 5(CX), R11
+ SHRQ $0x18, R11
+ MOVQ $0x00000001, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ RET
+
+hashADLoop:
+ // Hash in 16 byte chunks
+ CMPQ R9, $0x10
+ JB hashADTail
+ ADDQ (CX), R10
+ ADCQ 8(CX), R11
+ ADCQ $0x01, R12
+ LEAQ 16(CX), CX
+ SUBQ $0x10, R9
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ JMP hashADLoop
+
+hashADTail:
+ CMPQ R9, $0x00
+ JE hashADDone
+
+ // Hash last < 16 byte tail
+ XORQ R13, R13
+ XORQ R14, R14
+ XORQ R15, R15
+ ADDQ R9, CX
+
+hashADTailLoop:
+ SHLQ $0x08, R13, R14
+ SHLQ $0x08, R13
+ MOVB -1(CX), R15
+ XORQ R15, R13
+ DECQ CX
+ DECQ R9
+ JNE hashADTailLoop
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+
+hashADDone:
+ RET
+
+// func chacha20Poly1305Open(dst []byte, key []uint32, src []byte, ad []byte) bool
+// Requires: AVX, AVX2, BMI2, CMOV, SSE2
+TEXT ·chacha20Poly1305Open(SB), $288-97
+ // For aligned stack access
+ MOVQ SP, BP
+ ADDQ $0x20, BP
+ ANDQ $-32, BP
+ MOVQ dst_base+0(FP), DI
+ MOVQ key_base+24(FP), R8
+ MOVQ src_base+48(FP), SI
+ MOVQ src_len+56(FP), BX
+ MOVQ ad_base+72(FP), CX
+ VZEROUPPER
+ VMOVDQU ·chacha20Constants<>+0(SB), Y0
+ VBROADCASTI128 16(R8), Y14
+ VBROADCASTI128 32(R8), Y12
+ VBROADCASTI128 48(R8), Y4
+ VPADDD ·avx2InitMask<>+0(SB), Y4, Y4
+
+ // Special optimization, for very short buffers
+ CMPQ BX, $0xc0
+ JBE openAVX2192
+ CMPQ BX, $0x00000140
+ JBE openAVX2320
+
+ // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+ VMOVDQA Y14, 32(BP)
+ VMOVDQA Y12, 64(BP)
+ VMOVDQA Y4, 192(BP)
+ MOVQ $0x0000000a, R9
+
+openAVX2PreparePolyKey:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x04, Y4, Y4, Y4
+ DECQ R9
+ JNE openAVX2PreparePolyKey
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 192(BP), Y4, Y4
+ VPERM2I128 $0x02, Y0, Y14, Y3
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>+0(SB), Y3, Y3
+ VMOVDQA Y3, (BP)
+
+ // Stream for the first 64 bytes
+ VPERM2I128 $0x13, Y0, Y14, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y14
+
+ // Hash AD + first 64 bytes
+ MOVQ ad_len+80(FP), R9
+ CALL polyHashADInternal<>(SB)
+ XORQ CX, CX
+
+openAVX2InitialHash64:
+ ADDQ (SI)(CX*1), R10
+ ADCQ 8(SI)(CX*1), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ ADDQ $0x10, CX
+ CMPQ CX, $0x40
+ JNE openAVX2InitialHash64
+
+ // Decrypt the first 64 bytes
+ VPXOR (SI), Y0, Y0
+ VPXOR 32(SI), Y14, Y14
+ VMOVDQU Y0, (DI)
+ VMOVDQU Y14, 32(DI)
+ LEAQ 64(SI), SI
+ LEAQ 64(DI), DI
+ SUBQ $0x40, BX
+
+openAVX2MainLoop:
+ CMPQ BX, $0x00000200
+ JB openAVX2MainLoopDone
+
+ // Load state, increment counter blocks, store the incremented counters
+ VMOVDQU ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA Y0, Y7
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA Y14, Y11
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA Y12, Y15
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VPADDD ·avx2IncMask<>+0(SB), Y2, Y3
+ VMOVDQA Y4, 96(BP)
+ VMOVDQA Y1, 128(BP)
+ VMOVDQA Y2, 160(BP)
+ VMOVDQA Y3, 192(BP)
+ XORQ CX, CX
+
+openAVX2InternalLoop:
+ ADDQ (SI)(CX*1), R10
+ ADCQ 8(SI)(CX*1), R11
+ ADCQ $0x01, R12
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ ADDQ 16(SI)(CX*1), R10
+ ADCQ 24(SI)(CX*1), R11
+ ADCQ $0x01, R12
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x04, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPALIGNR $0x0c, Y3, Y3, Y3
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ ADDQ 32(SI)(CX*1), R10
+ ADCQ 40(SI)(CX*1), R11
+ ADCQ $0x01, R12
+ LEAQ 48(CX), CX
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x0c, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ VPALIGNR $0x04, Y3, Y3, Y3
+ CMPQ CX, $0x000001e0
+ JNE openAVX2InternalLoop
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD ·chacha20Constants<>+0(SB), Y6, Y6
+ VPADDD ·chacha20Constants<>+0(SB), Y7, Y7
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 32(BP), Y10, Y10
+ VPADDD 32(BP), Y11, Y11
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD 64(BP), Y8, Y8
+ VPADDD 64(BP), Y15, Y15
+ VPADDD 96(BP), Y4, Y4
+ VPADDD 128(BP), Y1, Y1
+ VPADDD 160(BP), Y2, Y2
+ VPADDD 192(BP), Y3, Y3
+ VMOVDQA Y15, 224(BP)
+
+ // We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+ ADDQ 480(SI), R10
+ ADCQ 488(SI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPERM2I128 $0x02, Y0, Y14, Y15
+ VPERM2I128 $0x13, Y0, Y14, Y14
+ VPERM2I128 $0x02, Y12, Y4, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y12
+ VPXOR (SI), Y15, Y15
+ VPXOR 32(SI), Y0, Y0
+ VPXOR 64(SI), Y14, Y14
+ VPXOR 96(SI), Y12, Y12
+ VMOVDQU Y15, (DI)
+ VMOVDQU Y0, 32(DI)
+ VMOVDQU Y14, 64(DI)
+ VMOVDQU Y12, 96(DI)
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ VPXOR 128(SI), Y0, Y0
+ VPXOR 160(SI), Y14, Y14
+ VPXOR 192(SI), Y12, Y12
+ VPXOR 224(SI), Y4, Y4
+ VMOVDQU Y0, 128(DI)
+ VMOVDQU Y14, 160(DI)
+ VMOVDQU Y12, 192(DI)
+ VMOVDQU Y4, 224(DI)
+
+ // and here
+ ADDQ 496(SI), R10
+ ADCQ 504(SI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPERM2I128 $0x02, Y6, Y10, Y0
+ VPERM2I128 $0x02, Y8, Y2, Y14
+ VPERM2I128 $0x13, Y6, Y10, Y12
+ VPERM2I128 $0x13, Y8, Y2, Y4
+ VPXOR 256(SI), Y0, Y0
+ VPXOR 288(SI), Y14, Y14
+ VPXOR 320(SI), Y12, Y12
+ VPXOR 352(SI), Y4, Y4
+ VMOVDQU Y0, 256(DI)
+ VMOVDQU Y14, 288(DI)
+ VMOVDQU Y12, 320(DI)
+ VMOVDQU Y4, 352(DI)
+ VPERM2I128 $0x02, Y7, Y11, Y0
+ VPERM2I128 $0x02, 224(BP), Y3, Y14
+ VPERM2I128 $0x13, Y7, Y11, Y12
+ VPERM2I128 $0x13, 224(BP), Y3, Y4
+ VPXOR 384(SI), Y0, Y0
+ VPXOR 416(SI), Y14, Y14
+ VPXOR 448(SI), Y12, Y12
+ VPXOR 480(SI), Y4, Y4
+ VMOVDQU Y0, 384(DI)
+ VMOVDQU Y14, 416(DI)
+ VMOVDQU Y12, 448(DI)
+ VMOVDQU Y4, 480(DI)
+ LEAQ 512(SI), SI
+ LEAQ 512(DI), DI
+ SUBQ $0x00000200, BX
+ JMP openAVX2MainLoop
+
+openAVX2MainLoopDone:
+ // Handle the various tail sizes efficiently
+ TESTQ BX, BX
+ JE openSSEFinalize
+ CMPQ BX, $0x80
+ JBE openAVX2Tail128
+ CMPQ BX, $0x00000100
+ JBE openAVX2Tail256
+ CMPQ BX, $0x00000180
+ JBE openAVX2Tail384
+ JMP openAVX2Tail512
+
+openSSEFinalize:
+ // Hash in the PT, AAD lengths
+ ADDQ ad_len+80(FP), R10
+ ADCQ src_len+56(FP), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+
+ // Final reduce
+ MOVQ R10, R13
+ MOVQ R11, R14
+ MOVQ R12, R15
+ SUBQ $-5, R10
+ SBBQ $-1, R11
+ SBBQ $0x03, R12
+ CMOVQCS R13, R10
+ CMOVQCS R14, R11
+ CMOVQCS R15, R12
+
+ // Add in the "s" part of the key
+ ADDQ 16(BP), R10
+ ADCQ 24(BP), R11
+
+ // Finally, constant time compare to the tag at the end of the message
+ XORQ AX, AX
+ MOVQ $0x00000001, DX
+ XORQ (SI), R10
+ XORQ 8(SI), R11
+ ORQ R11, R10
+ CMOVQEQ DX, AX
+
+ // Return true iff tags are equal
+ MOVB AX, ret+96(FP)
+ RET
+
+openSSETail16:
+ TESTQ BX, BX
+ JE openSSEFinalize
+
+ // We can safely load the CT from the end, because it is padded with the MAC
+ MOVQ BX, R9
+ SHLQ $0x04, R9
+ LEAQ ·andMask<>+0(SB), R13
+ MOVOU (SI), X12
+ ADDQ BX, SI
+ PAND -16(R13)(R9*1), X12
+ MOVO X12, 64(BP)
+ MOVQ X12, R13
+ MOVQ 72(BP), R14
+ PXOR X1, X12
+
+ // We can only store one byte at a time, since plaintext can be shorter than 16 bytes
+openSSETail16Store:
+ MOVQ X12, R8
+ MOVB R8, (DI)
+ PSRLDQ $0x01, X12
+ INCQ DI
+ DECQ BX
+ JNE openSSETail16Store
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ JMP openSSEFinalize
+
+openAVX2192:
+ VMOVDQA Y0, Y5
+ VMOVDQA Y14, Y9
+ VMOVDQA Y12, Y13
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VMOVDQA Y0, Y6
+ VMOVDQA Y14, Y10
+ VMOVDQA Y12, Y8
+ VMOVDQA Y4, Y2
+ VMOVDQA Y1, Y15
+ MOVQ $0x0000000a, R9
+
+openAVX2192InnerCipherLoop:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ DECQ R9
+ JNE openAVX2192InnerCipherLoop
+ VPADDD Y6, Y0, Y0
+ VPADDD Y6, Y5, Y5
+ VPADDD Y10, Y14, Y14
+ VPADDD Y10, Y9, Y9
+ VPADDD Y8, Y12, Y12
+ VPADDD Y8, Y13, Y13
+ VPADDD Y2, Y4, Y4
+ VPADDD Y15, Y1, Y1
+ VPERM2I128 $0x02, Y0, Y14, Y3
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>+0(SB), Y3, Y3
+ VMOVDQA Y3, (BP)
+
+ // Stream for up to 192 bytes
+ VPERM2I128 $0x13, Y0, Y14, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y14
+ VPERM2I128 $0x02, Y5, Y9, Y12
+ VPERM2I128 $0x02, Y13, Y1, Y4
+ VPERM2I128 $0x13, Y5, Y9, Y5
+ VPERM2I128 $0x13, Y13, Y1, Y9
+
+openAVX2ShortOpen:
+ // Hash
+ MOVQ ad_len+80(FP), R9
+ CALL polyHashADInternal<>(SB)
+
+openAVX2ShortOpenLoop:
+ CMPQ BX, $0x20
+ JB openAVX2ShortTail32
+ SUBQ $0x20, BX
+
+ // Load for hashing
+ ADDQ (SI), R10
+ ADCQ 8(SI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ ADDQ 16(SI), R10
+ ADCQ 24(SI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+
+ // Load for decryption
+ VPXOR (SI), Y0, Y0
+ VMOVDQU Y0, (DI)
+ LEAQ 32(SI), SI
+ LEAQ 32(DI), DI
+
+ // Shift stream left
+ VMOVDQA Y14, Y0
+ VMOVDQA Y12, Y14
+ VMOVDQA Y4, Y12
+ VMOVDQA Y5, Y4
+ VMOVDQA Y9, Y5
+ VMOVDQA Y13, Y9
+ VMOVDQA Y1, Y13
+ VMOVDQA Y6, Y1
+ VMOVDQA Y10, Y6
+ JMP openAVX2ShortOpenLoop
+
+openAVX2ShortTail32:
+ CMPQ BX, $0x10
+ VMOVDQA X0, X1
+ JB openAVX2ShortDone
+ SUBQ $0x10, BX
+
+ // Load for hashing
+ ADDQ (SI), R10
+ ADCQ 8(SI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+
+ // Load for decryption
+ VPXOR (SI), X0, X12
+ VMOVDQU X12, (DI)
+ LEAQ 16(SI), SI
+ LEAQ 16(DI), DI
+ VPERM2I128 $0x11, Y0, Y0, Y0
+ VMOVDQA X0, X1
+
+openAVX2ShortDone:
+ VZEROUPPER
+ JMP openSSETail16
+
+openAVX2320:
+ VMOVDQA Y0, Y5
+ VMOVDQA Y14, Y9
+ VMOVDQA Y12, Y13
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VMOVDQA Y0, Y6
+ VMOVDQA Y14, Y10
+ VMOVDQA Y12, Y8
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VMOVDQA Y14, Y7
+ VMOVDQA Y12, Y11
+ VMOVDQA Y4, Y15
+ MOVQ $0x0000000a, R9
+
+openAVX2320InnerCipherLoop:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ DECQ R9
+ JNE openAVX2320InnerCipherLoop
+ VMOVDQA ·chacha20Constants<>+0(SB), Y3
+ VPADDD Y3, Y0, Y0
+ VPADDD Y3, Y5, Y5
+ VPADDD Y3, Y6, Y6
+ VPADDD Y7, Y14, Y14
+ VPADDD Y7, Y9, Y9
+ VPADDD Y7, Y10, Y10
+ VPADDD Y11, Y12, Y12
+ VPADDD Y11, Y13, Y13
+ VPADDD Y11, Y8, Y8
+ VMOVDQA ·avx2IncMask<>+0(SB), Y3
+ VPADDD Y15, Y4, Y4
+ VPADDD Y3, Y15, Y15
+ VPADDD Y15, Y1, Y1
+ VPADDD Y3, Y15, Y15
+ VPADDD Y15, Y2, Y2
+
+ // Clamp and store poly key
+ VPERM2I128 $0x02, Y0, Y14, Y3
+ VPAND ·polyClampMask<>+0(SB), Y3, Y3
+ VMOVDQA Y3, (BP)
+
+ // Stream for up to 320 bytes
+ VPERM2I128 $0x13, Y0, Y14, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y14
+ VPERM2I128 $0x02, Y5, Y9, Y12
+ VPERM2I128 $0x02, Y13, Y1, Y4
+ VPERM2I128 $0x13, Y5, Y9, Y5
+ VPERM2I128 $0x13, Y13, Y1, Y9
+ VPERM2I128 $0x02, Y6, Y10, Y13
+ VPERM2I128 $0x02, Y8, Y2, Y1
+ VPERM2I128 $0x13, Y6, Y10, Y6
+ VPERM2I128 $0x13, Y8, Y2, Y10
+ JMP openAVX2ShortOpen
+
+openAVX2Tail128:
+ // Need to decrypt up to 128 bytes - prepare two blocks
+ VMOVDQA ·chacha20Constants<>+0(SB), Y5
+ VMOVDQA 32(BP), Y9
+ VMOVDQA 64(BP), Y13
+ VMOVDQA 192(BP), Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y1
+ VMOVDQA Y1, Y4
+ XORQ R9, R9
+ MOVQ BX, CX
+ ANDQ $-16, CX
+ TESTQ CX, CX
+ JE openAVX2Tail128LoopB
+
+openAVX2Tail128LoopA:
+ ADDQ (SI)(R9*1), R10
+ ADCQ 8(SI)(R9*1), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+
+openAVX2Tail128LoopB:
+ ADDQ $0x10, R9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x04, Y1, Y1, Y1
+ CMPQ R9, CX
+ JB openAVX2Tail128LoopA
+ CMPQ R9, $0xa0
+ JNE openAVX2Tail128LoopB
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 64(BP), Y13, Y13
+ VPADDD Y4, Y1, Y1
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+
+openAVX2TailLoop:
+ CMPQ BX, $0x20
+ JB openAVX2Tail
+ SUBQ $0x20, BX
+
+ // Load for decryption
+ VPXOR (SI), Y0, Y0
+ VMOVDQU Y0, (DI)
+ LEAQ 32(SI), SI
+ LEAQ 32(DI), DI
+ VMOVDQA Y14, Y0
+ VMOVDQA Y12, Y14
+ VMOVDQA Y4, Y12
+ JMP openAVX2TailLoop
+
+openAVX2Tail:
+ CMPQ BX, $0x10
+ VMOVDQA X0, X1
+ JB openAVX2TailDone
+ SUBQ $0x10, BX
+
+ // Load for decryption
+ VPXOR (SI), X0, X12
+ VMOVDQU X12, (DI)
+ LEAQ 16(SI), SI
+ LEAQ 16(DI), DI
+ VPERM2I128 $0x11, Y0, Y0, Y0
+ VMOVDQA X0, X1
+
+openAVX2TailDone:
+ VZEROUPPER
+ JMP openSSETail16
+
+openAVX2Tail256:
+ VMOVDQA ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VMOVDQA Y4, Y7
+ VMOVDQA Y1, Y11
+
+ // Compute the number of iterations that will hash data
+ MOVQ BX, 224(BP)
+ MOVQ BX, CX
+ SUBQ $0x80, CX
+ SHRQ $0x04, CX
+ MOVQ $0x0000000a, R9
+ CMPQ CX, $0x0a
+ CMOVQGT R9, CX
+ MOVQ SI, BX
+ XORQ R9, R9
+
+openAVX2Tail256LoopA:
+ ADDQ (BX), R10
+ ADCQ 8(BX), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(BX), BX
+
+openAVX2Tail256LoopB:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ INCQ R9
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ CMPQ R9, CX
+ JB openAVX2Tail256LoopA
+ CMPQ R9, $0x0a
+ JNE openAVX2Tail256LoopB
+ MOVQ BX, R9
+ SUBQ SI, BX
+ MOVQ BX, CX
+ MOVQ 224(BP), BX
+
+openAVX2Tail256Hash:
+ ADDQ $0x10, CX
+ CMPQ CX, BX
+ JGT openAVX2Tail256HashEnd
+ ADDQ (R9), R10
+ ADCQ 8(R9), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(R9), R9
+ JMP openAVX2Tail256Hash
+
+openAVX2Tail256HashEnd:
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD Y7, Y4, Y4
+ VPADDD Y11, Y1, Y1
+ VPERM2I128 $0x02, Y0, Y14, Y6
+ VPERM2I128 $0x02, Y12, Y4, Y10
+ VPERM2I128 $0x13, Y0, Y14, Y8
+ VPERM2I128 $0x13, Y12, Y4, Y2
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ VPXOR (SI), Y6, Y6
+ VPXOR 32(SI), Y10, Y10
+ VPXOR 64(SI), Y8, Y8
+ VPXOR 96(SI), Y2, Y2
+ VMOVDQU Y6, (DI)
+ VMOVDQU Y10, 32(DI)
+ VMOVDQU Y8, 64(DI)
+ VMOVDQU Y2, 96(DI)
+ LEAQ 128(SI), SI
+ LEAQ 128(DI), DI
+ SUBQ $0x80, BX
+ JMP openAVX2TailLoop
+
+openAVX2Tail384:
+ // Need to decrypt up to 384 bytes - prepare six blocks
+ VMOVDQA ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VMOVDQA Y4, 96(BP)
+ VMOVDQA Y1, 128(BP)
+ VMOVDQA Y2, 160(BP)
+
+ // Compute the number of iterations that will hash two blocks of data
+ MOVQ BX, 224(BP)
+ MOVQ BX, CX
+ SUBQ $0x00000100, CX
+ SHRQ $0x04, CX
+ ADDQ $0x06, CX
+ MOVQ $0x0000000a, R9
+ CMPQ CX, $0x0a
+ CMOVQGT R9, CX
+ MOVQ SI, BX
+ XORQ R9, R9
+
+openAVX2Tail384LoopB:
+ ADDQ (BX), R10
+ ADCQ 8(BX), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(BX), BX
+
+openAVX2Tail384LoopA:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ ADDQ (BX), R10
+ ADCQ 8(BX), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(BX), BX
+ INCQ R9
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ CMPQ R9, CX
+ JB openAVX2Tail384LoopB
+ CMPQ R9, $0x0a
+ JNE openAVX2Tail384LoopA
+ MOVQ BX, R9
+ SUBQ SI, BX
+ MOVQ BX, CX
+ MOVQ 224(BP), BX
+
+openAVX2Tail384Hash:
+ ADDQ $0x10, CX
+ CMPQ CX, BX
+ JGT openAVX2Tail384HashEnd
+ ADDQ (R9), R10
+ ADCQ 8(R9), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(R9), R9
+ JMP openAVX2Tail384Hash
+
+openAVX2Tail384HashEnd:
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD ·chacha20Constants<>+0(SB), Y6, Y6
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 32(BP), Y10, Y10
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD 64(BP), Y8, Y8
+ VPADDD 96(BP), Y4, Y4
+ VPADDD 128(BP), Y1, Y1
+ VPADDD 160(BP), Y2, Y2
+ VPERM2I128 $0x02, Y0, Y14, Y3
+ VPERM2I128 $0x02, Y12, Y4, Y7
+ VPERM2I128 $0x13, Y0, Y14, Y11
+ VPERM2I128 $0x13, Y12, Y4, Y15
+ VPXOR (SI), Y3, Y3
+ VPXOR 32(SI), Y7, Y7
+ VPXOR 64(SI), Y11, Y11
+ VPXOR 96(SI), Y15, Y15
+ VMOVDQU Y3, (DI)
+ VMOVDQU Y7, 32(DI)
+ VMOVDQU Y11, 64(DI)
+ VMOVDQU Y15, 96(DI)
+ VPERM2I128 $0x02, Y5, Y9, Y3
+ VPERM2I128 $0x02, Y13, Y1, Y7
+ VPERM2I128 $0x13, Y5, Y9, Y11
+ VPERM2I128 $0x13, Y13, Y1, Y15
+ VPXOR 128(SI), Y3, Y3
+ VPXOR 160(SI), Y7, Y7
+ VPXOR 192(SI), Y11, Y11
+ VPXOR 224(SI), Y15, Y15
+ VMOVDQU Y3, 128(DI)
+ VMOVDQU Y7, 160(DI)
+ VMOVDQU Y11, 192(DI)
+ VMOVDQU Y15, 224(DI)
+ VPERM2I128 $0x02, Y6, Y10, Y0
+ VPERM2I128 $0x02, Y8, Y2, Y14
+ VPERM2I128 $0x13, Y6, Y10, Y12
+ VPERM2I128 $0x13, Y8, Y2, Y4
+ LEAQ 256(SI), SI
+ LEAQ 256(DI), DI
+ SUBQ $0x00000100, BX
+ JMP openAVX2TailLoop
+
+openAVX2Tail512:
+ VMOVDQU ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA Y0, Y7
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA Y14, Y11
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA Y12, Y15
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VPADDD ·avx2IncMask<>+0(SB), Y2, Y3
+ VMOVDQA Y4, 96(BP)
+ VMOVDQA Y1, 128(BP)
+ VMOVDQA Y2, 160(BP)
+ VMOVDQA Y3, 192(BP)
+ XORQ CX, CX
+ MOVQ SI, R9
+
+openAVX2Tail512LoopB:
+ ADDQ (R9), R10
+ ADCQ 8(R9), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(R9), R9
+
+openAVX2Tail512LoopA:
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ ADDQ (R9), R10
+ ADCQ 8(R9), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x04, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPALIGNR $0x0c, Y3, Y3, Y3
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ ADDQ 16(R9), R10
+ ADCQ 24(R9), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(R9), R9
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x0c, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ VPALIGNR $0x04, Y3, Y3, Y3
+ INCQ CX
+ CMPQ CX, $0x04
+ JLT openAVX2Tail512LoopB
+ CMPQ CX, $0x0a
+ JNE openAVX2Tail512LoopA
+ MOVQ BX, CX
+ SUBQ $0x00000180, CX
+ ANDQ $-16, CX
+
+openAVX2Tail512HashLoop:
+ TESTQ CX, CX
+ JE openAVX2Tail512HashEnd
+ ADDQ (R9), R10
+ ADCQ 8(R9), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(R9), R9
+ SUBQ $0x10, CX
+ JMP openAVX2Tail512HashLoop
+
+openAVX2Tail512HashEnd:
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD ·chacha20Constants<>+0(SB), Y6, Y6
+ VPADDD ·chacha20Constants<>+0(SB), Y7, Y7
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 32(BP), Y10, Y10
+ VPADDD 32(BP), Y11, Y11
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD 64(BP), Y8, Y8
+ VPADDD 64(BP), Y15, Y15
+ VPADDD 96(BP), Y4, Y4
+ VPADDD 128(BP), Y1, Y1
+ VPADDD 160(BP), Y2, Y2
+ VPADDD 192(BP), Y3, Y3
+ VMOVDQA Y15, 224(BP)
+ VPERM2I128 $0x02, Y0, Y14, Y15
+ VPERM2I128 $0x13, Y0, Y14, Y14
+ VPERM2I128 $0x02, Y12, Y4, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y12
+ VPXOR (SI), Y15, Y15
+ VPXOR 32(SI), Y0, Y0
+ VPXOR 64(SI), Y14, Y14
+ VPXOR 96(SI), Y12, Y12
+ VMOVDQU Y15, (DI)
+ VMOVDQU Y0, 32(DI)
+ VMOVDQU Y14, 64(DI)
+ VMOVDQU Y12, 96(DI)
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ VPXOR 128(SI), Y0, Y0
+ VPXOR 160(SI), Y14, Y14
+ VPXOR 192(SI), Y12, Y12
+ VPXOR 224(SI), Y4, Y4
+ VMOVDQU Y0, 128(DI)
+ VMOVDQU Y14, 160(DI)
+ VMOVDQU Y12, 192(DI)
+ VMOVDQU Y4, 224(DI)
+ VPERM2I128 $0x02, Y6, Y10, Y0
+ VPERM2I128 $0x02, Y8, Y2, Y14
+ VPERM2I128 $0x13, Y6, Y10, Y12
+ VPERM2I128 $0x13, Y8, Y2, Y4
+ VPXOR 256(SI), Y0, Y0
+ VPXOR 288(SI), Y14, Y14
+ VPXOR 320(SI), Y12, Y12
+ VPXOR 352(SI), Y4, Y4
+ VMOVDQU Y0, 256(DI)
+ VMOVDQU Y14, 288(DI)
+ VMOVDQU Y12, 320(DI)
+ VMOVDQU Y4, 352(DI)
+ VPERM2I128 $0x02, Y7, Y11, Y0
+ VPERM2I128 $0x02, 224(BP), Y3, Y14
+ VPERM2I128 $0x13, Y7, Y11, Y12
+ VPERM2I128 $0x13, 224(BP), Y3, Y4
+ LEAQ 384(SI), SI
+ LEAQ 384(DI), DI
+ SUBQ $0x00000180, BX
+ JMP openAVX2TailLoop
+
+DATA ·chacha20Constants<>+0(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+4(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+8(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+12(SB)/4, $0x6b206574
+DATA ·chacha20Constants<>+16(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+20(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+24(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+28(SB)/4, $0x6b206574
+GLOBL ·chacha20Constants<>(SB), RODATA|NOPTR, $32
+
+DATA ·avx2InitMask<>+0(SB)/8, $0x0000000000000000
+DATA ·avx2InitMask<>+8(SB)/8, $0x0000000000000000
+DATA ·avx2InitMask<>+16(SB)/8, $0x0000000000000001
+DATA ·avx2InitMask<>+24(SB)/8, $0x0000000000000000
+GLOBL ·avx2InitMask<>(SB), RODATA|NOPTR, $32
+
+DATA ·rol16<>+0(SB)/8, $0x0504070601000302
+DATA ·rol16<>+8(SB)/8, $0x0d0c0f0e09080b0a
+DATA ·rol16<>+16(SB)/8, $0x0504070601000302
+DATA ·rol16<>+24(SB)/8, $0x0d0c0f0e09080b0a
+GLOBL ·rol16<>(SB), RODATA|NOPTR, $32
+
+DATA ·rol8<>+0(SB)/8, $0x0605040702010003
+DATA ·rol8<>+8(SB)/8, $0x0e0d0c0f0a09080b
+DATA ·rol8<>+16(SB)/8, $0x0605040702010003
+DATA ·rol8<>+24(SB)/8, $0x0e0d0c0f0a09080b
+GLOBL ·rol8<>(SB), RODATA|NOPTR, $32
+
+DATA ·polyClampMask<>+0(SB)/8, $0x0ffffffc0fffffff
+DATA ·polyClampMask<>+8(SB)/8, $0x0ffffffc0ffffffc
+DATA ·polyClampMask<>+16(SB)/8, $0xffffffffffffffff
+DATA ·polyClampMask<>+24(SB)/8, $0xffffffffffffffff
+GLOBL ·polyClampMask<>(SB), RODATA|NOPTR, $32
+
+DATA ·avx2IncMask<>+0(SB)/8, $0x0000000000000002
+DATA ·avx2IncMask<>+8(SB)/8, $0x0000000000000000
+DATA ·avx2IncMask<>+16(SB)/8, $0x0000000000000002
+DATA ·avx2IncMask<>+24(SB)/8, $0x0000000000000000
+GLOBL ·avx2IncMask<>(SB), RODATA|NOPTR, $32
+
+DATA ·andMask<>+0(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+8(SB)/8, $0x0000000000000000
+DATA ·andMask<>+16(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+24(SB)/8, $0x0000000000000000
+DATA ·andMask<>+32(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+40(SB)/8, $0x0000000000000000
+DATA ·andMask<>+48(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+56(SB)/8, $0x0000000000000000
+DATA ·andMask<>+64(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+72(SB)/8, $0x0000000000000000
+DATA ·andMask<>+80(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+88(SB)/8, $0x0000000000000000
+DATA ·andMask<>+96(SB)/8, $0x00ffffffffffffff
+DATA ·andMask<>+104(SB)/8, $0x0000000000000000
+DATA ·andMask<>+112(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+120(SB)/8, $0x0000000000000000
+DATA ·andMask<>+128(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+136(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+144(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+152(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+160(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+168(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+176(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+184(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+192(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+200(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+208(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+216(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+224(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+232(SB)/8, $0x00ffffffffffffff
+GLOBL ·andMask<>(SB), RODATA|NOPTR, $240
+
+// func chacha20Poly1305Seal(dst []byte, key []uint32, src []byte, ad []byte)
+// Requires: AVX, AVX2, BMI2, CMOV, SSE2
+TEXT ·chacha20Poly1305Seal(SB), $288-96
+ MOVQ SP, BP
+ ADDQ $0x20, BP
+ ANDQ $-32, BP
+ MOVQ dst_base+0(FP), DI
+ MOVQ key_base+24(FP), R8
+ MOVQ src_base+48(FP), SI
+ MOVQ src_len+56(FP), BX
+ MOVQ ad_base+72(FP), CX
+ VZEROUPPER
+ VMOVDQU ·chacha20Constants<>+0(SB), Y0
+ VBROADCASTI128 16(R8), Y14
+ VBROADCASTI128 32(R8), Y12
+ VBROADCASTI128 48(R8), Y4
+ VPADDD ·avx2InitMask<>+0(SB), Y4, Y4
+
+ // Special optimizations, for very short buffers
+ CMPQ BX, $0x000000c0
+ JBE seal192AVX2
+ CMPQ BX, $0x00000140
+ JBE seal320AVX2
+
+ // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA Y0, Y7
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA Y14, Y11
+ VMOVDQA Y14, 32(BP)
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA Y12, Y15
+ VMOVDQA Y12, 64(BP)
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VMOVDQA Y4, 96(BP)
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VMOVDQA Y1, 128(BP)
+ VPADDD ·avx2IncMask<>+0(SB), Y2, Y3
+ VMOVDQA Y2, 160(BP)
+ VMOVDQA Y3, 192(BP)
+ MOVQ $0x0000000a, R9
+
+sealAVX2IntroLoop:
+ VMOVDQA Y15, 224(BP)
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VMOVDQA 224(BP), Y15
+ VMOVDQA Y13, 224(BP)
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x0c, Y11, Y13
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x07, Y11, Y13
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VMOVDQA 224(BP), Y13
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPALIGNR $0x04, Y11, Y11, Y11
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x0c, Y3, Y3, Y3
+ VMOVDQA Y15, 224(BP)
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VMOVDQA 224(BP), Y15
+ VMOVDQA Y13, 224(BP)
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x0c, Y11, Y13
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x07, Y11, Y13
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VMOVDQA 224(BP), Y13
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x04, Y2, Y2, Y2
+ VPALIGNR $0x0c, Y11, Y11, Y11
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x04, Y3, Y3, Y3
+ DECQ R9
+ JNE sealAVX2IntroLoop
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD ·chacha20Constants<>+0(SB), Y6, Y6
+ VPADDD ·chacha20Constants<>+0(SB), Y7, Y7
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 32(BP), Y10, Y10
+ VPADDD 32(BP), Y11, Y11
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD 64(BP), Y8, Y8
+ VPADDD 64(BP), Y15, Y15
+ VPADDD 96(BP), Y4, Y4
+ VPADDD 128(BP), Y1, Y1
+ VPADDD 160(BP), Y2, Y2
+ VPADDD 192(BP), Y3, Y3
+ VPERM2I128 $0x13, Y12, Y4, Y12
+ VPERM2I128 $0x02, Y0, Y14, Y4
+ VPERM2I128 $0x13, Y0, Y14, Y0
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>+0(SB), Y4, Y4
+ VMOVDQA Y4, (BP)
+
+ // Hash AD
+ MOVQ ad_len+80(FP), R9
+ CALL polyHashADInternal<>(SB)
+
+ // Can store at least 320 bytes
+ VPXOR (SI), Y0, Y0
+ VPXOR 32(SI), Y12, Y12
+ VMOVDQU Y0, (DI)
+ VMOVDQU Y12, 32(DI)
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ VPXOR 64(SI), Y0, Y0
+ VPXOR 96(SI), Y14, Y14
+ VPXOR 128(SI), Y12, Y12
+ VPXOR 160(SI), Y4, Y4
+ VMOVDQU Y0, 64(DI)
+ VMOVDQU Y14, 96(DI)
+ VMOVDQU Y12, 128(DI)
+ VMOVDQU Y4, 160(DI)
+ VPERM2I128 $0x02, Y6, Y10, Y0
+ VPERM2I128 $0x02, Y8, Y2, Y14
+ VPERM2I128 $0x13, Y6, Y10, Y12
+ VPERM2I128 $0x13, Y8, Y2, Y4
+ VPXOR 192(SI), Y0, Y0
+ VPXOR 224(SI), Y14, Y14
+ VPXOR 256(SI), Y12, Y12
+ VPXOR 288(SI), Y4, Y4
+ VMOVDQU Y0, 192(DI)
+ VMOVDQU Y14, 224(DI)
+ VMOVDQU Y12, 256(DI)
+ VMOVDQU Y4, 288(DI)
+ MOVQ $0x00000140, CX
+ SUBQ $0x00000140, BX
+ LEAQ 320(SI), SI
+ VPERM2I128 $0x02, Y7, Y11, Y0
+ VPERM2I128 $0x02, Y15, Y3, Y14
+ VPERM2I128 $0x13, Y7, Y11, Y12
+ VPERM2I128 $0x13, Y15, Y3, Y4
+ CMPQ BX, $0x80
+ JBE sealAVX2SealHash
+ VPXOR (SI), Y0, Y0
+ VPXOR 32(SI), Y14, Y14
+ VPXOR 64(SI), Y12, Y12
+ VPXOR 96(SI), Y4, Y4
+ VMOVDQU Y0, 320(DI)
+ VMOVDQU Y14, 352(DI)
+ VMOVDQU Y12, 384(DI)
+ VMOVDQU Y4, 416(DI)
+ SUBQ $0x80, BX
+ LEAQ 128(SI), SI
+ MOVQ $0x00000008, CX
+ MOVQ $0x00000002, R9
+ CMPQ BX, $0x80
+ JBE sealAVX2Tail128
+ CMPQ BX, $0x00000100
+ JBE sealAVX2Tail256
+ CMPQ BX, $0x00000180
+ JBE sealAVX2Tail384
+ CMPQ BX, $0x00000200
+ JBE sealAVX2Tail512
+
+ // We have 448 bytes to hash, but main loop hashes 512 bytes at a time - perform some rounds, before the main loop
+ VMOVDQA ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA Y0, Y7
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA Y14, Y11
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA Y12, Y15
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VPADDD ·avx2IncMask<>+0(SB), Y2, Y3
+ VMOVDQA Y4, 96(BP)
+ VMOVDQA Y1, 128(BP)
+ VMOVDQA Y2, 160(BP)
+ VMOVDQA Y3, 192(BP)
+ VMOVDQA Y15, 224(BP)
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VMOVDQA 224(BP), Y15
+ VMOVDQA Y13, 224(BP)
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x0c, Y11, Y13
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x07, Y11, Y13
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VMOVDQA 224(BP), Y13
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPALIGNR $0x04, Y11, Y11, Y11
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x0c, Y3, Y3, Y3
+ VMOVDQA Y15, 224(BP)
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VMOVDQA 224(BP), Y15
+ VMOVDQA Y13, 224(BP)
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x0c, Y11, Y13
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VPADDD Y11, Y7, Y7
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y3, Y15, Y15
+ VPXOR Y15, Y11, Y11
+ VPSLLD $0x07, Y11, Y13
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y13, Y11, Y11
+ VMOVDQA 224(BP), Y13
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x04, Y2, Y2, Y2
+ VPALIGNR $0x0c, Y11, Y11, Y11
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x04, Y3, Y3, Y3
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ SUBQ $0x10, DI
+ MOVQ $0x00000009, CX
+ JMP sealAVX2InternalLoopStart
+
+sealAVX2MainLoop:
+ VMOVDQU ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA Y0, Y7
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA Y14, Y11
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA Y12, Y15
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VPADDD ·avx2IncMask<>+0(SB), Y2, Y3
+ VMOVDQA Y4, 96(BP)
+ VMOVDQA Y1, 128(BP)
+ VMOVDQA Y2, 160(BP)
+ VMOVDQA Y3, 192(BP)
+ MOVQ $0x0000000a, CX
+
+sealAVX2InternalLoop:
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+
+sealAVX2InternalLoopStart:
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ ADDQ 16(DI), R10
+ ADCQ 24(DI), R11
+ ADCQ $0x01, R12
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x04, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPALIGNR $0x0c, Y3, Y3, Y3
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ ADDQ 32(DI), R10
+ ADCQ 40(DI), R11
+ ADCQ $0x01, R12
+ LEAQ 48(DI), DI
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x0c, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ VPALIGNR $0x04, Y3, Y3, Y3
+ DECQ CX
+ JNE sealAVX2InternalLoop
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD ·chacha20Constants<>+0(SB), Y6, Y6
+ VPADDD ·chacha20Constants<>+0(SB), Y7, Y7
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 32(BP), Y10, Y10
+ VPADDD 32(BP), Y11, Y11
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD 64(BP), Y8, Y8
+ VPADDD 64(BP), Y15, Y15
+ VPADDD 96(BP), Y4, Y4
+ VPADDD 128(BP), Y1, Y1
+ VPADDD 160(BP), Y2, Y2
+ VPADDD 192(BP), Y3, Y3
+ VMOVDQA Y15, 224(BP)
+
+ // We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(DI), DI
+ VPERM2I128 $0x02, Y0, Y14, Y15
+ VPERM2I128 $0x13, Y0, Y14, Y14
+ VPERM2I128 $0x02, Y12, Y4, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y12
+ VPXOR (SI), Y15, Y15
+ VPXOR 32(SI), Y0, Y0
+ VPXOR 64(SI), Y14, Y14
+ VPXOR 96(SI), Y12, Y12
+ VMOVDQU Y15, (DI)
+ VMOVDQU Y0, 32(DI)
+ VMOVDQU Y14, 64(DI)
+ VMOVDQU Y12, 96(DI)
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ VPXOR 128(SI), Y0, Y0
+ VPXOR 160(SI), Y14, Y14
+ VPXOR 192(SI), Y12, Y12
+ VPXOR 224(SI), Y4, Y4
+ VMOVDQU Y0, 128(DI)
+ VMOVDQU Y14, 160(DI)
+ VMOVDQU Y12, 192(DI)
+ VMOVDQU Y4, 224(DI)
+
+ // and here
+ ADDQ -16(DI), R10
+ ADCQ -8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPERM2I128 $0x02, Y6, Y10, Y0
+ VPERM2I128 $0x02, Y8, Y2, Y14
+ VPERM2I128 $0x13, Y6, Y10, Y12
+ VPERM2I128 $0x13, Y8, Y2, Y4
+ VPXOR 256(SI), Y0, Y0
+ VPXOR 288(SI), Y14, Y14
+ VPXOR 320(SI), Y12, Y12
+ VPXOR 352(SI), Y4, Y4
+ VMOVDQU Y0, 256(DI)
+ VMOVDQU Y14, 288(DI)
+ VMOVDQU Y12, 320(DI)
+ VMOVDQU Y4, 352(DI)
+ VPERM2I128 $0x02, Y7, Y11, Y0
+ VPERM2I128 $0x02, 224(BP), Y3, Y14
+ VPERM2I128 $0x13, Y7, Y11, Y12
+ VPERM2I128 $0x13, 224(BP), Y3, Y4
+ VPXOR 384(SI), Y0, Y0
+ VPXOR 416(SI), Y14, Y14
+ VPXOR 448(SI), Y12, Y12
+ VPXOR 480(SI), Y4, Y4
+ VMOVDQU Y0, 384(DI)
+ VMOVDQU Y14, 416(DI)
+ VMOVDQU Y12, 448(DI)
+ VMOVDQU Y4, 480(DI)
+ LEAQ 512(SI), SI
+ SUBQ $0x00000200, BX
+ CMPQ BX, $0x00000200
+ JG sealAVX2MainLoop
+
+ // Tail can only hash 480 bytes
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ ADDQ 16(DI), R10
+ ADCQ 24(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(DI), DI
+ MOVQ $0x0000000a, CX
+ MOVQ $0x00000000, R9
+ CMPQ BX, $0x80
+ JBE sealAVX2Tail128
+ CMPQ BX, $0x00000100
+ JBE sealAVX2Tail256
+ CMPQ BX, $0x00000180
+ JBE sealAVX2Tail384
+ JMP sealAVX2Tail512
+
+sealSSETail:
+ TESTQ BX, BX
+ JE sealSSEFinalize
+
+ // We can only load the PT one byte at a time to avoid read after end of buffer
+ MOVQ BX, R9
+ SHLQ $0x04, R9
+ LEAQ ·andMask<>+0(SB), R13
+ MOVQ BX, CX
+ LEAQ -1(SI)(BX*1), SI
+ XORQ R15, R15
+ XORQ R8, R8
+ XORQ AX, AX
+
+sealSSETailLoadLoop:
+ SHLQ $0x08, R15, R8
+ SHLQ $0x08, R15
+ MOVB (SI), AX
+ XORQ AX, R15
+ LEAQ -1(SI), SI
+ DECQ CX
+ JNE sealSSETailLoadLoop
+ MOVQ R15, 64(BP)
+ MOVQ R8, 72(BP)
+ PXOR 64(BP), X1
+ MOVOU X1, (DI)
+ MOVOU -16(R13)(R9*1), X12
+ PAND X12, X1
+ MOVQ X1, R13
+ PSRLDQ $0x08, X1
+ MOVQ X1, R14
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ ADDQ BX, DI
+
+sealSSEFinalize:
+ // Hash in the buffer lengths
+ ADDQ ad_len+80(FP), R10
+ ADCQ src_len+56(FP), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+
+ // Final reduce
+ MOVQ R10, R13
+ MOVQ R11, R14
+ MOVQ R12, R15
+ SUBQ $-5, R10
+ SBBQ $-1, R11
+ SBBQ $0x03, R12
+ CMOVQCS R13, R10
+ CMOVQCS R14, R11
+ CMOVQCS R15, R12
+
+ // Add in the "s" part of the key
+ ADDQ 16(BP), R10
+ ADCQ 24(BP), R11
+
+ // Finally store the tag at the end of the message
+ MOVQ R10, (DI)
+ MOVQ R11, 8(DI)
+ RET
+
+seal192AVX2:
+ VMOVDQA Y0, Y5
+ VMOVDQA Y14, Y9
+ VMOVDQA Y12, Y13
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VMOVDQA Y0, Y6
+ VMOVDQA Y14, Y10
+ VMOVDQA Y12, Y8
+ VMOVDQA Y4, Y2
+ VMOVDQA Y1, Y15
+ MOVQ $0x0000000a, R9
+
+sealAVX2192InnerCipherLoop:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ DECQ R9
+ JNE sealAVX2192InnerCipherLoop
+ VPADDD Y6, Y0, Y0
+ VPADDD Y6, Y5, Y5
+ VPADDD Y10, Y14, Y14
+ VPADDD Y10, Y9, Y9
+ VPADDD Y8, Y12, Y12
+ VPADDD Y8, Y13, Y13
+ VPADDD Y2, Y4, Y4
+ VPADDD Y15, Y1, Y1
+ VPERM2I128 $0x02, Y0, Y14, Y3
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>+0(SB), Y3, Y3
+ VMOVDQA Y3, (BP)
+
+ // Stream for up to 192 bytes
+ VPERM2I128 $0x13, Y0, Y14, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y14
+ VPERM2I128 $0x02, Y5, Y9, Y12
+ VPERM2I128 $0x02, Y13, Y1, Y4
+ VPERM2I128 $0x13, Y5, Y9, Y5
+ VPERM2I128 $0x13, Y13, Y1, Y9
+
+sealAVX2ShortSeal:
+ // Hash aad
+ MOVQ ad_len+80(FP), R9
+ CALL polyHashADInternal<>(SB)
+ XORQ CX, CX
+
+sealAVX2SealHash:
+ // itr1 holds the number of bytes encrypted but not yet hashed
+ CMPQ CX, $0x10
+ JB sealAVX2ShortSealLoop
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ SUBQ $0x10, CX
+ ADDQ $0x10, DI
+ JMP sealAVX2SealHash
+
+sealAVX2ShortSealLoop:
+ CMPQ BX, $0x20
+ JB sealAVX2ShortTail32
+ SUBQ $0x20, BX
+
+ // Load for encryption
+ VPXOR (SI), Y0, Y0
+ VMOVDQU Y0, (DI)
+ LEAQ 32(SI), SI
+
+ // Now can hash
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ ADDQ 16(DI), R10
+ ADCQ 24(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(DI), DI
+
+ // Shift stream left
+ VMOVDQA Y14, Y0
+ VMOVDQA Y12, Y14
+ VMOVDQA Y4, Y12
+ VMOVDQA Y5, Y4
+ VMOVDQA Y9, Y5
+ VMOVDQA Y13, Y9
+ VMOVDQA Y1, Y13
+ VMOVDQA Y6, Y1
+ VMOVDQA Y10, Y6
+ JMP sealAVX2ShortSealLoop
+
+sealAVX2ShortTail32:
+ CMPQ BX, $0x10
+ VMOVDQA X0, X1
+ JB sealAVX2ShortDone
+ SUBQ $0x10, BX
+
+ // Load for encryption
+ VPXOR (SI), X0, X12
+ VMOVDQU X12, (DI)
+ LEAQ 16(SI), SI
+
+ // Hash
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(DI), DI
+ VPERM2I128 $0x11, Y0, Y0, Y0
+ VMOVDQA X0, X1
+
+sealAVX2ShortDone:
+ VZEROUPPER
+ JMP sealSSETail
+
+seal320AVX2:
+ VMOVDQA Y0, Y5
+ VMOVDQA Y14, Y9
+ VMOVDQA Y12, Y13
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VMOVDQA Y0, Y6
+ VMOVDQA Y14, Y10
+ VMOVDQA Y12, Y8
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VMOVDQA Y14, Y7
+ VMOVDQA Y12, Y11
+ VMOVDQA Y4, Y15
+ MOVQ $0x0000000a, R9
+
+sealAVX2320InnerCipherLoop:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ DECQ R9
+ JNE sealAVX2320InnerCipherLoop
+ VMOVDQA ·chacha20Constants<>+0(SB), Y3
+ VPADDD Y3, Y0, Y0
+ VPADDD Y3, Y5, Y5
+ VPADDD Y3, Y6, Y6
+ VPADDD Y7, Y14, Y14
+ VPADDD Y7, Y9, Y9
+ VPADDD Y7, Y10, Y10
+ VPADDD Y11, Y12, Y12
+ VPADDD Y11, Y13, Y13
+ VPADDD Y11, Y8, Y8
+ VMOVDQA ·avx2IncMask<>+0(SB), Y3
+ VPADDD Y15, Y4, Y4
+ VPADDD Y3, Y15, Y15
+ VPADDD Y15, Y1, Y1
+ VPADDD Y3, Y15, Y15
+ VPADDD Y15, Y2, Y2
+
+ // Clamp and store poly key
+ VPERM2I128 $0x02, Y0, Y14, Y3
+ VPAND ·polyClampMask<>+0(SB), Y3, Y3
+ VMOVDQA Y3, (BP)
+
+ // Stream for up to 320 bytes
+ VPERM2I128 $0x13, Y0, Y14, Y0
+ VPERM2I128 $0x13, Y12, Y4, Y14
+ VPERM2I128 $0x02, Y5, Y9, Y12
+ VPERM2I128 $0x02, Y13, Y1, Y4
+ VPERM2I128 $0x13, Y5, Y9, Y5
+ VPERM2I128 $0x13, Y13, Y1, Y9
+ VPERM2I128 $0x02, Y6, Y10, Y13
+ VPERM2I128 $0x02, Y8, Y2, Y1
+ VPERM2I128 $0x13, Y6, Y10, Y6
+ VPERM2I128 $0x13, Y8, Y2, Y10
+ JMP sealAVX2ShortSeal
+
+sealAVX2Tail128:
+ VMOVDQA ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA 32(BP), Y14
+ VMOVDQA 64(BP), Y12
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VMOVDQA Y4, Y1
+
+sealAVX2Tail128LoopA:
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(DI), DI
+
+sealAVX2Tail128LoopB:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ ADDQ 16(DI), R10
+ ADCQ 24(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(DI), DI
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x04, Y4, Y4, Y4
+ DECQ CX
+ JG sealAVX2Tail128LoopA
+ DECQ R9
+ JGE sealAVX2Tail128LoopB
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y5
+ VPADDD 32(BP), Y14, Y9
+ VPADDD 64(BP), Y12, Y13
+ VPADDD Y1, Y4, Y1
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ JMP sealAVX2ShortSealLoop
+
+sealAVX2Tail256:
+ VMOVDQA ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA ·chacha20Constants<>+0(SB), Y5
+ VMOVDQA 32(BP), Y14
+ VMOVDQA 32(BP), Y9
+ VMOVDQA 64(BP), Y12
+ VMOVDQA 64(BP), Y13
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VMOVDQA Y4, Y7
+ VMOVDQA Y1, Y11
+
+sealAVX2Tail256LoopA:
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(DI), DI
+
+sealAVX2Tail256LoopB:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ ADDQ 16(DI), R10
+ ADCQ 24(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(DI), DI
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ DECQ CX
+ JG sealAVX2Tail256LoopA
+ DECQ R9
+ JGE sealAVX2Tail256LoopB
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD Y7, Y4, Y4
+ VPADDD Y11, Y1, Y1
+ VPERM2I128 $0x02, Y0, Y14, Y3
+ VPERM2I128 $0x02, Y12, Y4, Y7
+ VPERM2I128 $0x13, Y0, Y14, Y11
+ VPERM2I128 $0x13, Y12, Y4, Y15
+ VPXOR (SI), Y3, Y3
+ VPXOR 32(SI), Y7, Y7
+ VPXOR 64(SI), Y11, Y11
+ VPXOR 96(SI), Y15, Y15
+ VMOVDQU Y3, (DI)
+ VMOVDQU Y7, 32(DI)
+ VMOVDQU Y11, 64(DI)
+ VMOVDQU Y15, 96(DI)
+ MOVQ $0x00000080, CX
+ LEAQ 128(SI), SI
+ SUBQ $0x80, BX
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ JMP sealAVX2SealHash
+
+sealAVX2Tail384:
+ VMOVDQA ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VMOVDQA Y4, Y7
+ VMOVDQA Y1, Y11
+ VMOVDQA Y2, Y15
+
+sealAVX2Tail384LoopA:
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(DI), DI
+
+sealAVX2Tail384LoopB:
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x0c, Y14, Y3
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y14, Y0, Y0
+ VPXOR Y0, Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPADDD Y4, Y12, Y12
+ VPXOR Y12, Y14, Y14
+ VPSLLD $0x07, Y14, Y3
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y3, Y14, Y14
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x0c, Y9, Y3
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y9, Y5, Y5
+ VPXOR Y5, Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPADDD Y1, Y13, Y13
+ VPXOR Y13, Y9, Y9
+ VPSLLD $0x07, Y9, Y3
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y3, Y9, Y9
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x0c, Y10, Y3
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ VPADDD Y10, Y6, Y6
+ VPXOR Y6, Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPADDD Y2, Y8, Y8
+ VPXOR Y8, Y10, Y10
+ VPSLLD $0x07, Y10, Y3
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y3, Y10, Y10
+ ADDQ 16(DI), R10
+ ADCQ 24(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(DI), DI
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ DECQ CX
+ JG sealAVX2Tail384LoopA
+ DECQ R9
+ JGE sealAVX2Tail384LoopB
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD ·chacha20Constants<>+0(SB), Y6, Y6
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 32(BP), Y10, Y10
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD 64(BP), Y8, Y8
+ VPADDD Y7, Y4, Y4
+ VPADDD Y11, Y1, Y1
+ VPADDD Y15, Y2, Y2
+ VPERM2I128 $0x02, Y0, Y14, Y3
+ VPERM2I128 $0x02, Y12, Y4, Y7
+ VPERM2I128 $0x13, Y0, Y14, Y11
+ VPERM2I128 $0x13, Y12, Y4, Y15
+ VPXOR (SI), Y3, Y3
+ VPXOR 32(SI), Y7, Y7
+ VPXOR 64(SI), Y11, Y11
+ VPXOR 96(SI), Y15, Y15
+ VMOVDQU Y3, (DI)
+ VMOVDQU Y7, 32(DI)
+ VMOVDQU Y11, 64(DI)
+ VMOVDQU Y15, 96(DI)
+ VPERM2I128 $0x02, Y5, Y9, Y3
+ VPERM2I128 $0x02, Y13, Y1, Y7
+ VPERM2I128 $0x13, Y5, Y9, Y11
+ VPERM2I128 $0x13, Y13, Y1, Y15
+ VPXOR 128(SI), Y3, Y3
+ VPXOR 160(SI), Y7, Y7
+ VPXOR 192(SI), Y11, Y11
+ VPXOR 224(SI), Y15, Y15
+ VMOVDQU Y3, 128(DI)
+ VMOVDQU Y7, 160(DI)
+ VMOVDQU Y11, 192(DI)
+ VMOVDQU Y15, 224(DI)
+ MOVQ $0x00000100, CX
+ LEAQ 256(SI), SI
+ SUBQ $0x00000100, BX
+ VPERM2I128 $0x02, Y6, Y10, Y0
+ VPERM2I128 $0x02, Y8, Y2, Y14
+ VPERM2I128 $0x13, Y6, Y10, Y12
+ VPERM2I128 $0x13, Y8, Y2, Y4
+ JMP sealAVX2SealHash
+
+sealAVX2Tail512:
+ VMOVDQA ·chacha20Constants<>+0(SB), Y0
+ VMOVDQA Y0, Y5
+ VMOVDQA Y0, Y6
+ VMOVDQA Y0, Y7
+ VMOVDQA 32(BP), Y14
+ VMOVDQA Y14, Y9
+ VMOVDQA Y14, Y10
+ VMOVDQA Y14, Y11
+ VMOVDQA 64(BP), Y12
+ VMOVDQA Y12, Y13
+ VMOVDQA Y12, Y8
+ VMOVDQA Y12, Y15
+ VMOVDQA 192(BP), Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y4
+ VPADDD ·avx2IncMask<>+0(SB), Y4, Y1
+ VPADDD ·avx2IncMask<>+0(SB), Y1, Y2
+ VPADDD ·avx2IncMask<>+0(SB), Y2, Y3
+ VMOVDQA Y4, 96(BP)
+ VMOVDQA Y1, 128(BP)
+ VMOVDQA Y2, 160(BP)
+ VMOVDQA Y3, 192(BP)
+
+sealAVX2Tail512LoopA:
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), AX
+ MOVQ AX, R15
+ MULQ R10
+ MOVQ AX, R13
+ MOVQ DX, R14
+ MOVQ (BP), AX
+ MULQ R11
+ IMULQ R12, R15
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), AX
+ MOVQ AX, R8
+ MULQ R10
+ ADDQ AX, R14
+ ADCQ $0x00, DX
+ MOVQ DX, R10
+ MOVQ 8(BP), AX
+ MULQ R11
+ ADDQ AX, R15
+ ADCQ $0x00, DX
+ IMULQ R12, R8
+ ADDQ R10, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 16(DI), DI
+
+sealAVX2Tail512LoopB:
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ ADDQ (DI), R10
+ ADCQ 8(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ VPALIGNR $0x04, Y14, Y14, Y14
+ VPALIGNR $0x04, Y9, Y9, Y9
+ VPALIGNR $0x04, Y10, Y10, Y10
+ VPALIGNR $0x04, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x0c, Y4, Y4, Y4
+ VPALIGNR $0x0c, Y1, Y1, Y1
+ VPALIGNR $0x0c, Y2, Y2, Y2
+ VPALIGNR $0x0c, Y3, Y3, Y3
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol16<>+0(SB), Y4, Y4
+ VPSHUFB ·rol16<>+0(SB), Y1, Y1
+ VPSHUFB ·rol16<>+0(SB), Y2, Y2
+ VPSHUFB ·rol16<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ ADDQ 16(DI), R10
+ ADCQ 24(DI), R11
+ ADCQ $0x01, R12
+ MOVQ (BP), DX
+ MOVQ DX, R15
+ MULXQ R10, R13, R14
+ IMULQ R12, R15
+ MULXQ R11, AX, DX
+ ADDQ AX, R14
+ ADCQ DX, R15
+ MOVQ 8(BP), DX
+ MULXQ R10, R10, AX
+ ADDQ R10, R14
+ MULXQ R11, R11, R8
+ ADCQ R11, R15
+ ADCQ $0x00, R8
+ IMULQ R12, DX
+ ADDQ AX, R15
+ ADCQ DX, R8
+ MOVQ R13, R10
+ MOVQ R14, R11
+ MOVQ R15, R12
+ ANDQ $0x03, R12
+ MOVQ R15, R13
+ ANDQ $-4, R13
+ MOVQ R8, R14
+ SHRQ $0x02, R8, R15
+ SHRQ $0x02, R8
+ ADDQ R13, R10
+ ADCQ R14, R11
+ ADCQ $0x00, R12
+ ADDQ R15, R10
+ ADCQ R8, R11
+ ADCQ $0x00, R12
+ LEAQ 32(DI), DI
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x0c, Y14, Y15
+ VPSRLD $0x14, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x0c, Y9, Y15
+ VPSRLD $0x14, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x0c, Y10, Y15
+ VPSRLD $0x14, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x0c, Y11, Y15
+ VPSRLD $0x14, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ VPADDD Y14, Y0, Y0
+ VPADDD Y9, Y5, Y5
+ VPADDD Y10, Y6, Y6
+ VPADDD Y11, Y7, Y7
+ VPXOR Y0, Y4, Y4
+ VPXOR Y5, Y1, Y1
+ VPXOR Y6, Y2, Y2
+ VPXOR Y7, Y3, Y3
+ VPSHUFB ·rol8<>+0(SB), Y4, Y4
+ VPSHUFB ·rol8<>+0(SB), Y1, Y1
+ VPSHUFB ·rol8<>+0(SB), Y2, Y2
+ VPSHUFB ·rol8<>+0(SB), Y3, Y3
+ VPADDD Y4, Y12, Y12
+ VPADDD Y1, Y13, Y13
+ VPADDD Y2, Y8, Y8
+ VPADDD Y3, Y15, Y15
+ VPXOR Y12, Y14, Y14
+ VPXOR Y13, Y9, Y9
+ VPXOR Y8, Y10, Y10
+ VPXOR Y15, Y11, Y11
+ VMOVDQA Y15, 224(BP)
+ VPSLLD $0x07, Y14, Y15
+ VPSRLD $0x19, Y14, Y14
+ VPXOR Y15, Y14, Y14
+ VPSLLD $0x07, Y9, Y15
+ VPSRLD $0x19, Y9, Y9
+ VPXOR Y15, Y9, Y9
+ VPSLLD $0x07, Y10, Y15
+ VPSRLD $0x19, Y10, Y10
+ VPXOR Y15, Y10, Y10
+ VPSLLD $0x07, Y11, Y15
+ VPSRLD $0x19, Y11, Y11
+ VPXOR Y15, Y11, Y11
+ VMOVDQA 224(BP), Y15
+ VPALIGNR $0x0c, Y14, Y14, Y14
+ VPALIGNR $0x0c, Y9, Y9, Y9
+ VPALIGNR $0x0c, Y10, Y10, Y10
+ VPALIGNR $0x0c, Y11, Y11, Y11
+ VPALIGNR $0x08, Y12, Y12, Y12
+ VPALIGNR $0x08, Y13, Y13, Y13
+ VPALIGNR $0x08, Y8, Y8, Y8
+ VPALIGNR $0x08, Y15, Y15, Y15
+ VPALIGNR $0x04, Y4, Y4, Y4
+ VPALIGNR $0x04, Y1, Y1, Y1
+ VPALIGNR $0x04, Y2, Y2, Y2
+ VPALIGNR $0x04, Y3, Y3, Y3
+ DECQ CX
+ JG sealAVX2Tail512LoopA
+ DECQ R9
+ JGE sealAVX2Tail512LoopB
+ VPADDD ·chacha20Constants<>+0(SB), Y0, Y0
+ VPADDD ·chacha20Constants<>+0(SB), Y5, Y5
+ VPADDD ·chacha20Constants<>+0(SB), Y6, Y6
+ VPADDD ·chacha20Constants<>+0(SB), Y7, Y7
+ VPADDD 32(BP), Y14, Y14
+ VPADDD 32(BP), Y9, Y9
+ VPADDD 32(BP), Y10, Y10
+ VPADDD 32(BP), Y11, Y11
+ VPADDD 64(BP), Y12, Y12
+ VPADDD 64(BP), Y13, Y13
+ VPADDD 64(BP), Y8, Y8
+ VPADDD 64(BP), Y15, Y15
+ VPADDD 96(BP), Y4, Y4
+ VPADDD 128(BP), Y1, Y1
+ VPADDD 160(BP), Y2, Y2
+ VPADDD 192(BP), Y3, Y3
+ VMOVDQA Y15, 224(BP)
+ VPERM2I128 $0x02, Y0, Y14, Y15
+ VPXOR (SI), Y15, Y15
+ VMOVDQU Y15, (DI)
+ VPERM2I128 $0x02, Y12, Y4, Y15
+ VPXOR 32(SI), Y15, Y15
+ VMOVDQU Y15, 32(DI)
+ VPERM2I128 $0x13, Y0, Y14, Y15
+ VPXOR 64(SI), Y15, Y15
+ VMOVDQU Y15, 64(DI)
+ VPERM2I128 $0x13, Y12, Y4, Y15
+ VPXOR 96(SI), Y15, Y15
+ VMOVDQU Y15, 96(DI)
+ VPERM2I128 $0x02, Y5, Y9, Y0
+ VPERM2I128 $0x02, Y13, Y1, Y14
+ VPERM2I128 $0x13, Y5, Y9, Y12
+ VPERM2I128 $0x13, Y13, Y1, Y4
+ VPXOR 128(SI), Y0, Y0
+ VPXOR 160(SI), Y14, Y14
+ VPXOR 192(SI), Y12, Y12
+ VPXOR 224(SI), Y4, Y4
+ VMOVDQU Y0, 128(DI)
+ VMOVDQU Y14, 160(DI)
+ VMOVDQU Y12, 192(DI)
+ VMOVDQU Y4, 224(DI)
+ VPERM2I128 $0x02, Y6, Y10, Y0
+ VPERM2I128 $0x02, Y8, Y2, Y14
+ VPERM2I128 $0x13, Y6, Y10, Y12
+ VPERM2I128 $0x13, Y8, Y2, Y4
+ VPXOR 256(SI), Y0, Y0
+ VPXOR 288(SI), Y14, Y14
+ VPXOR 320(SI), Y12, Y12
+ VPXOR 352(SI), Y4, Y4
+ VMOVDQU Y0, 256(DI)
+ VMOVDQU Y14, 288(DI)
+ VMOVDQU Y12, 320(DI)
+ VMOVDQU Y4, 352(DI)
+ MOVQ $0x00000180, CX
+ LEAQ 384(SI), SI
+ SUBQ $0x00000180, BX
+ VPERM2I128 $0x02, Y7, Y11, Y0
+ VPERM2I128 $0x02, 224(BP), Y3, Y14
+ VPERM2I128 $0x13, Y7, Y11, Y12
+ VPERM2I128 $0x13, 224(BP), Y3, Y4
+ JMP sealAVX2SealHash
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
new file mode 100644
index 00000000..2ecc840f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
@@ -0,0 +1,87 @@
+// 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 chacha20poly1305
+
+import (
+ "encoding/binary"
+
+ "golang.org/x/crypto/chacha20"
+ "golang.org/x/crypto/internal/alias"
+ "golang.org/x/crypto/internal/poly1305"
+)
+
+func writeWithPadding(p *poly1305.MAC, b []byte) {
+ p.Write(b)
+ if rem := len(b) % 16; rem != 0 {
+ var buf [16]byte
+ padLen := 16 - rem
+ p.Write(buf[:padLen])
+ }
+}
+
+func writeUint64(p *poly1305.MAC, n int) {
+ var buf [8]byte
+ binary.LittleEndian.PutUint64(buf[:], uint64(n))
+ p.Write(buf[:])
+}
+
+func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
+ ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
+ ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
+ if alias.InexactOverlap(out, plaintext) {
+ panic("chacha20poly1305: invalid buffer overlap of output and input")
+ }
+ if alias.AnyOverlap(out, additionalData) {
+ panic("chacha20poly1305: invalid buffer overlap of output and additional data")
+ }
+
+ var polyKey [32]byte
+ s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
+ s.XORKeyStream(polyKey[:], polyKey[:])
+ s.SetCounter(1) // set the counter to 1, skipping 32 bytes
+ s.XORKeyStream(ciphertext, plaintext)
+
+ p := poly1305.New(&polyKey)
+ writeWithPadding(p, additionalData)
+ writeWithPadding(p, ciphertext)
+ writeUint64(p, len(additionalData))
+ writeUint64(p, len(plaintext))
+ p.Sum(tag[:0])
+
+ return ret
+}
+
+func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ tag := ciphertext[len(ciphertext)-16:]
+ ciphertext = ciphertext[:len(ciphertext)-16]
+
+ var polyKey [32]byte
+ s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
+ s.XORKeyStream(polyKey[:], polyKey[:])
+ s.SetCounter(1) // set the counter to 1, skipping 32 bytes
+
+ p := poly1305.New(&polyKey)
+ writeWithPadding(p, additionalData)
+ writeWithPadding(p, ciphertext)
+ writeUint64(p, len(additionalData))
+ writeUint64(p, len(ciphertext))
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if alias.InexactOverlap(out, ciphertext) {
+ panic("chacha20poly1305: invalid buffer overlap of output and input")
+ }
+ if alias.AnyOverlap(out, additionalData) {
+ panic("chacha20poly1305: invalid buffer overlap of output and additional data")
+ }
+ if !p.Verify(tag) {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ s.XORKeyStream(out, ciphertext)
+ return ret, nil
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
new file mode 100644
index 00000000..34e6ab1d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
@@ -0,0 +1,15 @@
+// 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 !amd64 || !gc || purego
+
+package chacha20poly1305
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ return c.sealGeneric(dst, nonce, plaintext, additionalData)
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ return c.openGeneric(dst, nonce, ciphertext, additionalData)
+}
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/fips140only_compat.go b/vendor/golang.org/x/crypto/chacha20poly1305/fips140only_compat.go
new file mode 100644
index 00000000..9b9d5643
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/fips140only_compat.go
@@ -0,0 +1,9 @@
+// Copyright 2025 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 !go1.26
+
+package chacha20poly1305
+
+func fips140Enforced() bool { return false }
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/fips140only_go1.26.go b/vendor/golang.org/x/crypto/chacha20poly1305/fips140only_go1.26.go
new file mode 100644
index 00000000..f71089c4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/fips140only_go1.26.go
@@ -0,0 +1,11 @@
+// Copyright 2025 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 go1.26
+
+package chacha20poly1305
+
+import "crypto/fips140"
+
+func fips140Enforced() bool { return fips140.Enforced() }
diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
new file mode 100644
index 00000000..b4299b71
--- /dev/null
+++ b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go
@@ -0,0 +1,89 @@
+// 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 chacha20poly1305
+
+import (
+ "crypto/cipher"
+ "errors"
+
+ "golang.org/x/crypto/chacha20"
+)
+
+type xchacha20poly1305 struct {
+ key [KeySize]byte
+}
+
+// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
+//
+// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce,
+// suitable to be generated randomly without risk of collisions. It should be
+// preferred when nonce uniqueness cannot be trivially ensured, or whenever
+// nonces are randomly generated.
+func NewX(key []byte) (cipher.AEAD, error) {
+ if fips140Enforced() {
+ return nil, errors.New("chacha20poly1305: use of ChaCha20Poly1305 is not allowed in FIPS 140-only mode")
+ }
+ if len(key) != KeySize {
+ return nil, errors.New("chacha20poly1305: bad key length")
+ }
+ ret := new(xchacha20poly1305)
+ copy(ret.key[:], key)
+ return ret, nil
+}
+
+func (*xchacha20poly1305) NonceSize() int {
+ return NonceSizeX
+}
+
+func (*xchacha20poly1305) Overhead() int {
+ return Overhead
+}
+
+func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if len(nonce) != NonceSizeX {
+ panic("chacha20poly1305: bad nonce length passed to Seal")
+ }
+
+ // XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no
+ // size limit. However, since we reuse the ChaCha20-Poly1305 implementation,
+ // the second half of the counter is not available. This is unlikely to be
+ // an issue because the cipher.AEAD API requires the entire message to be in
+ // memory, and the counter overflows at 256 GB.
+ if uint64(len(plaintext)) > (1<<38)-64 {
+ panic("chacha20poly1305: plaintext too large")
+ }
+
+ c := new(chacha20poly1305)
+ hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
+ copy(c.key[:], hKey)
+
+ // The first 4 bytes of the final nonce are unused counter space.
+ cNonce := make([]byte, NonceSize)
+ copy(cNonce[4:12], nonce[16:24])
+
+ return c.seal(dst, cNonce[:], plaintext, additionalData)
+}
+
+func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if len(nonce) != NonceSizeX {
+ panic("chacha20poly1305: bad nonce length passed to Open")
+ }
+ if len(ciphertext) < 16 {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > (1<<38)-48 {
+ panic("chacha20poly1305: ciphertext too large")
+ }
+
+ c := new(chacha20poly1305)
+ hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
+ copy(c.key[:], hKey)
+
+ // The first 4 bytes of the final nonce are unused counter space.
+ cNonce := make([]byte, NonceSize)
+ copy(cNonce[4:12], nonce[16:24])
+
+ return c.open(dst, cNonce[:], ciphertext, additionalData)
+}
diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1.go
new file mode 100644
index 00000000..d25979d9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/cryptobyte/asn1.go
@@ -0,0 +1,825 @@
+// 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.
+
+package cryptobyte
+
+import (
+ encoding_asn1 "encoding/asn1"
+ "fmt"
+ "math/big"
+ "reflect"
+ "time"
+
+ "golang.org/x/crypto/cryptobyte/asn1"
+)
+
+// This file contains ASN.1-related methods for String and Builder.
+
+// Builder
+
+// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
+func (b *Builder) AddASN1Int64(v int64) {
+ b.addASN1Signed(asn1.INTEGER, v)
+}
+
+// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the
+// given tag.
+func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) {
+ b.addASN1Signed(tag, v)
+}
+
+// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
+func (b *Builder) AddASN1Enum(v int64) {
+ b.addASN1Signed(asn1.ENUM, v)
+}
+
+func (b *Builder) addASN1Signed(tag asn1.Tag, v int64) {
+ b.AddASN1(tag, func(c *Builder) {
+ length := 1
+ for i := v; i >= 0x80 || i < -0x80; i >>= 8 {
+ length++
+ }
+
+ for ; length > 0; length-- {
+ i := v >> uint((length-1)*8) & 0xff
+ c.AddUint8(uint8(i))
+ }
+ })
+}
+
+// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
+func (b *Builder) AddASN1Uint64(v uint64) {
+ b.AddASN1(asn1.INTEGER, func(c *Builder) {
+ length := 1
+ for i := v; i >= 0x80; i >>= 8 {
+ length++
+ }
+
+ for ; length > 0; length-- {
+ i := v >> uint((length-1)*8) & 0xff
+ c.AddUint8(uint8(i))
+ }
+ })
+}
+
+// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
+func (b *Builder) AddASN1BigInt(n *big.Int) {
+ if b.err != nil {
+ return
+ }
+
+ b.AddASN1(asn1.INTEGER, func(c *Builder) {
+ if n.Sign() < 0 {
+ // A negative number has to be converted to two's-complement form. So we
+ // invert and subtract 1. If the most-significant-bit isn't set then
+ // we'll need to pad the beginning with 0xff in order to keep the number
+ // negative.
+ nMinus1 := new(big.Int).Neg(n)
+ nMinus1.Sub(nMinus1, bigOne)
+ bytes := nMinus1.Bytes()
+ for i := range bytes {
+ bytes[i] ^= 0xff
+ }
+ if len(bytes) == 0 || bytes[0]&0x80 == 0 {
+ c.add(0xff)
+ }
+ c.add(bytes...)
+ } else if n.Sign() == 0 {
+ c.add(0)
+ } else {
+ bytes := n.Bytes()
+ if bytes[0]&0x80 != 0 {
+ c.add(0)
+ }
+ c.add(bytes...)
+ }
+ })
+}
+
+// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
+func (b *Builder) AddASN1OctetString(bytes []byte) {
+ b.AddASN1(asn1.OCTET_STRING, func(c *Builder) {
+ c.AddBytes(bytes)
+ })
+}
+
+const generalizedTimeFormatStr = "20060102150405Z0700"
+
+// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
+func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
+ if t.Year() < 0 || t.Year() > 9999 {
+ b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t)
+ return
+ }
+ b.AddASN1(asn1.GeneralizedTime, func(c *Builder) {
+ c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
+ })
+}
+
+// AddASN1UTCTime appends a DER-encoded ASN.1 UTCTime.
+func (b *Builder) AddASN1UTCTime(t time.Time) {
+ b.AddASN1(asn1.UTCTime, func(c *Builder) {
+ // As utilized by the X.509 profile, UTCTime can only
+ // represent the years 1950 through 2049.
+ if t.Year() < 1950 || t.Year() >= 2050 {
+ b.err = fmt.Errorf("cryptobyte: cannot represent %v as a UTCTime", t)
+ return
+ }
+ c.AddBytes([]byte(t.Format(defaultUTCTimeFormatStr)))
+ })
+}
+
+// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING. This does not
+// support BIT STRINGs that are not a whole number of bytes.
+func (b *Builder) AddASN1BitString(data []byte) {
+ b.AddASN1(asn1.BIT_STRING, func(b *Builder) {
+ b.AddUint8(0)
+ b.AddBytes(data)
+ })
+}
+
+func (b *Builder) addBase128Int(n int64) {
+ var length int
+ if n == 0 {
+ length = 1
+ } else {
+ for i := n; i > 0; i >>= 7 {
+ length++
+ }
+ }
+
+ for i := length - 1; i >= 0; i-- {
+ o := byte(n >> uint(i*7))
+ o &= 0x7f
+ if i != 0 {
+ o |= 0x80
+ }
+
+ b.add(o)
+ }
+}
+
+func isValidOID(oid encoding_asn1.ObjectIdentifier) bool {
+ if len(oid) < 2 {
+ return false
+ }
+
+ if oid[0] > 2 || (oid[0] <= 1 && oid[1] >= 40) {
+ return false
+ }
+
+ for _, v := range oid {
+ if v < 0 {
+ return false
+ }
+ }
+
+ return true
+}
+
+func (b *Builder) AddASN1ObjectIdentifier(oid encoding_asn1.ObjectIdentifier) {
+ b.AddASN1(asn1.OBJECT_IDENTIFIER, func(b *Builder) {
+ if !isValidOID(oid) {
+ b.err = fmt.Errorf("cryptobyte: invalid OID: %v", oid)
+ return
+ }
+
+ b.addBase128Int(int64(oid[0])*40 + int64(oid[1]))
+ for _, v := range oid[2:] {
+ b.addBase128Int(int64(v))
+ }
+ })
+}
+
+func (b *Builder) AddASN1Boolean(v bool) {
+ b.AddASN1(asn1.BOOLEAN, func(b *Builder) {
+ if v {
+ b.AddUint8(0xff)
+ } else {
+ b.AddUint8(0)
+ }
+ })
+}
+
+func (b *Builder) AddASN1NULL() {
+ b.add(uint8(asn1.NULL), 0)
+}
+
+// MarshalASN1 calls encoding_asn1.Marshal on its input and appends the result if
+// successful or records an error if one occurred.
+func (b *Builder) MarshalASN1(v interface{}) {
+ // NOTE(martinkr): This is somewhat of a hack to allow propagation of
+ // encoding_asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a
+ // value embedded into a struct, its tag information is lost.
+ if b.err != nil {
+ return
+ }
+ bytes, err := encoding_asn1.Marshal(v)
+ if err != nil {
+ b.err = err
+ return
+ }
+ b.AddBytes(bytes)
+}
+
+// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag.
+// Tags greater than 30 are not supported and result in an error (i.e.
+// low-tag-number form only). The child builder passed to the
+// BuilderContinuation can be used to build the content of the ASN.1 object.
+func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
+ if b.err != nil {
+ return
+ }
+ // Identifiers with the low five bits set indicate high-tag-number format
+ // (two or more octets), which we don't support.
+ if tag&0x1f == 0x1f {
+ b.err = fmt.Errorf("cryptobyte: high-tag number identifier octets not supported: 0x%x", tag)
+ return
+ }
+ b.AddUint8(uint8(tag))
+ b.addLengthPrefixed(1, true, f)
+}
+
+// String
+
+// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean
+// representation into out and advances. It reports whether the read
+// was successful.
+func (s *String) ReadASN1Boolean(out *bool) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.BOOLEAN) || len(bytes) != 1 {
+ return false
+ }
+
+ switch bytes[0] {
+ case 0:
+ *out = false
+ case 0xff:
+ *out = true
+ default:
+ return false
+ }
+
+ return true
+}
+
+// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
+// not point to an integer, to a big.Int, or to a []byte it panics. Only
+// positive and zero values can be decoded into []byte, and they are returned as
+// big-endian binary values that share memory with s. Positive values will have
+// no leading zeroes, and zero will be returned as a single zero byte.
+// ReadASN1Integer reports whether the read was successful.
+func (s *String) ReadASN1Integer(out interface{}) bool {
+ switch out := out.(type) {
+ case *int, *int8, *int16, *int32, *int64:
+ var i int64
+ if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) {
+ return false
+ }
+ reflect.ValueOf(out).Elem().SetInt(i)
+ return true
+ case *uint, *uint8, *uint16, *uint32, *uint64:
+ var u uint64
+ if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) {
+ return false
+ }
+ reflect.ValueOf(out).Elem().SetUint(u)
+ return true
+ case *big.Int:
+ return s.readASN1BigInt(out)
+ case *[]byte:
+ return s.readASN1Bytes(out)
+ default:
+ panic("out does not point to an integer type")
+ }
+}
+
+func checkASN1Integer(bytes []byte) bool {
+ if len(bytes) == 0 {
+ // An INTEGER is encoded with at least one octet.
+ return false
+ }
+ if len(bytes) == 1 {
+ return true
+ }
+ if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 {
+ // Value is not minimally encoded.
+ return false
+ }
+ return true
+}
+
+var bigOne = big.NewInt(1)
+
+func (s *String) readASN1BigInt(out *big.Int) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) {
+ return false
+ }
+ if bytes[0]&0x80 == 0x80 {
+ // Negative number.
+ neg := make([]byte, len(bytes))
+ for i, b := range bytes {
+ neg[i] = ^b
+ }
+ out.SetBytes(neg)
+ out.Add(out, bigOne)
+ out.Neg(out)
+ } else {
+ out.SetBytes(bytes)
+ }
+ return true
+}
+
+func (s *String) readASN1Bytes(out *[]byte) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) {
+ return false
+ }
+ if bytes[0]&0x80 == 0x80 {
+ return false
+ }
+ for len(bytes) > 1 && bytes[0] == 0 {
+ bytes = bytes[1:]
+ }
+ *out = bytes
+ return true
+}
+
+func (s *String) readASN1Int64(out *int64) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) {
+ return false
+ }
+ return true
+}
+
+func asn1Signed(out *int64, n []byte) bool {
+ length := len(n)
+ if length > 8 {
+ return false
+ }
+ for i := 0; i < length; i++ {
+ *out <<= 8
+ *out |= int64(n[i])
+ }
+ // Shift up and down in order to sign extend the result.
+ *out <<= 64 - uint8(length)*8
+ *out >>= 64 - uint8(length)*8
+ return true
+}
+
+func (s *String) readASN1Uint64(out *uint64) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) {
+ return false
+ }
+ return true
+}
+
+func asn1Unsigned(out *uint64, n []byte) bool {
+ length := len(n)
+ if length > 9 || length == 9 && n[0] != 0 {
+ // Too large for uint64.
+ return false
+ }
+ if n[0]&0x80 != 0 {
+ // Negative number.
+ return false
+ }
+ for i := 0; i < length; i++ {
+ *out <<= 8
+ *out |= uint64(n[i])
+ }
+ return true
+}
+
+// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out
+// and advances. It reports whether the read was successful and resulted in a
+// value that can be represented in an int64.
+func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool {
+ var bytes String
+ return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes)
+}
+
+// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports
+// whether the read was successful.
+func (s *String) ReadASN1Enum(out *int) bool {
+ var bytes String
+ var i int64
+ if !s.ReadASN1(&bytes, asn1.ENUM) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) {
+ return false
+ }
+ if int64(int(i)) != i {
+ return false
+ }
+ *out = int(i)
+ return true
+}
+
+func (s *String) readBase128Int(out *int) bool {
+ ret := 0
+ for i := 0; len(*s) > 0; i++ {
+ if i == 5 {
+ return false
+ }
+ // Avoid overflowing int on a 32-bit platform.
+ // We don't want different behavior based on the architecture.
+ if ret >= 1<<(31-7) {
+ return false
+ }
+ ret <<= 7
+ b := s.read(1)[0]
+
+ // ITU-T X.690, section 8.19.2:
+ // The subidentifier shall be encoded in the fewest possible octets,
+ // that is, the leading octet of the subidentifier shall not have the value 0x80.
+ if i == 0 && b == 0x80 {
+ return false
+ }
+
+ ret |= int(b & 0x7f)
+ if b&0x80 == 0 {
+ *out = ret
+ return true
+ }
+ }
+ return false // truncated
+}
+
+// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
+// advances. It reports whether the read was successful.
+func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 {
+ return false
+ }
+
+ // In the worst case, we get two elements from the first byte (which is
+ // encoded differently) and then every varint is a single byte long.
+ components := make([]int, len(bytes)+1)
+
+ // The first varint is 40*value1 + value2:
+ // According to this packing, value1 can take the values 0, 1 and 2 only.
+ // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
+ // then there are no restrictions on value2.
+ var v int
+ if !bytes.readBase128Int(&v) {
+ return false
+ }
+ if v < 80 {
+ components[0] = v / 40
+ components[1] = v % 40
+ } else {
+ components[0] = 2
+ components[1] = v - 80
+ }
+
+ i := 2
+ for ; len(bytes) > 0; i++ {
+ if !bytes.readBase128Int(&v) {
+ return false
+ }
+ components[i] = v
+ }
+ *out = components[:i]
+ return true
+}
+
+// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
+// advances. It reports whether the read was successful.
+func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.GeneralizedTime) {
+ return false
+ }
+ t := string(bytes)
+ res, err := time.Parse(generalizedTimeFormatStr, t)
+ if err != nil {
+ return false
+ }
+ if serialized := res.Format(generalizedTimeFormatStr); serialized != t {
+ return false
+ }
+ *out = res
+ return true
+}
+
+const defaultUTCTimeFormatStr = "060102150405Z0700"
+
+// ReadASN1UTCTime decodes an ASN.1 UTCTime into out and advances.
+// It reports whether the read was successful.
+func (s *String) ReadASN1UTCTime(out *time.Time) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.UTCTime) {
+ return false
+ }
+ t := string(bytes)
+
+ formatStr := defaultUTCTimeFormatStr
+ var err error
+ res, err := time.Parse(formatStr, t)
+ if err != nil {
+ // Fallback to minute precision if we can't parse second
+ // precision. If we are following X.509 or X.690 we shouldn't
+ // support this, but we do.
+ formatStr = "0601021504Z0700"
+ res, err = time.Parse(formatStr, t)
+ }
+ if err != nil {
+ return false
+ }
+
+ if serialized := res.Format(formatStr); serialized != t {
+ return false
+ }
+
+ if res.Year() >= 2050 {
+ // UTCTime interprets the low order digits 50-99 as 1950-99.
+ // This only applies to its use in the X.509 profile.
+ // See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
+ res = res.AddDate(-100, 0, 0)
+ }
+ *out = res
+ return true
+}
+
+// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances.
+// It reports whether the read was successful.
+func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
+ var bytes String
+ if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 ||
+ len(bytes)*8/8 != len(bytes) {
+ return false
+ }
+
+ paddingBits := bytes[0]
+ bytes = bytes[1:]
+ if paddingBits > 7 ||
+ len(bytes) == 0 && paddingBits != 0 ||
+ len(bytes) > 0 && bytes[len(bytes)-1]&(1< 4 || len(*s) < int(2+lenLen) {
+ return false
+ }
+
+ lenBytes := String((*s)[2 : 2+lenLen])
+ if !lenBytes.readUnsigned(&len32, int(lenLen)) {
+ return false
+ }
+
+ // ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
+ // with the minimum number of octets.
+ if len32 < 128 {
+ // Length should have used short-form encoding.
+ return false
+ }
+ if len32>>((lenLen-1)*8) == 0 {
+ // Leading octet is 0. Length should have been at least one byte shorter.
+ return false
+ }
+
+ headerLen = 2 + uint32(lenLen)
+ if headerLen+len32 < len32 {
+ // Overflow.
+ return false
+ }
+ length = headerLen + len32
+ }
+
+ if int(length) < 0 || !s.ReadBytes((*[]byte)(out), int(length)) {
+ return false
+ }
+ if skipHeader && !out.Skip(int(headerLen)) {
+ panic("cryptobyte: internal error")
+ }
+
+ return true
+}
diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go
new file mode 100644
index 00000000..90ef6a24
--- /dev/null
+++ b/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go
@@ -0,0 +1,46 @@
+// 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.
+
+// Package asn1 contains supporting types for parsing and building ASN.1
+// messages with the cryptobyte package.
+package asn1
+
+// Tag represents an ASN.1 identifier octet, consisting of a tag number
+// (indicating a type) and class (such as context-specific or constructed).
+//
+// Methods in the cryptobyte package only support the low-tag-number form, i.e.
+// a single identifier octet with bits 7-8 encoding the class and bits 1-6
+// encoding the tag number.
+type Tag uint8
+
+const (
+ classConstructed = 0x20
+ classContextSpecific = 0x80
+)
+
+// Constructed returns t with the constructed class bit set.
+func (t Tag) Constructed() Tag { return t | classConstructed }
+
+// ContextSpecific returns t with the context-specific class bit set.
+func (t Tag) ContextSpecific() Tag { return t | classContextSpecific }
+
+// The following is a list of standard tag and class combinations.
+const (
+ BOOLEAN = Tag(1)
+ INTEGER = Tag(2)
+ BIT_STRING = Tag(3)
+ OCTET_STRING = Tag(4)
+ NULL = Tag(5)
+ OBJECT_IDENTIFIER = Tag(6)
+ ENUM = Tag(10)
+ UTF8String = Tag(12)
+ SEQUENCE = Tag(16 | classConstructed)
+ SET = Tag(17 | classConstructed)
+ PrintableString = Tag(19)
+ T61String = Tag(20)
+ IA5String = Tag(22)
+ UTCTime = Tag(23)
+ GeneralizedTime = Tag(24)
+ GeneralString = Tag(27)
+)
diff --git a/vendor/golang.org/x/crypto/cryptobyte/builder.go b/vendor/golang.org/x/crypto/cryptobyte/builder.go
new file mode 100644
index 00000000..cf254f5f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/cryptobyte/builder.go
@@ -0,0 +1,350 @@
+// 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.
+
+package cryptobyte
+
+import (
+ "errors"
+ "fmt"
+)
+
+// A Builder builds byte strings from fixed-length and length-prefixed values.
+// Builders either allocate space as needed, or are ‘fixed’, which means that
+// they write into a given buffer and produce an error if it's exhausted.
+//
+// The zero value is a usable Builder that allocates space as needed.
+//
+// Simple values are marshaled and appended to a Builder using methods on the
+// Builder. Length-prefixed values are marshaled by providing a
+// BuilderContinuation, which is a function that writes the inner contents of
+// the value to a given Builder. See the documentation for BuilderContinuation
+// for details.
+type Builder struct {
+ err error
+ result []byte
+ fixedSize bool
+ child *Builder
+ offset int
+ pendingLenLen int
+ pendingIsASN1 bool
+ inContinuation *bool
+}
+
+// NewBuilder creates a Builder that appends its output to the given buffer.
+// Like append(), the slice will be reallocated if its capacity is exceeded.
+// Use Bytes to get the final buffer.
+func NewBuilder(buffer []byte) *Builder {
+ return &Builder{
+ result: buffer,
+ }
+}
+
+// NewFixedBuilder creates a Builder that appends its output into the given
+// buffer. This builder does not reallocate the output buffer. Writes that
+// would exceed the buffer's capacity are treated as an error.
+func NewFixedBuilder(buffer []byte) *Builder {
+ return &Builder{
+ result: buffer,
+ fixedSize: true,
+ }
+}
+
+// SetError sets the value to be returned as the error from Bytes. Writes
+// performed after calling SetError are ignored.
+func (b *Builder) SetError(err error) {
+ b.err = err
+}
+
+// Bytes returns the bytes written by the builder or an error if one has
+// occurred during building.
+func (b *Builder) Bytes() ([]byte, error) {
+ if b.err != nil {
+ return nil, b.err
+ }
+ return b.result[b.offset:], nil
+}
+
+// BytesOrPanic returns the bytes written by the builder or panics if an error
+// has occurred during building.
+func (b *Builder) BytesOrPanic() []byte {
+ if b.err != nil {
+ panic(b.err)
+ }
+ return b.result[b.offset:]
+}
+
+// AddUint8 appends an 8-bit value to the byte string.
+func (b *Builder) AddUint8(v uint8) {
+ b.add(byte(v))
+}
+
+// AddUint16 appends a big-endian, 16-bit value to the byte string.
+func (b *Builder) AddUint16(v uint16) {
+ b.add(byte(v>>8), byte(v))
+}
+
+// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
+// byte of the 32-bit input value is silently truncated.
+func (b *Builder) AddUint24(v uint32) {
+ b.add(byte(v>>16), byte(v>>8), byte(v))
+}
+
+// AddUint32 appends a big-endian, 32-bit value to the byte string.
+func (b *Builder) AddUint32(v uint32) {
+ b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+}
+
+// AddUint48 appends a big-endian, 48-bit value to the byte string.
+func (b *Builder) AddUint48(v uint64) {
+ b.add(byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+}
+
+// AddUint64 appends a big-endian, 64-bit value to the byte string.
+func (b *Builder) AddUint64(v uint64) {
+ b.add(byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+}
+
+// AddBytes appends a sequence of bytes to the byte string.
+func (b *Builder) AddBytes(v []byte) {
+ b.add(v...)
+}
+
+// BuilderContinuation is a continuation-passing interface for building
+// length-prefixed byte sequences. Builder methods for length-prefixed
+// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
+// supplied to them. The child builder passed to the continuation can be used
+// to build the content of the length-prefixed sequence. For example:
+//
+// parent := cryptobyte.NewBuilder()
+// parent.AddUint8LengthPrefixed(func (child *Builder) {
+// child.AddUint8(42)
+// child.AddUint8LengthPrefixed(func (grandchild *Builder) {
+// grandchild.AddUint8(5)
+// })
+// })
+//
+// It is an error to write more bytes to the child than allowed by the reserved
+// length prefix. After the continuation returns, the child must be considered
+// invalid, i.e. users must not store any copies or references of the child
+// that outlive the continuation.
+//
+// If the continuation panics with a value of type BuildError then the inner
+// error will be returned as the error from Bytes. If the child panics
+// otherwise then Bytes will repanic with the same value.
+type BuilderContinuation func(child *Builder)
+
+// BuildError wraps an error. If a BuilderContinuation panics with this value,
+// the panic will be recovered and the inner error will be returned from
+// Builder.Bytes.
+type BuildError struct {
+ Err error
+}
+
+// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
+func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
+ b.addLengthPrefixed(1, false, f)
+}
+
+// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
+func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
+ b.addLengthPrefixed(2, false, f)
+}
+
+// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
+func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
+ b.addLengthPrefixed(3, false, f)
+}
+
+// AddUint32LengthPrefixed adds a big-endian, 32-bit length-prefixed byte sequence.
+func (b *Builder) AddUint32LengthPrefixed(f BuilderContinuation) {
+ b.addLengthPrefixed(4, false, f)
+}
+
+func (b *Builder) callContinuation(f BuilderContinuation, arg *Builder) {
+ if !*b.inContinuation {
+ *b.inContinuation = true
+
+ defer func() {
+ *b.inContinuation = false
+
+ r := recover()
+ if r == nil {
+ return
+ }
+
+ if buildError, ok := r.(BuildError); ok {
+ b.err = buildError.Err
+ } else {
+ panic(r)
+ }
+ }()
+ }
+
+ f(arg)
+}
+
+func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
+ // Subsequent writes can be ignored if the builder has encountered an error.
+ if b.err != nil {
+ return
+ }
+
+ offset := len(b.result)
+ b.add(make([]byte, lenLen)...)
+
+ if b.inContinuation == nil {
+ b.inContinuation = new(bool)
+ }
+
+ b.child = &Builder{
+ result: b.result,
+ fixedSize: b.fixedSize,
+ offset: offset,
+ pendingLenLen: lenLen,
+ pendingIsASN1: isASN1,
+ inContinuation: b.inContinuation,
+ }
+
+ b.callContinuation(f, b.child)
+ b.flushChild()
+ if b.child != nil {
+ panic("cryptobyte: internal error")
+ }
+}
+
+func (b *Builder) flushChild() {
+ if b.child == nil {
+ return
+ }
+ b.child.flushChild()
+ child := b.child
+ b.child = nil
+
+ if child.err != nil {
+ b.err = child.err
+ return
+ }
+
+ length := len(child.result) - child.pendingLenLen - child.offset
+
+ if length < 0 {
+ panic("cryptobyte: internal error") // result unexpectedly shrunk
+ }
+
+ if child.pendingIsASN1 {
+ // For ASN.1, we reserved a single byte for the length. If that turned out
+ // to be incorrect, we have to move the contents along in order to make
+ // space.
+ if child.pendingLenLen != 1 {
+ panic("cryptobyte: internal error")
+ }
+ var lenLen, lenByte uint8
+ if int64(length) > 0xfffffffe {
+ b.err = errors.New("pending ASN.1 child too long")
+ return
+ } else if length > 0xffffff {
+ lenLen = 5
+ lenByte = 0x80 | 4
+ } else if length > 0xffff {
+ lenLen = 4
+ lenByte = 0x80 | 3
+ } else if length > 0xff {
+ lenLen = 3
+ lenByte = 0x80 | 2
+ } else if length > 0x7f {
+ lenLen = 2
+ lenByte = 0x80 | 1
+ } else {
+ lenLen = 1
+ lenByte = uint8(length)
+ length = 0
+ }
+
+ // Insert the initial length byte, make space for successive length bytes,
+ // and adjust the offset.
+ child.result[child.offset] = lenByte
+ extraBytes := int(lenLen - 1)
+ if extraBytes != 0 {
+ child.add(make([]byte, extraBytes)...)
+ childStart := child.offset + child.pendingLenLen
+ copy(child.result[childStart+extraBytes:], child.result[childStart:])
+ }
+ child.offset++
+ child.pendingLenLen = extraBytes
+ }
+
+ l := length
+ for i := child.pendingLenLen - 1; i >= 0; i-- {
+ child.result[child.offset+i] = uint8(l)
+ l >>= 8
+ }
+ if l != 0 {
+ b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
+ return
+ }
+
+ if b.fixedSize && &b.result[0] != &child.result[0] {
+ panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer")
+ }
+
+ b.result = child.result
+}
+
+func (b *Builder) add(bytes ...byte) {
+ if b.err != nil {
+ return
+ }
+ if b.child != nil {
+ panic("cryptobyte: attempted write while child is pending")
+ }
+ if len(b.result)+len(bytes) < len(bytes) {
+ b.err = errors.New("cryptobyte: length overflow")
+ }
+ if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
+ b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
+ return
+ }
+ b.result = append(b.result, bytes...)
+}
+
+// Unwrite rolls back non-negative n bytes written directly to the Builder.
+// An attempt by a child builder passed to a continuation to unwrite bytes
+// from its parent will panic.
+func (b *Builder) Unwrite(n int) {
+ if b.err != nil {
+ return
+ }
+ if b.child != nil {
+ panic("cryptobyte: attempted unwrite while child is pending")
+ }
+ length := len(b.result) - b.pendingLenLen - b.offset
+ if length < 0 {
+ panic("cryptobyte: internal error")
+ }
+ if n < 0 {
+ panic("cryptobyte: attempted to unwrite negative number of bytes")
+ }
+ if n > length {
+ panic("cryptobyte: attempted to unwrite more than was written")
+ }
+ b.result = b.result[:len(b.result)-n]
+}
+
+// A MarshalingValue marshals itself into a Builder.
+type MarshalingValue interface {
+ // Marshal is called by Builder.AddValue. It receives a pointer to a builder
+ // to marshal itself into. It may return an error that occurred during
+ // marshaling, such as unset or invalid values.
+ Marshal(b *Builder) error
+}
+
+// AddValue calls Marshal on v, passing a pointer to the builder to append to.
+// If Marshal returns an error, it is set on the Builder so that subsequent
+// appends don't have an effect.
+func (b *Builder) AddValue(v MarshalingValue) {
+ err := v.Marshal(b)
+ if err != nil {
+ b.err = err
+ }
+}
diff --git a/vendor/golang.org/x/crypto/cryptobyte/string.go b/vendor/golang.org/x/crypto/cryptobyte/string.go
new file mode 100644
index 00000000..4b0f8097
--- /dev/null
+++ b/vendor/golang.org/x/crypto/cryptobyte/string.go
@@ -0,0 +1,183 @@
+// 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.
+
+// Package cryptobyte contains types that help with parsing and constructing
+// length-prefixed, binary messages, including ASN.1 DER. (The asn1 subpackage
+// contains useful ASN.1 constants.)
+//
+// The String type is for parsing. It wraps a []byte slice and provides helper
+// functions for consuming structures, value by value.
+//
+// The Builder type is for constructing messages. It providers helper functions
+// for appending values and also for appending length-prefixed submessages –
+// without having to worry about calculating the length prefix ahead of time.
+//
+// See the documentation and examples for the Builder and String types to get
+// started.
+package cryptobyte
+
+// String represents a string of bytes. It provides methods for parsing
+// fixed-length and length-prefixed values from it.
+type String []byte
+
+// read advances a String by n bytes and returns them. If less than n bytes
+// remain, it returns nil.
+func (s *String) read(n int) []byte {
+ if len(*s) < n || n < 0 {
+ return nil
+ }
+ v := (*s)[:n]
+ *s = (*s)[n:]
+ return v
+}
+
+// Skip advances the String by n byte and reports whether it was successful.
+func (s *String) Skip(n int) bool {
+ return s.read(n) != nil
+}
+
+// ReadUint8 decodes an 8-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint8(out *uint8) bool {
+ v := s.read(1)
+ if v == nil {
+ return false
+ }
+ *out = uint8(v[0])
+ return true
+}
+
+// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint16(out *uint16) bool {
+ v := s.read(2)
+ if v == nil {
+ return false
+ }
+ *out = uint16(v[0])<<8 | uint16(v[1])
+ return true
+}
+
+// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint24(out *uint32) bool {
+ v := s.read(3)
+ if v == nil {
+ return false
+ }
+ *out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
+ return true
+}
+
+// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint32(out *uint32) bool {
+ v := s.read(4)
+ if v == nil {
+ return false
+ }
+ *out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
+ return true
+}
+
+// ReadUint48 decodes a big-endian, 48-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint48(out *uint64) bool {
+ v := s.read(6)
+ if v == nil {
+ return false
+ }
+ *out = uint64(v[0])<<40 | uint64(v[1])<<32 | uint64(v[2])<<24 | uint64(v[3])<<16 | uint64(v[4])<<8 | uint64(v[5])
+ return true
+}
+
+// ReadUint64 decodes a big-endian, 64-bit value into out and advances over it.
+// It reports whether the read was successful.
+func (s *String) ReadUint64(out *uint64) bool {
+ v := s.read(8)
+ if v == nil {
+ return false
+ }
+ *out = uint64(v[0])<<56 | uint64(v[1])<<48 | uint64(v[2])<<40 | uint64(v[3])<<32 | uint64(v[4])<<24 | uint64(v[5])<<16 | uint64(v[6])<<8 | uint64(v[7])
+ return true
+}
+
+func (s *String) readUnsigned(out *uint32, length int) bool {
+ v := s.read(length)
+ if v == nil {
+ return false
+ }
+ var result uint32
+ for i := 0; i < length; i++ {
+ result <<= 8
+ result |= uint32(v[i])
+ }
+ *out = result
+ return true
+}
+
+func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
+ lenBytes := s.read(lenLen)
+ if lenBytes == nil {
+ return false
+ }
+ var length uint32
+ for _, b := range lenBytes {
+ length = length << 8
+ length = length | uint32(b)
+ }
+ v := s.read(int(length))
+ if v == nil {
+ return false
+ }
+ *outChild = v
+ return true
+}
+
+// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
+// into out and advances over it. It reports whether the read was successful.
+func (s *String) ReadUint8LengthPrefixed(out *String) bool {
+ return s.readLengthPrefixed(1, out)
+}
+
+// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
+// length-prefixed value into out and advances over it. It reports whether the
+// read was successful.
+func (s *String) ReadUint16LengthPrefixed(out *String) bool {
+ return s.readLengthPrefixed(2, out)
+}
+
+// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
+// length-prefixed value into out and advances over it. It reports whether
+// the read was successful.
+func (s *String) ReadUint24LengthPrefixed(out *String) bool {
+ return s.readLengthPrefixed(3, out)
+}
+
+// ReadBytes reads n bytes into out and advances over them. It reports
+// whether the read was successful.
+func (s *String) ReadBytes(out *[]byte, n int) bool {
+ v := s.read(n)
+ if v == nil {
+ return false
+ }
+ *out = v
+ return true
+}
+
+// CopyBytes copies len(out) bytes into out and advances over them. It reports
+// whether the copy operation was successful
+func (s *String) CopyBytes(out []byte) bool {
+ n := len(out)
+ v := s.read(n)
+ if v == nil {
+ return false
+ }
+ return copy(out, v) == n
+}
+
+// Empty reports whether the string does not contain any bytes.
+func (s String) Empty() bool {
+ return len(s) == 0
+}
diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go
new file mode 100644
index 00000000..49f3a558
--- /dev/null
+++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go
@@ -0,0 +1,100 @@
+// 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.
+
+// Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation
+// Function (HKDF) as defined in RFC 5869.
+//
+// HKDF is a cryptographic key derivation function (KDF) with the goal of
+// expanding limited input keying material into one or more cryptographically
+// strong secret keys.
+package hkdf
+
+import (
+ "crypto/hkdf"
+ "crypto/hmac"
+ "errors"
+ "hash"
+ "io"
+)
+
+// Extract generates a pseudorandom key for use with Expand from an input secret
+// and an optional independent salt.
+//
+// Only use this function if you need to reuse the extracted key with multiple
+// Expand invocations and different context values. Most common scenarios,
+// including the generation of multiple keys, should use New instead.
+func Extract(hash func() hash.Hash, secret, salt []byte) []byte {
+ // Use the stdlib Extract, which disables FIPS 140 enforcement of the HMAC
+ // key (which in HKDF is the salt). The only possible error is FIPS 140
+ // enforcement of the hash, which had to panic under this API anyway. We
+ // don't use the stdlib Expand, because it switched to returning a []byte
+ // instead of an io.Reader, and Expand uses the HMAC key as a key.
+ out, err := hkdf.Extract(hash, secret, salt)
+ if err != nil {
+ panic(err)
+ }
+ return out
+}
+
+type hkdfReader struct {
+ expander hash.Hash
+ size int
+
+ info []byte
+ counter byte
+
+ prev []byte
+ buf []byte
+}
+
+func (f *hkdfReader) Read(p []byte) (int, error) {
+ // Check whether enough data can be generated
+ need := len(p)
+ remains := len(f.buf) + int(255-f.counter+1)*f.size
+ if remains < need {
+ return 0, errors.New("hkdf: entropy limit reached")
+ }
+ // Read any leftover from the buffer
+ n := copy(p, f.buf)
+ p = p[n:]
+
+ // Fill the rest of the buffer
+ for len(p) > 0 {
+ if f.counter > 1 {
+ f.expander.Reset()
+ }
+ f.expander.Write(f.prev)
+ f.expander.Write(f.info)
+ f.expander.Write([]byte{f.counter})
+ f.prev = f.expander.Sum(f.prev[:0])
+ f.counter++
+
+ // Copy the new batch into p
+ f.buf = f.prev
+ n = copy(p, f.buf)
+ p = p[n:]
+ }
+ // Save leftovers for next run
+ f.buf = f.buf[n:]
+
+ return need, nil
+}
+
+// Expand returns a Reader, from which keys can be read, using the given
+// pseudorandom key and optional context info, skipping the extraction step.
+//
+// The pseudorandomKey should have been generated by Extract, or be a uniformly
+// random or pseudorandom cryptographically strong key. See RFC 5869, Section
+// 3.3. Most common scenarios will want to use New instead.
+func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader {
+ expander := hmac.New(hash, pseudorandomKey)
+ return &hkdfReader{expander, expander.Size(), info, 1, nil, nil}
+}
+
+// New returns a Reader, from which keys can be read, using the given hash,
+// secret, salt and context info. Salt and info can be nil.
+func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
+ prk := Extract(hash, secret, salt)
+ return Expand(hash, prk, info)
+}
diff --git a/vendor/golang.org/x/crypto/internal/alias/alias.go b/vendor/golang.org/x/crypto/internal/alias/alias.go
new file mode 100644
index 00000000..551ff0c3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/alias/alias.go
@@ -0,0 +1,31 @@
+// 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 !purego
+
+// Package alias implements memory aliasing tests.
+package alias
+
+import "unsafe"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+ uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return AnyOverlap(x, y)
+}
diff --git a/vendor/golang.org/x/crypto/internal/alias/alias_purego.go b/vendor/golang.org/x/crypto/internal/alias/alias_purego.go
new file mode 100644
index 00000000..6fe61b5c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/alias/alias_purego.go
@@ -0,0 +1,34 @@
+// 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 purego
+
+// Package alias implements memory aliasing tests.
+package alias
+
+// This is the Google App Engine standard variant based on reflect
+// because the unsafe package and cgo are disallowed.
+
+import "reflect"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
+ reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return AnyOverlap(x, y)
+}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
new file mode 100644
index 00000000..8d99551f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
@@ -0,0 +1,9 @@
+// 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 (!amd64 && !loong64 && !ppc64le && !ppc64 && !s390x) || !gc || purego
+
+package poly1305
+
+type mac struct{ macGeneric }
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go b/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go
new file mode 100644
index 00000000..4aaea810
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go
@@ -0,0 +1,99 @@
+// Copyright 2012 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 poly1305 implements Poly1305 one-time message authentication code as
+// specified in https://cr.yp.to/mac/poly1305-20050329.pdf.
+//
+// Poly1305 is a fast, one-time authentication function. It is infeasible for an
+// attacker to generate an authenticator for a message without the key. However, a
+// key must only be used for a single message. Authenticating two different
+// messages with the same key allows an attacker to forge authenticators for other
+// messages with the same key.
+//
+// Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
+// used with a fixed key in order to generate one-time keys from an nonce.
+// However, in this package AES isn't used and the one-time key is specified
+// directly.
+package poly1305
+
+import "crypto/subtle"
+
+// TagSize is the size, in bytes, of a poly1305 authenticator.
+const TagSize = 16
+
+// Sum generates an authenticator for msg using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ h := New(key)
+ h.Write(m)
+ h.Sum(out[:0])
+}
+
+// Verify returns true if mac is a valid authenticator for m with the given key.
+func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
+ var tmp [16]byte
+ Sum(&tmp, m, key)
+ return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
+}
+
+// New returns a new MAC computing an authentication
+// tag of all data written to it with the given key.
+// This allows writing the message progressively instead
+// of passing it as a single slice. Common users should use
+// the Sum function instead.
+//
+// The key must be unique for each message, as authenticating
+// two different messages with the same key allows an attacker
+// to forge messages at will.
+func New(key *[32]byte) *MAC {
+ m := &MAC{}
+ initialize(key, &m.macState)
+ return m
+}
+
+// MAC is an io.Writer computing an authentication tag
+// of the data written to it.
+//
+// MAC cannot be used like common hash.Hash implementations,
+// because using a poly1305 key twice breaks its security.
+// Therefore writing data to a running MAC after calling
+// Sum or Verify causes it to panic.
+type MAC struct {
+ mac // platform-dependent implementation
+
+ finalized bool
+}
+
+// Size returns the number of bytes Sum will return.
+func (h *MAC) Size() int { return TagSize }
+
+// Write adds more data to the running message authentication code.
+// It never returns an error.
+//
+// It must not be called after the first call of Sum or Verify.
+func (h *MAC) Write(p []byte) (n int, err error) {
+ if h.finalized {
+ panic("poly1305: write to MAC after Sum or Verify")
+ }
+ return h.mac.Write(p)
+}
+
+// Sum computes the authenticator of all data written to the
+// message authentication code.
+func (h *MAC) Sum(b []byte) []byte {
+ var mac [TagSize]byte
+ h.mac.Sum(&mac)
+ h.finalized = true
+ return append(b, mac[:]...)
+}
+
+// Verify returns whether the authenticator of all data written to
+// the message authentication code matches the expected value.
+func (h *MAC) Verify(expected []byte) bool {
+ var mac [TagSize]byte
+ h.mac.Sum(&mac)
+ h.finalized = true
+ return subtle.ConstantTimeCompare(expected, mac[:]) == 1
+}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s
new file mode 100644
index 00000000..13375738
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s
@@ -0,0 +1,93 @@
+// Code generated by command: go run sum_amd64_asm.go -out ../sum_amd64.s -pkg poly1305. DO NOT EDIT.
+
+//go:build gc && !purego
+
+// func update(state *macState, msg []byte)
+TEXT ·update(SB), $0-32
+ MOVQ state+0(FP), DI
+ MOVQ msg_base+8(FP), SI
+ MOVQ msg_len+16(FP), R15
+ MOVQ (DI), R8
+ MOVQ 8(DI), R9
+ MOVQ 16(DI), R10
+ MOVQ 24(DI), R11
+ MOVQ 32(DI), R12
+ CMPQ R15, $0x10
+ JB bytes_between_0_and_15
+
+loop:
+ ADDQ (SI), R8
+ ADCQ 8(SI), R9
+ ADCQ $0x01, R10
+ LEAQ 16(SI), SI
+
+multiply:
+ MOVQ R11, AX
+ MULQ R8
+ MOVQ AX, BX
+ MOVQ DX, CX
+ MOVQ R11, AX
+ MULQ R9
+ ADDQ AX, CX
+ ADCQ $0x00, DX
+ MOVQ R11, R13
+ IMULQ R10, R13
+ ADDQ DX, R13
+ MOVQ R12, AX
+ MULQ R8
+ ADDQ AX, CX
+ ADCQ $0x00, DX
+ MOVQ DX, R8
+ MOVQ R12, R14
+ IMULQ R10, R14
+ MOVQ R12, AX
+ MULQ R9
+ ADDQ AX, R13
+ ADCQ DX, R14
+ ADDQ R8, R13
+ ADCQ $0x00, R14
+ MOVQ BX, R8
+ MOVQ CX, R9
+ MOVQ R13, R10
+ ANDQ $0x03, R10
+ MOVQ R13, BX
+ ANDQ $-4, BX
+ ADDQ BX, R8
+ ADCQ R14, R9
+ ADCQ $0x00, R10
+ SHRQ $0x02, R14, R13
+ SHRQ $0x02, R14
+ ADDQ R13, R8
+ ADCQ R14, R9
+ ADCQ $0x00, R10
+ SUBQ $0x10, R15
+ CMPQ R15, $0x10
+ JAE loop
+
+bytes_between_0_and_15:
+ TESTQ R15, R15
+ JZ done
+ MOVQ $0x00000001, BX
+ XORQ CX, CX
+ XORQ R13, R13
+ ADDQ R15, SI
+
+flush_buffer:
+ SHLQ $0x08, BX, CX
+ SHLQ $0x08, BX
+ MOVB -1(SI), R13
+ XORQ R13, BX
+ DECQ SI
+ DECQ R15
+ JNZ flush_buffer
+ ADDQ BX, R8
+ ADCQ CX, R9
+ ADCQ $0x00, R10
+ MOVQ $0x00000010, R15
+ JMP multiply
+
+done:
+ MOVQ R8, (DI)
+ MOVQ R9, 8(DI)
+ MOVQ R10, 16(DI)
+ RET
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go
new file mode 100644
index 00000000..315b84ac
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_asm.go
@@ -0,0 +1,47 @@
+// Copyright 2012 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 && !purego && (amd64 || loong64 || ppc64 || ppc64le)
+
+package poly1305
+
+//go:noescape
+func update(state *macState, msg []byte)
+
+// mac is a wrapper for macGeneric that redirects calls that would have gone to
+// updateGeneric to update.
+//
+// Its Write and Sum methods are otherwise identical to the macGeneric ones, but
+// using function pointers would carry a major performance cost.
+type mac struct{ macGeneric }
+
+func (h *mac) Write(p []byte) (int, error) {
+ nn := len(p)
+ if h.offset > 0 {
+ n := copy(h.buffer[h.offset:], p)
+ if h.offset+n < TagSize {
+ h.offset += n
+ return nn, nil
+ }
+ p = p[n:]
+ h.offset = 0
+ update(&h.macState, h.buffer[:])
+ }
+ if n := len(p) - (len(p) % TagSize); n > 0 {
+ update(&h.macState, p[:n])
+ p = p[n:]
+ }
+ if len(p) > 0 {
+ h.offset += copy(h.buffer[h.offset:], p)
+ }
+ return nn, nil
+}
+
+func (h *mac) Sum(out *[16]byte) {
+ state := h.macState
+ if h.offset > 0 {
+ update(&state, h.buffer[:h.offset])
+ }
+ finalize(out, &state.h, &state.s)
+}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go
new file mode 100644
index 00000000..ec2202bd
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go
@@ -0,0 +1,312 @@
+// 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.
+
+// This file provides the generic implementation of Sum and MAC. Other files
+// might provide optimized assembly implementations of some of this code.
+
+package poly1305
+
+import (
+ "encoding/binary"
+ "math/bits"
+)
+
+// Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag
+// for a 64 bytes message is approximately
+//
+// s + m[0:16] * r⁴ + m[16:32] * r³ + m[32:48] * r² + m[48:64] * r mod 2¹³⁰ - 5
+//
+// for some secret r and s. It can be computed sequentially like
+//
+// for len(msg) > 0:
+// h += read(msg, 16)
+// h *= r
+// h %= 2¹³⁰ - 5
+// return h + s
+//
+// All the complexity is about doing performant constant-time math on numbers
+// larger than any available numeric type.
+
+func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) {
+ h := newMACGeneric(key)
+ h.Write(msg)
+ h.Sum(out)
+}
+
+func newMACGeneric(key *[32]byte) macGeneric {
+ m := macGeneric{}
+ initialize(key, &m.macState)
+ return m
+}
+
+// macState holds numbers in saturated 64-bit little-endian limbs. That is,
+// the value of [x0, x1, x2] is x[0] + x[1] * 2⁶⁴ + x[2] * 2¹²⁸.
+type macState struct {
+ // h is the main accumulator. It is to be interpreted modulo 2¹³⁰ - 5, but
+ // can grow larger during and after rounds. It must, however, remain below
+ // 2 * (2¹³⁰ - 5).
+ h [3]uint64
+ // r and s are the private key components.
+ r [2]uint64
+ s [2]uint64
+}
+
+type macGeneric struct {
+ macState
+
+ buffer [TagSize]byte
+ offset int
+}
+
+// Write splits the incoming message into TagSize chunks, and passes them to
+// update. It buffers incomplete chunks.
+func (h *macGeneric) Write(p []byte) (int, error) {
+ nn := len(p)
+ if h.offset > 0 {
+ n := copy(h.buffer[h.offset:], p)
+ if h.offset+n < TagSize {
+ h.offset += n
+ return nn, nil
+ }
+ p = p[n:]
+ h.offset = 0
+ updateGeneric(&h.macState, h.buffer[:])
+ }
+ if n := len(p) - (len(p) % TagSize); n > 0 {
+ updateGeneric(&h.macState, p[:n])
+ p = p[n:]
+ }
+ if len(p) > 0 {
+ h.offset += copy(h.buffer[h.offset:], p)
+ }
+ return nn, nil
+}
+
+// Sum flushes the last incomplete chunk from the buffer, if any, and generates
+// the MAC output. It does not modify its state, in order to allow for multiple
+// calls to Sum, even if no Write is allowed after Sum.
+func (h *macGeneric) Sum(out *[TagSize]byte) {
+ state := h.macState
+ if h.offset > 0 {
+ updateGeneric(&state, h.buffer[:h.offset])
+ }
+ finalize(out, &state.h, &state.s)
+}
+
+// [rMask0, rMask1] is the specified Poly1305 clamping mask in little-endian. It
+// clears some bits of the secret coefficient to make it possible to implement
+// multiplication more efficiently.
+const (
+ rMask0 = 0x0FFFFFFC0FFFFFFF
+ rMask1 = 0x0FFFFFFC0FFFFFFC
+)
+
+// initialize loads the 256-bit key into the two 128-bit secret values r and s.
+func initialize(key *[32]byte, m *macState) {
+ m.r[0] = binary.LittleEndian.Uint64(key[0:8]) & rMask0
+ m.r[1] = binary.LittleEndian.Uint64(key[8:16]) & rMask1
+ m.s[0] = binary.LittleEndian.Uint64(key[16:24])
+ m.s[1] = binary.LittleEndian.Uint64(key[24:32])
+}
+
+// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
+// bits.Mul64 and bits.Add64 intrinsics.
+type uint128 struct {
+ lo, hi uint64
+}
+
+func mul64(a, b uint64) uint128 {
+ hi, lo := bits.Mul64(a, b)
+ return uint128{lo, hi}
+}
+
+func add128(a, b uint128) uint128 {
+ lo, c := bits.Add64(a.lo, b.lo, 0)
+ hi, c := bits.Add64(a.hi, b.hi, c)
+ if c != 0 {
+ panic("poly1305: unexpected overflow")
+ }
+ return uint128{lo, hi}
+}
+
+func shiftRightBy2(a uint128) uint128 {
+ a.lo = a.lo>>2 | (a.hi&3)<<62
+ a.hi = a.hi >> 2
+ return a
+}
+
+// updateGeneric absorbs msg into the state.h accumulator. For each chunk m of
+// 128 bits of message, it computes
+//
+// h₊ = (h + m) * r mod 2¹³⁰ - 5
+//
+// If the msg length is not a multiple of TagSize, it assumes the last
+// incomplete chunk is the final one.
+func updateGeneric(state *macState, msg []byte) {
+ h0, h1, h2 := state.h[0], state.h[1], state.h[2]
+ r0, r1 := state.r[0], state.r[1]
+
+ for len(msg) > 0 {
+ var c uint64
+
+ // For the first step, h + m, we use a chain of bits.Add64 intrinsics.
+ // The resulting value of h might exceed 2¹³⁰ - 5, but will be partially
+ // reduced at the end of the multiplication below.
+ //
+ // The spec requires us to set a bit just above the message size, not to
+ // hide leading zeroes. For full chunks, that's 1 << 128, so we can just
+ // add 1 to the most significant (2¹²⁸) limb, h2.
+ if len(msg) >= TagSize {
+ h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0)
+ h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c)
+ h2 += c + 1
+
+ msg = msg[TagSize:]
+ } else {
+ var buf [TagSize]byte
+ copy(buf[:], msg)
+ buf[len(msg)] = 1
+
+ h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0)
+ h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c)
+ h2 += c
+
+ msg = nil
+ }
+
+ // Multiplication of big number limbs is similar to elementary school
+ // columnar multiplication. Instead of digits, there are 64-bit limbs.
+ //
+ // We are multiplying a 3 limbs number, h, by a 2 limbs number, r.
+ //
+ // h2 h1 h0 x
+ // r1 r0 =
+ // ----------------
+ // h2r0 h1r0 h0r0 <-- individual 128-bit products
+ // + h2r1 h1r1 h0r1
+ // ------------------------
+ // m3 m2 m1 m0 <-- result in 128-bit overlapping limbs
+ // ------------------------
+ // m3.hi m2.hi m1.hi m0.hi <-- carry propagation
+ // + m3.lo m2.lo m1.lo m0.lo
+ // -------------------------------
+ // t4 t3 t2 t1 t0 <-- final result in 64-bit limbs
+ //
+ // The main difference from pen-and-paper multiplication is that we do
+ // carry propagation in a separate step, as if we wrote two digit sums
+ // at first (the 128-bit limbs), and then carried the tens all at once.
+
+ h0r0 := mul64(h0, r0)
+ h1r0 := mul64(h1, r0)
+ h2r0 := mul64(h2, r0)
+ h0r1 := mul64(h0, r1)
+ h1r1 := mul64(h1, r1)
+ h2r1 := mul64(h2, r1)
+
+ // Since h2 is known to be at most 7 (5 + 1 + 1), and r0 and r1 have their
+ // top 4 bits cleared by rMask{0,1}, we know that their product is not going
+ // to overflow 64 bits, so we can ignore the high part of the products.
+ //
+ // This also means that the product doesn't have a fifth limb (t4).
+ if h2r0.hi != 0 {
+ panic("poly1305: unexpected overflow")
+ }
+ if h2r1.hi != 0 {
+ panic("poly1305: unexpected overflow")
+ }
+
+ m0 := h0r0
+ m1 := add128(h1r0, h0r1) // These two additions don't overflow thanks again
+ m2 := add128(h2r0, h1r1) // to the 4 masked bits at the top of r0 and r1.
+ m3 := h2r1
+
+ t0 := m0.lo
+ t1, c := bits.Add64(m1.lo, m0.hi, 0)
+ t2, c := bits.Add64(m2.lo, m1.hi, c)
+ t3, _ := bits.Add64(m3.lo, m2.hi, c)
+
+ // Now we have the result as 4 64-bit limbs, and we need to reduce it
+ // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do
+ // a cheap partial reduction according to the reduction identity
+ //
+ // c * 2¹³⁰ + n = c * 5 + n mod 2¹³⁰ - 5
+ //
+ // because 2¹³⁰ = 5 mod 2¹³⁰ - 5. Partial reduction since the result is
+ // likely to be larger than 2¹³⁰ - 5, but still small enough to fit the
+ // assumptions we make about h in the rest of the code.
+ //
+ // See also https://speakerdeck.com/gtank/engineering-prime-numbers?slide=23
+
+ // We split the final result at the 2¹³⁰ mark into h and cc, the carry.
+ // Note that the carry bits are effectively shifted left by 2, in other
+ // words, cc = c * 4 for the c in the reduction identity.
+ h0, h1, h2 = t0, t1, t2&maskLow2Bits
+ cc := uint128{t2 & maskNotLow2Bits, t3}
+
+ // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c.
+
+ h0, c = bits.Add64(h0, cc.lo, 0)
+ h1, c = bits.Add64(h1, cc.hi, c)
+ h2 += c
+
+ cc = shiftRightBy2(cc)
+
+ h0, c = bits.Add64(h0, cc.lo, 0)
+ h1, c = bits.Add64(h1, cc.hi, c)
+ h2 += c
+
+ // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most
+ //
+ // 5 * 2¹²⁸ + (2¹²⁸ - 1) = 6 * 2¹²⁸ - 1
+ }
+
+ state.h[0], state.h[1], state.h[2] = h0, h1, h2
+}
+
+const (
+ maskLow2Bits uint64 = 0x0000000000000003
+ maskNotLow2Bits uint64 = ^maskLow2Bits
+)
+
+// select64 returns x if v == 1 and y if v == 0, in constant time.
+func select64(v, x, y uint64) uint64 { return ^(v-1)&x | (v-1)&y }
+
+// [p0, p1, p2] is 2¹³⁰ - 5 in little endian order.
+const (
+ p0 = 0xFFFFFFFFFFFFFFFB
+ p1 = 0xFFFFFFFFFFFFFFFF
+ p2 = 0x0000000000000003
+)
+
+// finalize completes the modular reduction of h and computes
+//
+// out = h + s mod 2¹²⁸
+func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
+ h0, h1, h2 := h[0], h[1], h[2]
+
+ // After the partial reduction in updateGeneric, h might be more than
+ // 2¹³⁰ - 5, but will be less than 2 * (2¹³⁰ - 5). To complete the reduction
+ // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the
+ // result if the subtraction underflows, and t otherwise.
+
+ hMinusP0, b := bits.Sub64(h0, p0, 0)
+ hMinusP1, b := bits.Sub64(h1, p1, b)
+ _, b = bits.Sub64(h2, p2, b)
+
+ // h = h if h < p else h - p
+ h0 = select64(b, h0, hMinusP0)
+ h1 = select64(b, h1, hMinusP1)
+
+ // Finally, we compute the last Poly1305 step
+ //
+ // tag = h + s mod 2¹²⁸
+ //
+ // by just doing a wide addition with the 128 low bits of h and discarding
+ // the overflow.
+ h0, c := bits.Add64(h0, s[0], 0)
+ h1, _ = bits.Add64(h1, s[1], c)
+
+ binary.LittleEndian.PutUint64(out[0:8], h0)
+ binary.LittleEndian.PutUint64(out[8:16], h1)
+}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s
new file mode 100644
index 00000000..bc8361da
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_loong64.s
@@ -0,0 +1,123 @@
+// Copyright 2025 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 && !purego
+
+// func update(state *macState, msg []byte)
+TEXT ·update(SB), $0-32
+ MOVV state+0(FP), R4
+ MOVV msg_base+8(FP), R5
+ MOVV msg_len+16(FP), R6
+
+ MOVV $0x10, R7
+
+ MOVV (R4), R8 // h0
+ MOVV 8(R4), R9 // h1
+ MOVV 16(R4), R10 // h2
+ MOVV 24(R4), R11 // r0
+ MOVV 32(R4), R12 // r1
+
+ BLT R6, R7, bytes_between_0_and_15
+
+loop:
+ MOVV (R5), R14 // msg[0:8]
+ MOVV 8(R5), R16 // msg[8:16]
+ ADDV R14, R8, R8 // h0 (x1 + y1 = z1', if z1' < x1 then z1' overflow)
+ ADDV R16, R9, R27
+ SGTU R14, R8, R24 // h0.carry
+ SGTU R9, R27, R28
+ ADDV R27, R24, R9 // h1
+ SGTU R27, R9, R24
+ OR R24, R28, R24 // h1.carry
+ ADDV $0x01, R24, R24
+ ADDV R10, R24, R10 // h2
+
+ ADDV $16, R5, R5 // msg = msg[16:]
+
+multiply:
+ MULV R8, R11, R14 // h0r0.lo
+ MULHVU R8, R11, R15 // h0r0.hi
+ MULV R9, R11, R13 // h1r0.lo
+ MULHVU R9, R11, R16 // h1r0.hi
+ ADDV R13, R15, R15
+ SGTU R13, R15, R24
+ ADDV R24, R16, R16
+ MULV R10, R11, R25
+ ADDV R16, R25, R25
+ MULV R8, R12, R13 // h0r1.lo
+ MULHVU R8, R12, R16 // h0r1.hi
+ ADDV R13, R15, R15
+ SGTU R13, R15, R24
+ ADDV R24, R16, R16
+ MOVV R16, R8
+ MULV R10, R12, R26 // h2r1
+ MULV R9, R12, R13 // h1r1.lo
+ MULHVU R9, R12, R16 // h1r1.hi
+ ADDV R13, R25, R25
+ ADDV R16, R26, R27
+ SGTU R13, R25, R24
+ ADDV R27, R24, R26
+ ADDV R8, R25, R25
+ SGTU R8, R25, R24
+ ADDV R24, R26, R26
+ AND $3, R25, R10
+ AND $-4, R25, R17
+ ADDV R17, R14, R8
+ ADDV R26, R15, R27
+ SGTU R17, R8, R24
+ SGTU R26, R27, R28
+ ADDV R27, R24, R9
+ SGTU R27, R9, R24
+ OR R24, R28, R24
+ ADDV R24, R10, R10
+ SLLV $62, R26, R27
+ SRLV $2, R25, R28
+ SRLV $2, R26, R26
+ OR R27, R28, R25
+ ADDV R25, R8, R8
+ ADDV R26, R9, R27
+ SGTU R25, R8, R24
+ SGTU R26, R27, R28
+ ADDV R27, R24, R9
+ SGTU R27, R9, R24
+ OR R24, R28, R24
+ ADDV R24, R10, R10
+
+ SUBV $16, R6, R6
+ BGE R6, R7, loop
+
+bytes_between_0_and_15:
+ BEQ R6, R0, done
+ MOVV $1, R14
+ XOR R15, R15
+ ADDV R6, R5, R5
+
+flush_buffer:
+ MOVBU -1(R5), R25
+ SRLV $56, R14, R24
+ SLLV $8, R15, R28
+ SLLV $8, R14, R14
+ OR R24, R28, R15
+ XOR R25, R14, R14
+ SUBV $1, R6, R6
+ SUBV $1, R5, R5
+ BNE R6, R0, flush_buffer
+
+ ADDV R14, R8, R8
+ SGTU R14, R8, R24
+ ADDV R15, R9, R27
+ SGTU R15, R27, R28
+ ADDV R27, R24, R9
+ SGTU R27, R9, R24
+ OR R24, R28, R24
+ ADDV R10, R24, R10
+
+ MOVV $16, R6
+ JMP multiply
+
+done:
+ MOVV R8, (R4)
+ MOVV R9, 8(R4)
+ MOVV R10, 16(R4)
+ RET
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s
new file mode 100644
index 00000000..6899a1da
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64x.s
@@ -0,0 +1,187 @@
+// 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 && !purego && (ppc64 || ppc64le)
+
+#include "textflag.h"
+
+// This was ported from the amd64 implementation.
+
+#ifdef GOARCH_ppc64le
+#define LE_MOVD MOVD
+#define LE_MOVWZ MOVWZ
+#define LE_MOVHZ MOVHZ
+#else
+#define LE_MOVD MOVDBR
+#define LE_MOVWZ MOVWBR
+#define LE_MOVHZ MOVHBR
+#endif
+
+#define POLY1305_ADD(msg, h0, h1, h2, t0, t1, t2) \
+ LE_MOVD (msg)( R0), t0; \
+ LE_MOVD (msg)(R24), t1; \
+ MOVD $1, t2; \
+ ADDC t0, h0, h0; \
+ ADDE t1, h1, h1; \
+ ADDE t2, h2; \
+ ADD $16, msg
+
+#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \
+ MULLD r0, h0, t0; \
+ MULHDU r0, h0, t1; \
+ MULLD r0, h1, t4; \
+ MULHDU r0, h1, t5; \
+ ADDC t4, t1, t1; \
+ MULLD r0, h2, t2; \
+ MULHDU r1, h0, t4; \
+ MULLD r1, h0, h0; \
+ ADDE t5, t2, t2; \
+ ADDC h0, t1, t1; \
+ MULLD h2, r1, t3; \
+ ADDZE t4, h0; \
+ MULHDU r1, h1, t5; \
+ MULLD r1, h1, t4; \
+ ADDC t4, t2, t2; \
+ ADDE t5, t3, t3; \
+ ADDC h0, t2, t2; \
+ MOVD $-4, t4; \
+ ADDZE t3; \
+ RLDICL $0, t2, $62, h2; \
+ AND t2, t4, h0; \
+ ADDC t0, h0, h0; \
+ ADDE t3, t1, h1; \
+ SLD $62, t3, t4; \
+ SRD $2, t2; \
+ ADDZE h2; \
+ OR t4, t2, t2; \
+ SRD $2, t3; \
+ ADDC t2, h0, h0; \
+ ADDE t3, h1, h1; \
+ ADDZE h2
+
+// func update(state *[7]uint64, msg []byte)
+TEXT ·update(SB), $0-32
+ MOVD state+0(FP), R3
+ MOVD msg_base+8(FP), R4
+ MOVD msg_len+16(FP), R5
+
+ MOVD 0(R3), R8 // h0
+ MOVD 8(R3), R9 // h1
+ MOVD 16(R3), R10 // h2
+ MOVD 24(R3), R11 // r0
+ MOVD 32(R3), R12 // r1
+
+ MOVD $8, R24
+
+ CMP R5, $16
+ BLT bytes_between_0_and_15
+
+loop:
+ POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22)
+
+ PCALIGN $16
+multiply:
+ POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21)
+ ADD $-16, R5
+ CMP R5, $16
+ BGE loop
+
+bytes_between_0_and_15:
+ CMP R5, $0
+ BEQ done
+ MOVD $0, R16 // h0
+ MOVD $0, R17 // h1
+
+flush_buffer:
+ CMP R5, $8
+ BLE just1
+
+ MOVD $8, R21
+ SUB R21, R5, R21
+
+ // Greater than 8 -- load the rightmost remaining bytes in msg
+ // and put into R17 (h1)
+ LE_MOVD (R4)(R21), R17
+ MOVD $16, R22
+
+ // Find the offset to those bytes
+ SUB R5, R22, R22
+ SLD $3, R22
+
+ // Shift to get only the bytes in msg
+ SRD R22, R17, R17
+
+ // Put 1 at high end
+ MOVD $1, R23
+ SLD $3, R21
+ SLD R21, R23, R23
+ OR R23, R17, R17
+
+ // Remainder is 8
+ MOVD $8, R5
+
+just1:
+ CMP R5, $8
+ BLT less8
+
+ // Exactly 8
+ LE_MOVD (R4), R16
+
+ CMP R17, $0
+
+ // Check if we've already set R17; if not
+ // set 1 to indicate end of msg.
+ BNE carry
+ MOVD $1, R17
+ BR carry
+
+less8:
+ MOVD $0, R16 // h0
+ MOVD $0, R22 // shift count
+ CMP R5, $4
+ BLT less4
+ LE_MOVWZ (R4), R16
+ ADD $4, R4
+ ADD $-4, R5
+ MOVD $32, R22
+
+less4:
+ CMP R5, $2
+ BLT less2
+ LE_MOVHZ (R4), R21
+ SLD R22, R21, R21
+ OR R16, R21, R16
+ ADD $16, R22
+ ADD $-2, R5
+ ADD $2, R4
+
+less2:
+ CMP R5, $0
+ BEQ insert1
+ MOVBZ (R4), R21
+ SLD R22, R21, R21
+ OR R16, R21, R16
+ ADD $8, R22
+
+insert1:
+ // Insert 1 at end of msg
+ MOVD $1, R21
+ SLD R22, R21, R21
+ OR R16, R21, R16
+
+carry:
+ // Add new values to h0, h1, h2
+ ADDC R16, R8
+ ADDE R17, R9
+ ADDZE R10, R10
+ MOVD $16, R5
+ ADD R5, R4
+ BR multiply
+
+done:
+ // Save h0, h1, h2 in state
+ MOVD R8, 0(R3)
+ MOVD R9, 8(R3)
+ MOVD R10, 16(R3)
+ RET
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go
new file mode 100644
index 00000000..e1d033a4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go
@@ -0,0 +1,76 @@
+// 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 && !purego
+
+package poly1305
+
+import (
+ "golang.org/x/sys/cpu"
+)
+
+// updateVX is an assembly implementation of Poly1305 that uses vector
+// instructions. It must only be called if the vector facility (vx) is
+// available.
+//
+//go:noescape
+func updateVX(state *macState, msg []byte)
+
+// mac is a replacement for macGeneric that uses a larger buffer and redirects
+// calls that would have gone to updateGeneric to updateVX if the vector
+// facility is installed.
+//
+// A larger buffer is required for good performance because the vector
+// implementation has a higher fixed cost per call than the generic
+// implementation.
+type mac struct {
+ macState
+
+ buffer [16 * TagSize]byte // size must be a multiple of block size (16)
+ offset int
+}
+
+func (h *mac) Write(p []byte) (int, error) {
+ nn := len(p)
+ if h.offset > 0 {
+ n := copy(h.buffer[h.offset:], p)
+ if h.offset+n < len(h.buffer) {
+ h.offset += n
+ return nn, nil
+ }
+ p = p[n:]
+ h.offset = 0
+ if cpu.S390X.HasVX {
+ updateVX(&h.macState, h.buffer[:])
+ } else {
+ updateGeneric(&h.macState, h.buffer[:])
+ }
+ }
+
+ tail := len(p) % len(h.buffer) // number of bytes to copy into buffer
+ body := len(p) - tail // number of bytes to process now
+ if body > 0 {
+ if cpu.S390X.HasVX {
+ updateVX(&h.macState, p[:body])
+ } else {
+ updateGeneric(&h.macState, p[:body])
+ }
+ }
+ h.offset = copy(h.buffer[:], p[body:]) // copy tail bytes - can be 0
+ return nn, nil
+}
+
+func (h *mac) Sum(out *[TagSize]byte) {
+ state := h.macState
+ remainder := h.buffer[:h.offset]
+
+ // Use the generic implementation if we have 2 or fewer blocks left
+ // to sum. The vector implementation has a higher startup time.
+ if cpu.S390X.HasVX && len(remainder) > 2*TagSize {
+ updateVX(&state, remainder)
+ } else if len(remainder) > 0 {
+ updateGeneric(&state, remainder)
+ }
+ finalize(out, &state.h, &state.s)
+}
diff --git a/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s
new file mode 100644
index 00000000..0fe3a7c2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s
@@ -0,0 +1,503 @@
+// 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 && !purego
+
+#include "textflag.h"
+
+// This implementation of Poly1305 uses the vector facility (vx)
+// to process up to 2 blocks (32 bytes) per iteration using an
+// algorithm based on the one described in:
+//
+// NEON crypto, Daniel J. Bernstein & Peter Schwabe
+// https://cryptojedi.org/papers/neoncrypto-20120320.pdf
+//
+// This algorithm uses 5 26-bit limbs to represent a 130-bit
+// value. These limbs are, for the most part, zero extended and
+// placed into 64-bit vector register elements. Each vector
+// register is 128-bits wide and so holds 2 of these elements.
+// Using 26-bit limbs allows us plenty of headroom to accommodate
+// accumulations before and after multiplication without
+// overflowing either 32-bits (before multiplication) or 64-bits
+// (after multiplication).
+//
+// In order to parallelise the operations required to calculate
+// the sum we use two separate accumulators and then sum those
+// in an extra final step. For compatibility with the generic
+// implementation we perform this summation at the end of every
+// updateVX call.
+//
+// To use two accumulators we must multiply the message blocks
+// by r² rather than r. Only the final message block should be
+// multiplied by r.
+//
+// Example:
+//
+// We want to calculate the sum (h) for a 64 byte message (m):
+//
+// h = m[0:16]r⁴ + m[16:32]r³ + m[32:48]r² + m[48:64]r
+//
+// To do this we split the calculation into the even indices
+// and odd indices of the message. These form our SIMD 'lanes':
+//
+// h = m[ 0:16]r⁴ + m[32:48]r² + <- lane 0
+// m[16:32]r³ + m[48:64]r <- lane 1
+//
+// To calculate this iteratively we refactor so that both lanes
+// are written in terms of r² and r:
+//
+// h = (m[ 0:16]r² + m[32:48])r² + <- lane 0
+// (m[16:32]r² + m[48:64])r <- lane 1
+// ^ ^
+// | coefficients for second iteration
+// coefficients for first iteration
+//
+// So in this case we would have two iterations. In the first
+// both lanes are multiplied by r². In the second only the
+// first lane is multiplied by r² and the second lane is
+// instead multiplied by r. This gives use the odd and even
+// powers of r that we need from the original equation.
+//
+// Notation:
+//
+// h - accumulator
+// r - key
+// m - message
+//
+// [a, b] - SIMD register holding two 64-bit values
+// [a, b, c, d] - SIMD register holding four 32-bit values
+// xᵢ[n] - limb n of variable x with bit width i
+//
+// Limbs are expressed in little endian order, so for 26-bit
+// limbs x₂₆[4] will be the most significant limb and x₂₆[0]
+// will be the least significant limb.
+
+// masking constants
+#define MOD24 V0 // [0x0000000000ffffff, 0x0000000000ffffff] - mask low 24-bits
+#define MOD26 V1 // [0x0000000003ffffff, 0x0000000003ffffff] - mask low 26-bits
+
+// expansion constants (see EXPAND macro)
+#define EX0 V2
+#define EX1 V3
+#define EX2 V4
+
+// key (r², r or 1 depending on context)
+#define R_0 V5
+#define R_1 V6
+#define R_2 V7
+#define R_3 V8
+#define R_4 V9
+
+// precalculated coefficients (5r², 5r or 0 depending on context)
+#define R5_1 V10
+#define R5_2 V11
+#define R5_3 V12
+#define R5_4 V13
+
+// message block (m)
+#define M_0 V14
+#define M_1 V15
+#define M_2 V16
+#define M_3 V17
+#define M_4 V18
+
+// accumulator (h)
+#define H_0 V19
+#define H_1 V20
+#define H_2 V21
+#define H_3 V22
+#define H_4 V23
+
+// temporary registers (for short-lived values)
+#define T_0 V24
+#define T_1 V25
+#define T_2 V26
+#define T_3 V27
+#define T_4 V28
+
+GLOBL ·constants<>(SB), RODATA, $0x30
+// EX0
+DATA ·constants<>+0x00(SB)/8, $0x0006050403020100
+DATA ·constants<>+0x08(SB)/8, $0x1016151413121110
+// EX1
+DATA ·constants<>+0x10(SB)/8, $0x060c0b0a09080706
+DATA ·constants<>+0x18(SB)/8, $0x161c1b1a19181716
+// EX2
+DATA ·constants<>+0x20(SB)/8, $0x0d0d0d0d0d0f0e0d
+DATA ·constants<>+0x28(SB)/8, $0x1d1d1d1d1d1f1e1d
+
+// MULTIPLY multiplies each lane of f and g, partially reduced
+// modulo 2¹³⁰ - 5. The result, h, consists of partial products
+// in each lane that need to be reduced further to produce the
+// final result.
+//
+// h₁₃₀ = (f₁₃₀g₁₃₀) % 2¹³⁰ + (5f₁₃₀g₁₃₀) / 2¹³⁰
+//
+// Note that the multiplication by 5 of the high bits is
+// achieved by precalculating the multiplication of four of the
+// g coefficients by 5. These are g51-g54.
+#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \
+ VMLOF f0, g0, h0 \
+ VMLOF f0, g3, h3 \
+ VMLOF f0, g1, h1 \
+ VMLOF f0, g4, h4 \
+ VMLOF f0, g2, h2 \
+ VMLOF f1, g54, T_0 \
+ VMLOF f1, g2, T_3 \
+ VMLOF f1, g0, T_1 \
+ VMLOF f1, g3, T_4 \
+ VMLOF f1, g1, T_2 \
+ VMALOF f2, g53, h0, h0 \
+ VMALOF f2, g1, h3, h3 \
+ VMALOF f2, g54, h1, h1 \
+ VMALOF f2, g2, h4, h4 \
+ VMALOF f2, g0, h2, h2 \
+ VMALOF f3, g52, T_0, T_0 \
+ VMALOF f3, g0, T_3, T_3 \
+ VMALOF f3, g53, T_1, T_1 \
+ VMALOF f3, g1, T_4, T_4 \
+ VMALOF f3, g54, T_2, T_2 \
+ VMALOF f4, g51, h0, h0 \
+ VMALOF f4, g54, h3, h3 \
+ VMALOF f4, g52, h1, h1 \
+ VMALOF f4, g0, h4, h4 \
+ VMALOF f4, g53, h2, h2 \
+ VAG T_0, h0, h0 \
+ VAG T_3, h3, h3 \
+ VAG T_1, h1, h1 \
+ VAG T_4, h4, h4 \
+ VAG T_2, h2, h2
+
+// REDUCE performs the following carry operations in four
+// stages, as specified in Bernstein & Schwabe:
+//
+// 1: h₂₆[0]->h₂₆[1] h₂₆[3]->h₂₆[4]
+// 2: h₂₆[1]->h₂₆[2] h₂₆[4]->h₂₆[0]
+// 3: h₂₆[0]->h₂₆[1] h₂₆[2]->h₂₆[3]
+// 4: h₂₆[3]->h₂₆[4]
+//
+// The result is that all of the limbs are limited to 26-bits
+// except for h₂₆[1] and h₂₆[4] which are limited to 27-bits.
+//
+// Note that although each limb is aligned at 26-bit intervals
+// they may contain values that exceed 2²⁶ - 1, hence the need
+// to carry the excess bits in each limb.
+#define REDUCE(h0, h1, h2, h3, h4) \
+ VESRLG $26, h0, T_0 \
+ VESRLG $26, h3, T_1 \
+ VN MOD26, h0, h0 \
+ VN MOD26, h3, h3 \
+ VAG T_0, h1, h1 \
+ VAG T_1, h4, h4 \
+ VESRLG $26, h1, T_2 \
+ VESRLG $26, h4, T_3 \
+ VN MOD26, h1, h1 \
+ VN MOD26, h4, h4 \
+ VESLG $2, T_3, T_4 \
+ VAG T_3, T_4, T_4 \
+ VAG T_2, h2, h2 \
+ VAG T_4, h0, h0 \
+ VESRLG $26, h2, T_0 \
+ VESRLG $26, h0, T_1 \
+ VN MOD26, h2, h2 \
+ VN MOD26, h0, h0 \
+ VAG T_0, h3, h3 \
+ VAG T_1, h1, h1 \
+ VESRLG $26, h3, T_2 \
+ VN MOD26, h3, h3 \
+ VAG T_2, h4, h4
+
+// EXPAND splits the 128-bit little-endian values in0 and in1
+// into 26-bit big-endian limbs and places the results into
+// the first and second lane of d₂₆[0:4] respectively.
+//
+// The EX0, EX1 and EX2 constants are arrays of byte indices
+// for permutation. The permutation both reverses the bytes
+// in the input and ensures the bytes are copied into the
+// destination limb ready to be shifted into their final
+// position.
+#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \
+ VPERM in0, in1, EX0, d0 \
+ VPERM in0, in1, EX1, d2 \
+ VPERM in0, in1, EX2, d4 \
+ VESRLG $26, d0, d1 \
+ VESRLG $30, d2, d3 \
+ VESRLG $4, d2, d2 \
+ VN MOD26, d0, d0 \ // [in0₂₆[0], in1₂₆[0]]
+ VN MOD26, d3, d3 \ // [in0₂₆[3], in1₂₆[3]]
+ VN MOD26, d1, d1 \ // [in0₂₆[1], in1₂₆[1]]
+ VN MOD24, d4, d4 \ // [in0₂₆[4], in1₂₆[4]]
+ VN MOD26, d2, d2 // [in0₂₆[2], in1₂₆[2]]
+
+// func updateVX(state *macState, msg []byte)
+TEXT ·updateVX(SB), NOSPLIT, $0
+ MOVD state+0(FP), R1
+ LMG msg+8(FP), R2, R3 // R2=msg_base, R3=msg_len
+
+ // load EX0, EX1 and EX2
+ MOVD $·constants<>(SB), R5
+ VLM (R5), EX0, EX2
+
+ // generate masks
+ VGMG $(64-24), $63, MOD24 // [0x00ffffff, 0x00ffffff]
+ VGMG $(64-26), $63, MOD26 // [0x03ffffff, 0x03ffffff]
+
+ // load h (accumulator) and r (key) from state
+ VZERO T_1 // [0, 0]
+ VL 0(R1), T_0 // [h₆₄[0], h₆₄[1]]
+ VLEG $0, 16(R1), T_1 // [h₆₄[2], 0]
+ VL 24(R1), T_2 // [r₆₄[0], r₆₄[1]]
+ VPDI $0, T_0, T_2, T_3 // [h₆₄[0], r₆₄[0]]
+ VPDI $5, T_0, T_2, T_4 // [h₆₄[1], r₆₄[1]]
+
+ // unpack h and r into 26-bit limbs
+ // note: h₆₄[2] may have the low 3 bits set, so h₂₆[4] is a 27-bit value
+ VN MOD26, T_3, H_0 // [h₂₆[0], r₂₆[0]]
+ VZERO H_1 // [0, 0]
+ VZERO H_3 // [0, 0]
+ VGMG $(64-12-14), $(63-12), T_0 // [0x03fff000, 0x03fff000] - 26-bit mask with low 12 bits masked out
+ VESLG $24, T_1, T_1 // [h₆₄[2]<<24, 0]
+ VERIMG $-26&63, T_3, MOD26, H_1 // [h₂₆[1], r₂₆[1]]
+ VESRLG $+52&63, T_3, H_2 // [h₂₆[2], r₂₆[2]] - low 12 bits only
+ VERIMG $-14&63, T_4, MOD26, H_3 // [h₂₆[1], r₂₆[1]]
+ VESRLG $40, T_4, H_4 // [h₂₆[4], r₂₆[4]] - low 24 bits only
+ VERIMG $+12&63, T_4, T_0, H_2 // [h₂₆[2], r₂₆[2]] - complete
+ VO T_1, H_4, H_4 // [h₂₆[4], r₂₆[4]] - complete
+
+ // replicate r across all 4 vector elements
+ VREPF $3, H_0, R_0 // [r₂₆[0], r₂₆[0], r₂₆[0], r₂₆[0]]
+ VREPF $3, H_1, R_1 // [r₂₆[1], r₂₆[1], r₂₆[1], r₂₆[1]]
+ VREPF $3, H_2, R_2 // [r₂₆[2], r₂₆[2], r₂₆[2], r₂₆[2]]
+ VREPF $3, H_3, R_3 // [r₂₆[3], r₂₆[3], r₂₆[3], r₂₆[3]]
+ VREPF $3, H_4, R_4 // [r₂₆[4], r₂₆[4], r₂₆[4], r₂₆[4]]
+
+ // zero out lane 1 of h
+ VLEIG $1, $0, H_0 // [h₂₆[0], 0]
+ VLEIG $1, $0, H_1 // [h₂₆[1], 0]
+ VLEIG $1, $0, H_2 // [h₂₆[2], 0]
+ VLEIG $1, $0, H_3 // [h₂₆[3], 0]
+ VLEIG $1, $0, H_4 // [h₂₆[4], 0]
+
+ // calculate 5r (ignore least significant limb)
+ VREPIF $5, T_0
+ VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r₂₆[1], 5r₂₆[1], 5r₂₆[1]]
+ VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r₂₆[2], 5r₂₆[2], 5r₂₆[2]]
+ VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r₂₆[3], 5r₂₆[3], 5r₂₆[3]]
+ VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r₂₆[4], 5r₂₆[4], 5r₂₆[4]]
+
+ // skip r² calculation if we are only calculating one block
+ CMPBLE R3, $16, skip
+
+ // calculate r²
+ MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, M_0, M_1, M_2, M_3, M_4)
+ REDUCE(M_0, M_1, M_2, M_3, M_4)
+ VGBM $0x0f0f, T_0
+ VERIMG $0, M_0, T_0, R_0 // [r₂₆[0], r²₂₆[0], r₂₆[0], r²₂₆[0]]
+ VERIMG $0, M_1, T_0, R_1 // [r₂₆[1], r²₂₆[1], r₂₆[1], r²₂₆[1]]
+ VERIMG $0, M_2, T_0, R_2 // [r₂₆[2], r²₂₆[2], r₂₆[2], r²₂₆[2]]
+ VERIMG $0, M_3, T_0, R_3 // [r₂₆[3], r²₂₆[3], r₂₆[3], r²₂₆[3]]
+ VERIMG $0, M_4, T_0, R_4 // [r₂₆[4], r²₂₆[4], r₂₆[4], r²₂₆[4]]
+
+ // calculate 5r² (ignore least significant limb)
+ VREPIF $5, T_0
+ VMLF T_0, R_1, R5_1 // [5r₂₆[1], 5r²₂₆[1], 5r₂₆[1], 5r²₂₆[1]]
+ VMLF T_0, R_2, R5_2 // [5r₂₆[2], 5r²₂₆[2], 5r₂₆[2], 5r²₂₆[2]]
+ VMLF T_0, R_3, R5_3 // [5r₂₆[3], 5r²₂₆[3], 5r₂₆[3], 5r²₂₆[3]]
+ VMLF T_0, R_4, R5_4 // [5r₂₆[4], 5r²₂₆[4], 5r₂₆[4], 5r²₂₆[4]]
+
+loop:
+ CMPBLE R3, $32, b2 // 2 or fewer blocks remaining, need to change key coefficients
+
+ // load next 2 blocks from message
+ VLM (R2), T_0, T_1
+
+ // update message slice
+ SUB $32, R3
+ MOVD $32(R2), R2
+
+ // unpack message blocks into 26-bit big-endian limbs
+ EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
+
+ // add 2¹²⁸ to each message block value
+ VLEIB $4, $1, M_4
+ VLEIB $12, $1, M_4
+
+multiply:
+ // accumulate the incoming message
+ VAG H_0, M_0, M_0
+ VAG H_3, M_3, M_3
+ VAG H_1, M_1, M_1
+ VAG H_4, M_4, M_4
+ VAG H_2, M_2, M_2
+
+ // multiply the accumulator by the key coefficient
+ MULTIPLY(M_0, M_1, M_2, M_3, M_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4)
+
+ // carry and partially reduce the partial products
+ REDUCE(H_0, H_1, H_2, H_3, H_4)
+
+ CMPBNE R3, $0, loop
+
+finish:
+ // sum lane 0 and lane 1 and put the result in lane 1
+ VZERO T_0
+ VSUMQG H_0, T_0, H_0
+ VSUMQG H_3, T_0, H_3
+ VSUMQG H_1, T_0, H_1
+ VSUMQG H_4, T_0, H_4
+ VSUMQG H_2, T_0, H_2
+
+ // reduce again after summation
+ // TODO(mundaym): there might be a more efficient way to do this
+ // now that we only have 1 active lane. For example, we could
+ // simultaneously pack the values as we reduce them.
+ REDUCE(H_0, H_1, H_2, H_3, H_4)
+
+ // carry h[1] through to h[4] so that only h[4] can exceed 2²⁶ - 1
+ // TODO(mundaym): in testing this final carry was unnecessary.
+ // Needs a proof before it can be removed though.
+ VESRLG $26, H_1, T_1
+ VN MOD26, H_1, H_1
+ VAQ T_1, H_2, H_2
+ VESRLG $26, H_2, T_2
+ VN MOD26, H_2, H_2
+ VAQ T_2, H_3, H_3
+ VESRLG $26, H_3, T_3
+ VN MOD26, H_3, H_3
+ VAQ T_3, H_4, H_4
+
+ // h is now < 2(2¹³⁰ - 5)
+ // Pack each lane in h₂₆[0:4] into h₁₂₈[0:1].
+ VESLG $26, H_1, H_1
+ VESLG $26, H_3, H_3
+ VO H_0, H_1, H_0
+ VO H_2, H_3, H_2
+ VESLG $4, H_2, H_2
+ VLEIB $7, $48, H_1
+ VSLB H_1, H_2, H_2
+ VO H_0, H_2, H_0
+ VLEIB $7, $104, H_1
+ VSLB H_1, H_4, H_3
+ VO H_3, H_0, H_0
+ VLEIB $7, $24, H_1
+ VSRLB H_1, H_4, H_1
+
+ // update state
+ VSTEG $1, H_0, 0(R1)
+ VSTEG $0, H_0, 8(R1)
+ VSTEG $1, H_1, 16(R1)
+ RET
+
+b2: // 2 or fewer blocks remaining
+ CMPBLE R3, $16, b1
+
+ // Load the 2 remaining blocks (17-32 bytes remaining).
+ MOVD $-17(R3), R0 // index of final byte to load modulo 16
+ VL (R2), T_0 // load full 16 byte block
+ VLL R0, 16(R2), T_1 // load final (possibly partial) block and pad with zeros to 16 bytes
+
+ // The Poly1305 algorithm requires that a 1 bit be appended to
+ // each message block. If the final block is less than 16 bytes
+ // long then it is easiest to insert the 1 before the message
+ // block is split into 26-bit limbs. If, on the other hand, the
+ // final message block is 16 bytes long then we append the 1 bit
+ // after expansion as normal.
+ MOVBZ $1, R0
+ MOVD $-16(R3), R3 // index of byte in last block to insert 1 at (could be 16)
+ CMPBEQ R3, $16, 2(PC) // skip the insertion if the final block is 16 bytes long
+ VLVGB R3, R0, T_1 // insert 1 into the byte at index R3
+
+ // Split both blocks into 26-bit limbs in the appropriate lanes.
+ EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
+
+ // Append a 1 byte to the end of the second to last block.
+ VLEIB $4, $1, M_4
+
+ // Append a 1 byte to the end of the last block only if it is a
+ // full 16 byte block.
+ CMPBNE R3, $16, 2(PC)
+ VLEIB $12, $1, M_4
+
+ // Finally, set up the coefficients for the final multiplication.
+ // We have previously saved r and 5r in the 32-bit even indexes
+ // of the R_[0-4] and R5_[1-4] coefficient registers.
+ //
+ // We want lane 0 to be multiplied by r² so that can be kept the
+ // same. We want lane 1 to be multiplied by r so we need to move
+ // the saved r value into the 32-bit odd index in lane 1 by
+ // rotating the 64-bit lane by 32.
+ VGBM $0x00ff, T_0 // [0, 0xffffffffffffffff] - mask lane 1 only
+ VERIMG $32, R_0, T_0, R_0 // [_, r²₂₆[0], _, r₂₆[0]]
+ VERIMG $32, R_1, T_0, R_1 // [_, r²₂₆[1], _, r₂₆[1]]
+ VERIMG $32, R_2, T_0, R_2 // [_, r²₂₆[2], _, r₂₆[2]]
+ VERIMG $32, R_3, T_0, R_3 // [_, r²₂₆[3], _, r₂₆[3]]
+ VERIMG $32, R_4, T_0, R_4 // [_, r²₂₆[4], _, r₂₆[4]]
+ VERIMG $32, R5_1, T_0, R5_1 // [_, 5r²₂₆[1], _, 5r₂₆[1]]
+ VERIMG $32, R5_2, T_0, R5_2 // [_, 5r²₂₆[2], _, 5r₂₆[2]]
+ VERIMG $32, R5_3, T_0, R5_3 // [_, 5r²₂₆[3], _, 5r₂₆[3]]
+ VERIMG $32, R5_4, T_0, R5_4 // [_, 5r²₂₆[4], _, 5r₂₆[4]]
+
+ MOVD $0, R3
+ BR multiply
+
+skip:
+ CMPBEQ R3, $0, finish
+
+b1: // 1 block remaining
+
+ // Load the final block (1-16 bytes). This will be placed into
+ // lane 0.
+ MOVD $-1(R3), R0
+ VLL R0, (R2), T_0 // pad to 16 bytes with zeros
+
+ // The Poly1305 algorithm requires that a 1 bit be appended to
+ // each message block. If the final block is less than 16 bytes
+ // long then it is easiest to insert the 1 before the message
+ // block is split into 26-bit limbs. If, on the other hand, the
+ // final message block is 16 bytes long then we append the 1 bit
+ // after expansion as normal.
+ MOVBZ $1, R0
+ CMPBEQ R3, $16, 2(PC)
+ VLVGB R3, R0, T_0
+
+ // Set the message block in lane 1 to the value 0 so that it
+ // can be accumulated without affecting the final result.
+ VZERO T_1
+
+ // Split the final message block into 26-bit limbs in lane 0.
+ // Lane 1 will be contain 0.
+ EXPAND(T_0, T_1, M_0, M_1, M_2, M_3, M_4)
+
+ // Append a 1 byte to the end of the last block only if it is a
+ // full 16 byte block.
+ CMPBNE R3, $16, 2(PC)
+ VLEIB $4, $1, M_4
+
+ // We have previously saved r and 5r in the 32-bit even indexes
+ // of the R_[0-4] and R5_[1-4] coefficient registers.
+ //
+ // We want lane 0 to be multiplied by r so we need to move the
+ // saved r value into the 32-bit odd index in lane 0. We want
+ // lane 1 to be set to the value 1. This makes multiplication
+ // a no-op. We do this by setting lane 1 in every register to 0
+ // and then just setting the 32-bit index 3 in R_0 to 1.
+ VZERO T_0
+ MOVD $0, R0
+ MOVD $0x10111213, R12
+ VLVGP R12, R0, T_1 // [_, 0x10111213, _, 0x00000000]
+ VPERM T_0, R_0, T_1, R_0 // [_, r₂₆[0], _, 0]
+ VPERM T_0, R_1, T_1, R_1 // [_, r₂₆[1], _, 0]
+ VPERM T_0, R_2, T_1, R_2 // [_, r₂₆[2], _, 0]
+ VPERM T_0, R_3, T_1, R_3 // [_, r₂₆[3], _, 0]
+ VPERM T_0, R_4, T_1, R_4 // [_, r₂₆[4], _, 0]
+ VPERM T_0, R5_1, T_1, R5_1 // [_, 5r₂₆[1], _, 0]
+ VPERM T_0, R5_2, T_1, R5_2 // [_, 5r₂₆[2], _, 0]
+ VPERM T_0, R5_3, T_1, R5_3 // [_, 5r₂₆[3], _, 0]
+ VPERM T_0, R5_4, T_1, R5_4 // [_, 5r₂₆[4], _, 0]
+
+ // Set the value of lane 1 to be 1.
+ VLEIF $3, $1, R_0 // [_, r₂₆[0], _, 1]
+
+ MOVD $0, R3
+ BR multiply
diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go
new file mode 100644
index 00000000..a51269d9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/hashes.go
@@ -0,0 +1,95 @@
+// 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.
+
+// Package sha3 implements the SHA-3 hash algorithms and the SHAKE extendable
+// output functions defined in FIPS 202.
+//
+// Most of this package is a wrapper around the crypto/sha3 package in the
+// standard library. The only exception is the legacy Keccak hash functions.
+package sha3
+
+import (
+ "crypto/sha3"
+ "hash"
+)
+
+// New224 creates a new SHA3-224 hash.
+// Its generic security strength is 224 bits against preimage attacks,
+// and 112 bits against collision attacks.
+//
+// It is a wrapper for the [sha3.New224] function in the standard library.
+//
+//go:fix inline
+func New224() hash.Hash {
+ return sha3.New224()
+}
+
+// New256 creates a new SHA3-256 hash.
+// Its generic security strength is 256 bits against preimage attacks,
+// and 128 bits against collision attacks.
+//
+// It is a wrapper for the [sha3.New256] function in the standard library.
+//
+//go:fix inline
+func New256() hash.Hash {
+ return sha3.New256()
+}
+
+// New384 creates a new SHA3-384 hash.
+// Its generic security strength is 384 bits against preimage attacks,
+// and 192 bits against collision attacks.
+//
+// It is a wrapper for the [sha3.New384] function in the standard library.
+//
+//go:fix inline
+func New384() hash.Hash {
+ return sha3.New384()
+}
+
+// New512 creates a new SHA3-512 hash.
+// Its generic security strength is 512 bits against preimage attacks,
+// and 256 bits against collision attacks.
+//
+// It is a wrapper for the [sha3.New512] function in the standard library.
+//
+//go:fix inline
+func New512() hash.Hash {
+ return sha3.New512()
+}
+
+// Sum224 returns the SHA3-224 digest of the data.
+//
+// It is a wrapper for the [sha3.Sum224] function in the standard library.
+//
+//go:fix inline
+func Sum224(data []byte) [28]byte {
+ return sha3.Sum224(data)
+}
+
+// Sum256 returns the SHA3-256 digest of the data.
+//
+// It is a wrapper for the [sha3.Sum256] function in the standard library.
+//
+//go:fix inline
+func Sum256(data []byte) [32]byte {
+ return sha3.Sum256(data)
+}
+
+// Sum384 returns the SHA3-384 digest of the data.
+//
+// It is a wrapper for the [sha3.Sum384] function in the standard library.
+//
+//go:fix inline
+func Sum384(data []byte) [48]byte {
+ return sha3.Sum384(data)
+}
+
+// Sum512 returns the SHA3-512 digest of the data.
+//
+// It is a wrapper for the [sha3.Sum512] function in the standard library.
+//
+//go:fix inline
+func Sum512(data []byte) [64]byte {
+ return sha3.Sum512(data)
+}
diff --git a/vendor/golang.org/x/crypto/sha3/legacy_hash.go b/vendor/golang.org/x/crypto/sha3/legacy_hash.go
new file mode 100644
index 00000000..b8784536
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/legacy_hash.go
@@ -0,0 +1,263 @@
+// 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.
+
+package sha3
+
+// This implementation is only used for NewLegacyKeccak256 and
+// NewLegacyKeccak512, which are not implemented by crypto/sha3.
+// All other functions in this package are wrappers around crypto/sha3.
+
+import (
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "hash"
+ "unsafe"
+
+ "golang.org/x/sys/cpu"
+)
+
+const (
+ dsbyteKeccak = 0b00000001
+
+ // rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in
+ // bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits.
+ rateK256 = (1600 - 256) / 8
+ rateK512 = (1600 - 512) / 8
+ rateK1024 = (1600 - 1024) / 8
+)
+
+// NewLegacyKeccak256 creates a new Keccak-256 hash.
+//
+// Only use this function if you require compatibility with an existing cryptosystem
+// that uses non-standard padding. All other users should use New256 instead.
+func NewLegacyKeccak256() hash.Hash {
+ return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak}
+}
+
+// NewLegacyKeccak512 creates a new Keccak-512 hash.
+//
+// Only use this function if you require compatibility with an existing cryptosystem
+// that uses non-standard padding. All other users should use New512 instead.
+func NewLegacyKeccak512() hash.Hash {
+ return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak}
+}
+
+// spongeDirection indicates the direction bytes are flowing through the sponge.
+type spongeDirection int
+
+const (
+ // spongeAbsorbing indicates that the sponge is absorbing input.
+ spongeAbsorbing spongeDirection = iota
+ // spongeSqueezing indicates that the sponge is being squeezed.
+ spongeSqueezing
+)
+
+type state struct {
+ a [1600 / 8]byte // main state of the hash
+
+ // a[n:rate] is the buffer. If absorbing, it's the remaining space to XOR
+ // into before running the permutation. If squeezing, it's the remaining
+ // output to produce before running the permutation.
+ n, rate int
+
+ // dsbyte contains the "domain separation" bits and the first bit of
+ // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
+ // SHA-3 and SHAKE functions by appending bitstrings to the message.
+ // Using a little-endian bit-ordering convention, these are "01" for SHA-3
+ // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
+ // padding rule from section 5.1 is applied to pad the message to a multiple
+ // of the rate, which involves adding a "1" bit, zero or more "0" bits, and
+ // a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
+ // giving 00000110b (0x06) and 00011111b (0x1f).
+ // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
+ // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
+ // Extendable-Output Functions (May 2014)"
+ dsbyte byte
+
+ outputLen int // the default output size in bytes
+ state spongeDirection // whether the sponge is absorbing or squeezing
+}
+
+// BlockSize returns the rate of sponge underlying this hash function.
+func (d *state) BlockSize() int { return d.rate }
+
+// Size returns the output size of the hash function in bytes.
+func (d *state) Size() int { return d.outputLen }
+
+// Reset clears the internal state by zeroing the sponge state and
+// the buffer indexes, and setting Sponge.state to absorbing.
+func (d *state) Reset() {
+ // Zero the permutation's state.
+ for i := range d.a {
+ d.a[i] = 0
+ }
+ d.state = spongeAbsorbing
+ d.n = 0
+}
+
+func (d *state) clone() *state {
+ ret := *d
+ return &ret
+}
+
+// permute applies the KeccakF-1600 permutation.
+func (d *state) permute() {
+ var a *[25]uint64
+ if cpu.IsBigEndian {
+ a = new([25]uint64)
+ for i := range a {
+ a[i] = binary.LittleEndian.Uint64(d.a[i*8:])
+ }
+ } else {
+ a = (*[25]uint64)(unsafe.Pointer(&d.a))
+ }
+
+ keccakF1600(a)
+ d.n = 0
+
+ if cpu.IsBigEndian {
+ for i := range a {
+ binary.LittleEndian.PutUint64(d.a[i*8:], a[i])
+ }
+ }
+}
+
+// pads appends the domain separation bits in dsbyte, applies
+// the multi-bitrate 10..1 padding rule, and permutes the state.
+func (d *state) padAndPermute() {
+ // Pad with this instance's domain-separator bits. We know that there's
+ // at least one byte of space in the sponge because, if it were full,
+ // permute would have been called to empty it. dsbyte also contains the
+ // first one bit for the padding. See the comment in the state struct.
+ d.a[d.n] ^= d.dsbyte
+ // This adds the final one bit for the padding. Because of the way that
+ // bits are numbered from the LSB upwards, the final bit is the MSB of
+ // the last byte.
+ d.a[d.rate-1] ^= 0x80
+ // Apply the permutation
+ d.permute()
+ d.state = spongeSqueezing
+}
+
+// Write absorbs more data into the hash's state. It panics if any
+// output has already been read.
+func (d *state) Write(p []byte) (n int, err error) {
+ if d.state != spongeAbsorbing {
+ panic("sha3: Write after Read")
+ }
+
+ n = len(p)
+
+ for len(p) > 0 {
+ x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p)
+ d.n += x
+ p = p[x:]
+
+ // If the sponge is full, apply the permutation.
+ if d.n == d.rate {
+ d.permute()
+ }
+ }
+
+ return
+}
+
+// Read squeezes an arbitrary number of bytes from the sponge.
+func (d *state) Read(out []byte) (n int, err error) {
+ // If we're still absorbing, pad and apply the permutation.
+ if d.state == spongeAbsorbing {
+ d.padAndPermute()
+ }
+
+ n = len(out)
+
+ // Now, do the squeezing.
+ for len(out) > 0 {
+ // Apply the permutation if we've squeezed the sponge dry.
+ if d.n == d.rate {
+ d.permute()
+ }
+
+ x := copy(out, d.a[d.n:d.rate])
+ d.n += x
+ out = out[x:]
+ }
+
+ return
+}
+
+// Sum applies padding to the hash state and then squeezes out the desired
+// number of output bytes. It panics if any output has already been read.
+func (d *state) Sum(in []byte) []byte {
+ if d.state != spongeAbsorbing {
+ panic("sha3: Sum after Read")
+ }
+
+ // Make a copy of the original hash so that caller can keep writing
+ // and summing.
+ dup := d.clone()
+ hash := make([]byte, dup.outputLen, 64) // explicit cap to allow stack allocation
+ dup.Read(hash)
+ return append(in, hash...)
+}
+
+const (
+ magicKeccak = "sha\x0b"
+ // magic || rate || main state || n || sponge direction
+ marshaledSize = len(magicKeccak) + 1 + 200 + 1 + 1
+)
+
+func (d *state) MarshalBinary() ([]byte, error) {
+ return d.AppendBinary(make([]byte, 0, marshaledSize))
+}
+
+func (d *state) AppendBinary(b []byte) ([]byte, error) {
+ switch d.dsbyte {
+ case dsbyteKeccak:
+ b = append(b, magicKeccak...)
+ default:
+ panic("unknown dsbyte")
+ }
+ // rate is at most 168, and n is at most rate.
+ b = append(b, byte(d.rate))
+ b = append(b, d.a[:]...)
+ b = append(b, byte(d.n), byte(d.state))
+ return b, nil
+}
+
+func (d *state) UnmarshalBinary(b []byte) error {
+ if len(b) != marshaledSize {
+ return errors.New("sha3: invalid hash state")
+ }
+
+ magic := string(b[:len(magicKeccak)])
+ b = b[len(magicKeccak):]
+ switch {
+ case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
+ default:
+ return errors.New("sha3: invalid hash state identifier")
+ }
+
+ rate := int(b[0])
+ b = b[1:]
+ if rate != d.rate {
+ return errors.New("sha3: invalid hash state function")
+ }
+
+ copy(d.a[:], b)
+ b = b[len(d.a):]
+
+ n, state := int(b[0]), spongeDirection(b[1])
+ if n > d.rate {
+ return errors.New("sha3: invalid hash state")
+ }
+ d.n = n
+ if state != spongeAbsorbing && state != spongeSqueezing {
+ return errors.New("sha3: invalid hash state")
+ }
+ d.state = state
+
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/sha3/legacy_keccakf.go b/vendor/golang.org/x/crypto/sha3/legacy_keccakf.go
new file mode 100644
index 00000000..101588c1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/legacy_keccakf.go
@@ -0,0 +1,416 @@
+// 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.
+
+package sha3
+
+// This implementation is only used for NewLegacyKeccak256 and
+// NewLegacyKeccak512, which are not implemented by crypto/sha3.
+// All other functions in this package are wrappers around crypto/sha3.
+
+import "math/bits"
+
+// rc stores the round constants for use in the ι step.
+var rc = [24]uint64{
+ 0x0000000000000001,
+ 0x0000000000008082,
+ 0x800000000000808A,
+ 0x8000000080008000,
+ 0x000000000000808B,
+ 0x0000000080000001,
+ 0x8000000080008081,
+ 0x8000000000008009,
+ 0x000000000000008A,
+ 0x0000000000000088,
+ 0x0000000080008009,
+ 0x000000008000000A,
+ 0x000000008000808B,
+ 0x800000000000008B,
+ 0x8000000000008089,
+ 0x8000000000008003,
+ 0x8000000000008002,
+ 0x8000000000000080,
+ 0x000000000000800A,
+ 0x800000008000000A,
+ 0x8000000080008081,
+ 0x8000000000008080,
+ 0x0000000080000001,
+ 0x8000000080008008,
+}
+
+// keccakF1600 applies the Keccak permutation to a 1600b-wide
+// state represented as a slice of 25 uint64s.
+func keccakF1600(a *[25]uint64) {
+ // Implementation translated from Keccak-inplace.c
+ // in the keccak reference code.
+ var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
+
+ for i := 0; i < 24; i += 4 {
+ // Combines the 5 steps in each round into 2 steps.
+ // Unrolls 4 rounds per loop and spreads some steps across rounds.
+
+ // Round 1
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[6] ^ d1
+ bc1 = bits.RotateLeft64(t, 44)
+ t = a[12] ^ d2
+ bc2 = bits.RotateLeft64(t, 43)
+ t = a[18] ^ d3
+ bc3 = bits.RotateLeft64(t, 21)
+ t = a[24] ^ d4
+ bc4 = bits.RotateLeft64(t, 14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i]
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc2 = bits.RotateLeft64(t, 3)
+ t = a[16] ^ d1
+ bc3 = bits.RotateLeft64(t, 45)
+ t = a[22] ^ d2
+ bc4 = bits.RotateLeft64(t, 61)
+ t = a[3] ^ d3
+ bc0 = bits.RotateLeft64(t, 28)
+ t = a[9] ^ d4
+ bc1 = bits.RotateLeft64(t, 20)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc4 = bits.RotateLeft64(t, 18)
+ t = a[1] ^ d1
+ bc0 = bits.RotateLeft64(t, 1)
+ t = a[7] ^ d2
+ bc1 = bits.RotateLeft64(t, 6)
+ t = a[13] ^ d3
+ bc2 = bits.RotateLeft64(t, 25)
+ t = a[19] ^ d4
+ bc3 = bits.RotateLeft64(t, 8)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc1 = bits.RotateLeft64(t, 36)
+ t = a[11] ^ d1
+ bc2 = bits.RotateLeft64(t, 10)
+ t = a[17] ^ d2
+ bc3 = bits.RotateLeft64(t, 15)
+ t = a[23] ^ d3
+ bc4 = bits.RotateLeft64(t, 56)
+ t = a[4] ^ d4
+ bc0 = bits.RotateLeft64(t, 27)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc3 = bits.RotateLeft64(t, 41)
+ t = a[21] ^ d1
+ bc4 = bits.RotateLeft64(t, 2)
+ t = a[2] ^ d2
+ bc0 = bits.RotateLeft64(t, 62)
+ t = a[8] ^ d3
+ bc1 = bits.RotateLeft64(t, 55)
+ t = a[14] ^ d4
+ bc2 = bits.RotateLeft64(t, 39)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 2
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[16] ^ d1
+ bc1 = bits.RotateLeft64(t, 44)
+ t = a[7] ^ d2
+ bc2 = bits.RotateLeft64(t, 43)
+ t = a[23] ^ d3
+ bc3 = bits.RotateLeft64(t, 21)
+ t = a[14] ^ d4
+ bc4 = bits.RotateLeft64(t, 14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1]
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc2 = bits.RotateLeft64(t, 3)
+ t = a[11] ^ d1
+ bc3 = bits.RotateLeft64(t, 45)
+ t = a[2] ^ d2
+ bc4 = bits.RotateLeft64(t, 61)
+ t = a[18] ^ d3
+ bc0 = bits.RotateLeft64(t, 28)
+ t = a[9] ^ d4
+ bc1 = bits.RotateLeft64(t, 20)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc4 = bits.RotateLeft64(t, 18)
+ t = a[6] ^ d1
+ bc0 = bits.RotateLeft64(t, 1)
+ t = a[22] ^ d2
+ bc1 = bits.RotateLeft64(t, 6)
+ t = a[13] ^ d3
+ bc2 = bits.RotateLeft64(t, 25)
+ t = a[4] ^ d4
+ bc3 = bits.RotateLeft64(t, 8)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc1 = bits.RotateLeft64(t, 36)
+ t = a[1] ^ d1
+ bc2 = bits.RotateLeft64(t, 10)
+ t = a[17] ^ d2
+ bc3 = bits.RotateLeft64(t, 15)
+ t = a[8] ^ d3
+ bc4 = bits.RotateLeft64(t, 56)
+ t = a[24] ^ d4
+ bc0 = bits.RotateLeft64(t, 27)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc3 = bits.RotateLeft64(t, 41)
+ t = a[21] ^ d1
+ bc4 = bits.RotateLeft64(t, 2)
+ t = a[12] ^ d2
+ bc0 = bits.RotateLeft64(t, 62)
+ t = a[3] ^ d3
+ bc1 = bits.RotateLeft64(t, 55)
+ t = a[19] ^ d4
+ bc2 = bits.RotateLeft64(t, 39)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 3
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[11] ^ d1
+ bc1 = bits.RotateLeft64(t, 44)
+ t = a[22] ^ d2
+ bc2 = bits.RotateLeft64(t, 43)
+ t = a[8] ^ d3
+ bc3 = bits.RotateLeft64(t, 21)
+ t = a[19] ^ d4
+ bc4 = bits.RotateLeft64(t, 14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2]
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc2 = bits.RotateLeft64(t, 3)
+ t = a[1] ^ d1
+ bc3 = bits.RotateLeft64(t, 45)
+ t = a[12] ^ d2
+ bc4 = bits.RotateLeft64(t, 61)
+ t = a[23] ^ d3
+ bc0 = bits.RotateLeft64(t, 28)
+ t = a[9] ^ d4
+ bc1 = bits.RotateLeft64(t, 20)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc4 = bits.RotateLeft64(t, 18)
+ t = a[16] ^ d1
+ bc0 = bits.RotateLeft64(t, 1)
+ t = a[2] ^ d2
+ bc1 = bits.RotateLeft64(t, 6)
+ t = a[13] ^ d3
+ bc2 = bits.RotateLeft64(t, 25)
+ t = a[24] ^ d4
+ bc3 = bits.RotateLeft64(t, 8)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc1 = bits.RotateLeft64(t, 36)
+ t = a[6] ^ d1
+ bc2 = bits.RotateLeft64(t, 10)
+ t = a[17] ^ d2
+ bc3 = bits.RotateLeft64(t, 15)
+ t = a[3] ^ d3
+ bc4 = bits.RotateLeft64(t, 56)
+ t = a[14] ^ d4
+ bc0 = bits.RotateLeft64(t, 27)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc3 = bits.RotateLeft64(t, 41)
+ t = a[21] ^ d1
+ bc4 = bits.RotateLeft64(t, 2)
+ t = a[7] ^ d2
+ bc0 = bits.RotateLeft64(t, 62)
+ t = a[18] ^ d3
+ bc1 = bits.RotateLeft64(t, 55)
+ t = a[4] ^ d4
+ bc2 = bits.RotateLeft64(t, 39)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 4
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[1] ^ d1
+ bc1 = bits.RotateLeft64(t, 44)
+ t = a[2] ^ d2
+ bc2 = bits.RotateLeft64(t, 43)
+ t = a[3] ^ d3
+ bc3 = bits.RotateLeft64(t, 21)
+ t = a[4] ^ d4
+ bc4 = bits.RotateLeft64(t, 14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3]
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc2 = bits.RotateLeft64(t, 3)
+ t = a[6] ^ d1
+ bc3 = bits.RotateLeft64(t, 45)
+ t = a[7] ^ d2
+ bc4 = bits.RotateLeft64(t, 61)
+ t = a[8] ^ d3
+ bc0 = bits.RotateLeft64(t, 28)
+ t = a[9] ^ d4
+ bc1 = bits.RotateLeft64(t, 20)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc4 = bits.RotateLeft64(t, 18)
+ t = a[11] ^ d1
+ bc0 = bits.RotateLeft64(t, 1)
+ t = a[12] ^ d2
+ bc1 = bits.RotateLeft64(t, 6)
+ t = a[13] ^ d3
+ bc2 = bits.RotateLeft64(t, 25)
+ t = a[14] ^ d4
+ bc3 = bits.RotateLeft64(t, 8)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc1 = bits.RotateLeft64(t, 36)
+ t = a[16] ^ d1
+ bc2 = bits.RotateLeft64(t, 10)
+ t = a[17] ^ d2
+ bc3 = bits.RotateLeft64(t, 15)
+ t = a[18] ^ d3
+ bc4 = bits.RotateLeft64(t, 56)
+ t = a[19] ^ d4
+ bc0 = bits.RotateLeft64(t, 27)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc3 = bits.RotateLeft64(t, 41)
+ t = a[21] ^ d1
+ bc4 = bits.RotateLeft64(t, 2)
+ t = a[22] ^ d2
+ bc0 = bits.RotateLeft64(t, 62)
+ t = a[23] ^ d3
+ bc1 = bits.RotateLeft64(t, 55)
+ t = a[24] ^ d4
+ bc2 = bits.RotateLeft64(t, 39)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go
new file mode 100644
index 00000000..6f3f70c2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/shake.go
@@ -0,0 +1,119 @@
+// 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.
+
+package sha3
+
+import (
+ "crypto/sha3"
+ "hash"
+ "io"
+)
+
+// ShakeHash defines the interface to hash functions that support
+// arbitrary-length output. When used as a plain [hash.Hash], it
+// produces minimum-length outputs that provide full-strength generic
+// security.
+type ShakeHash interface {
+ hash.Hash
+
+ // Read reads more output from the hash; reading affects the hash's
+ // state. (ShakeHash.Read is thus very different from Hash.Sum.)
+ // It never returns an error, but subsequent calls to Write or Sum
+ // will panic.
+ io.Reader
+
+ // Clone returns a copy of the ShakeHash in its current state.
+ Clone() ShakeHash
+}
+
+// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
+// Its generic security strength is 128 bits against all attacks if at
+// least 32 bytes of its output are used.
+func NewShake128() ShakeHash {
+ return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128}
+}
+
+// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
+// Its generic security strength is 256 bits against all attacks if
+// at least 64 bytes of its output are used.
+func NewShake256() ShakeHash {
+ return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256}
+}
+
+// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
+// a customizable variant of SHAKE128.
+// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
+// desired. S is a customization byte string used for domain separation - two cSHAKE
+// computations on same input with different S yield unrelated outputs.
+// When N and S are both empty, this is equivalent to NewShake128.
+func NewCShake128(N, S []byte) ShakeHash {
+ return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE {
+ return sha3.NewCSHAKE128(N, S)
+ }}
+}
+
+// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
+// a customizable variant of SHAKE256.
+// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
+// desired. S is a customization byte string used for domain separation - two cSHAKE
+// computations on same input with different S yield unrelated outputs.
+// When N and S are both empty, this is equivalent to NewShake256.
+func NewCShake256(N, S []byte) ShakeHash {
+ return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE {
+ return sha3.NewCSHAKE256(N, S)
+ }}
+}
+
+// ShakeSum128 writes an arbitrary-length digest of data into hash.
+func ShakeSum128(hash, data []byte) {
+ h := NewShake128()
+ h.Write(data)
+ h.Read(hash)
+}
+
+// ShakeSum256 writes an arbitrary-length digest of data into hash.
+func ShakeSum256(hash, data []byte) {
+ h := NewShake256()
+ h.Write(data)
+ h.Read(hash)
+}
+
+// shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE
+// to implement the ShakeHash interface.
+type shakeWrapper struct {
+ *sha3.SHAKE
+ outputLen int
+ squeezing bool
+ newSHAKE func() *sha3.SHAKE
+}
+
+func (w *shakeWrapper) Read(p []byte) (n int, err error) {
+ w.squeezing = true
+ return w.SHAKE.Read(p)
+}
+
+func (w *shakeWrapper) Clone() ShakeHash {
+ s := w.newSHAKE()
+ b, err := w.MarshalBinary()
+ if err != nil {
+ panic(err) // unreachable
+ }
+ if err := s.UnmarshalBinary(b); err != nil {
+ panic(err) // unreachable
+ }
+ return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE}
+}
+
+func (w *shakeWrapper) Size() int { return w.outputLen }
+
+func (w *shakeWrapper) Sum(b []byte) []byte {
+ if w.squeezing {
+ panic("sha3: Sum after Read")
+ }
+ out := make([]byte, w.outputLen)
+ // Clone the state so that we don't affect future Write calls.
+ s := w.Clone()
+ s.Read(out)
+ return append(b, out...)
+}
diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE
new file mode 100644
index 00000000..2a7cf70d
--- /dev/null
+++ b/vendor/golang.org/x/net/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/net/PATENTS b/vendor/golang.org/x/net/PATENTS
new file mode 100644
index 00000000..73309904
--- /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/bpf/asm.go b/vendor/golang.org/x/net/bpf/asm.go
new file mode 100644
index 00000000..15e21b18
--- /dev/null
+++ b/vendor/golang.org/x/net/bpf/asm.go
@@ -0,0 +1,41 @@
+// 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 bpf
+
+import "fmt"
+
+// Assemble converts insts into raw instructions suitable for loading
+// into a BPF virtual machine.
+//
+// Currently, no optimization is attempted, the assembled program flow
+// is exactly as provided.
+func Assemble(insts []Instruction) ([]RawInstruction, error) {
+ ret := make([]RawInstruction, len(insts))
+ var err error
+ for i, inst := range insts {
+ ret[i], err = inst.Assemble()
+ if err != nil {
+ return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
+ }
+ }
+ return ret, nil
+}
+
+// Disassemble attempts to parse raw back into
+// Instructions. Unrecognized RawInstructions are assumed to be an
+// extension not implemented by this package, and are passed through
+// unchanged to the output. The allDecoded value reports whether insts
+// contains no RawInstructions.
+func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
+ insts = make([]Instruction, len(raw))
+ allDecoded = true
+ for i, r := range raw {
+ insts[i] = r.Disassemble()
+ if _, ok := insts[i].(RawInstruction); ok {
+ allDecoded = false
+ }
+ }
+ return insts, allDecoded
+}
diff --git a/vendor/golang.org/x/net/bpf/constants.go b/vendor/golang.org/x/net/bpf/constants.go
new file mode 100644
index 00000000..12f3ee83
--- /dev/null
+++ b/vendor/golang.org/x/net/bpf/constants.go
@@ -0,0 +1,222 @@
+// 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 bpf
+
+// A Register is a register of the BPF virtual machine.
+type Register uint16
+
+const (
+ // RegA is the accumulator register. RegA is always the
+ // destination register of ALU operations.
+ RegA Register = iota
+ // RegX is the indirection register, used by LoadIndirect
+ // operations.
+ RegX
+)
+
+// An ALUOp is an arithmetic or logic operation.
+type ALUOp uint16
+
+// ALU binary operation types.
+const (
+ ALUOpAdd ALUOp = iota << 4
+ ALUOpSub
+ ALUOpMul
+ ALUOpDiv
+ ALUOpOr
+ ALUOpAnd
+ ALUOpShiftLeft
+ ALUOpShiftRight
+ aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type.
+ ALUOpMod
+ ALUOpXor
+)
+
+// A JumpTest is a comparison operator used in conditional jumps.
+type JumpTest uint16
+
+// Supported operators for conditional jumps.
+// K can be RegX for JumpIfX
+const (
+ // K == A
+ JumpEqual JumpTest = iota
+ // K != A
+ JumpNotEqual
+ // K > A
+ JumpGreaterThan
+ // K < A
+ JumpLessThan
+ // K >= A
+ JumpGreaterOrEqual
+ // K <= A
+ JumpLessOrEqual
+ // K & A != 0
+ JumpBitsSet
+ // K & A == 0
+ JumpBitsNotSet
+)
+
+// An Extension is a function call provided by the kernel that
+// performs advanced operations that are expensive or impossible
+// within the BPF virtual machine.
+//
+// Extensions are only implemented by the Linux kernel.
+//
+// TODO: should we prune this list? Some of these extensions seem
+// either broken or near-impossible to use correctly, whereas other
+// (len, random, ifindex) are quite useful.
+type Extension int
+
+// Extension functions available in the Linux kernel.
+const (
+ // extOffset is the negative maximum number of instructions used
+ // to load instructions by overloading the K argument.
+ extOffset = -0x1000
+ // ExtLen returns the length of the packet.
+ ExtLen Extension = 1
+ // ExtProto returns the packet's L3 protocol type.
+ ExtProto Extension = 0
+ // ExtType returns the packet's type (skb->pkt_type in the kernel)
+ //
+ // TODO: better documentation. How nice an API do we want to
+ // provide for these esoteric extensions?
+ ExtType Extension = 4
+ // ExtPayloadOffset returns the offset of the packet payload, or
+ // the first protocol header that the kernel does not know how to
+ // parse.
+ ExtPayloadOffset Extension = 52
+ // ExtInterfaceIndex returns the index of the interface on which
+ // the packet was received.
+ ExtInterfaceIndex Extension = 8
+ // ExtNetlinkAttr returns the netlink attribute of type X at
+ // offset A.
+ ExtNetlinkAttr Extension = 12
+ // ExtNetlinkAttrNested returns the nested netlink attribute of
+ // type X at offset A.
+ ExtNetlinkAttrNested Extension = 16
+ // ExtMark returns the packet's mark value.
+ ExtMark Extension = 20
+ // ExtQueue returns the packet's assigned hardware queue.
+ ExtQueue Extension = 24
+ // ExtLinkLayerType returns the packet's hardware address type
+ // (e.g. Ethernet, Infiniband).
+ ExtLinkLayerType Extension = 28
+ // ExtRXHash returns the packets receive hash.
+ //
+ // TODO: figure out what this rxhash actually is.
+ ExtRXHash Extension = 32
+ // ExtCPUID returns the ID of the CPU processing the current
+ // packet.
+ ExtCPUID Extension = 36
+ // ExtVLANTag returns the packet's VLAN tag.
+ ExtVLANTag Extension = 44
+ // ExtVLANTagPresent returns non-zero if the packet has a VLAN
+ // tag.
+ //
+ // TODO: I think this might be a lie: it reads bit 0x1000 of the
+ // VLAN header, which changed meaning in recent revisions of the
+ // spec - this extension may now return meaningless information.
+ ExtVLANTagPresent Extension = 48
+ // ExtVLANProto returns 0x8100 if the frame has a VLAN header,
+ // 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
+ // other value if no VLAN information is present.
+ ExtVLANProto Extension = 60
+ // ExtRand returns a uniformly random uint32.
+ ExtRand Extension = 56
+)
+
+// The following gives names to various bit patterns used in opcode construction.
+
+const (
+ opMaskCls uint16 = 0x7
+ // opClsLoad masks
+ opMaskLoadDest = 0x01
+ opMaskLoadWidth = 0x18
+ opMaskLoadMode = 0xe0
+ // opClsALU & opClsJump
+ opMaskOperand = 0x08
+ opMaskOperator = 0xf0
+)
+
+const (
+ // +---------------+-----------------+---+---+---+
+ // | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 |
+ // +---------------+-----------------+---+---+---+
+ opClsLoadA uint16 = iota
+ // +---------------+-----------------+---+---+---+
+ // | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 |
+ // +---------------+-----------------+---+---+---+
+ opClsLoadX
+ // +---+---+---+---+---+---+---+---+
+ // | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
+ // +---+---+---+---+---+---+---+---+
+ opClsStoreA
+ // +---+---+---+---+---+---+---+---+
+ // | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
+ // +---+---+---+---+---+---+---+---+
+ opClsStoreX
+ // +---------------+-----------------+---+---+---+
+ // | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 |
+ // +---------------+-----------------+---+---+---+
+ opClsALU
+ // +-----------------------------+---+---+---+---+
+ // | TestOperator (4b) | 0 | 1 | 0 | 1 |
+ // +-----------------------------+---+---+---+---+
+ opClsJump
+ // +---+-------------------------+---+---+---+---+
+ // | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 |
+ // +---+-------------------------+---+---+---+---+
+ opClsReturn
+ // +---+-------------------------+---+---+---+---+
+ // | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 |
+ // +---+-------------------------+---+---+---+---+
+ opClsMisc
+)
+
+const (
+ opAddrModeImmediate uint16 = iota << 5
+ opAddrModeAbsolute
+ opAddrModeIndirect
+ opAddrModeScratch
+ opAddrModePacketLen // actually an extension, not an addressing mode.
+ opAddrModeMemShift
+)
+
+const (
+ opLoadWidth4 uint16 = iota << 3
+ opLoadWidth2
+ opLoadWidth1
+)
+
+// Operand for ALU and Jump instructions
+type opOperand uint16
+
+// Supported operand sources.
+const (
+ opOperandConstant opOperand = iota << 3
+ opOperandX
+)
+
+// An jumpOp is a conditional jump condition.
+type jumpOp uint16
+
+// Supported jump conditions.
+const (
+ opJumpAlways jumpOp = iota << 4
+ opJumpEqual
+ opJumpGT
+ opJumpGE
+ opJumpSet
+)
+
+const (
+ opRetSrcConstant uint16 = iota << 4
+ opRetSrcA
+)
+
+const (
+ opMiscTAX = 0x00
+ opMiscTXA = 0x80
+)
diff --git a/vendor/golang.org/x/net/bpf/doc.go b/vendor/golang.org/x/net/bpf/doc.go
new file mode 100644
index 00000000..04ec1c8a
--- /dev/null
+++ b/vendor/golang.org/x/net/bpf/doc.go
@@ -0,0 +1,80 @@
+// 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 bpf implements marshaling and unmarshaling of programs for the
+Berkeley Packet Filter virtual machine, and provides a Go implementation
+of the virtual machine.
+
+BPF's main use is to specify a packet filter for network taps, so that
+the kernel doesn't have to expensively copy every packet it sees to
+userspace. However, it's been repurposed to other areas where running
+user code in-kernel is needed. For example, Linux's seccomp uses BPF
+to apply security policies to system calls. For simplicity, this
+documentation refers only to packets, but other uses of BPF have their
+own data payloads.
+
+BPF programs run in a restricted virtual machine. It has almost no
+access to kernel functions, and while conditional branches are
+allowed, they can only jump forwards, to guarantee that there are no
+infinite loops.
+
+# The virtual machine
+
+The BPF VM is an accumulator machine. Its main register, called
+register A, is an implicit source and destination in all arithmetic
+and logic operations. The machine also has 16 scratch registers for
+temporary storage, and an indirection register (register X) for
+indirect memory access. All registers are 32 bits wide.
+
+Each run of a BPF program is given one packet, which is placed in the
+VM's read-only "main memory". LoadAbsolute and LoadIndirect
+instructions can fetch up to 32 bits at a time into register A for
+examination.
+
+The goal of a BPF program is to produce and return a verdict (uint32),
+which tells the kernel what to do with the packet. In the context of
+packet filtering, the returned value is the number of bytes of the
+packet to forward to userspace, or 0 to ignore the packet. Other
+contexts like seccomp define their own return values.
+
+In order to simplify programs, attempts to read past the end of the
+packet terminate the program execution with a verdict of 0 (ignore
+packet). This means that the vast majority of BPF programs don't need
+to do any explicit bounds checking.
+
+In addition to the bytes of the packet, some BPF programs have access
+to extensions, which are essentially calls to kernel utility
+functions. Currently, the only extensions supported by this package
+are the Linux packet filter extensions.
+
+# Examples
+
+This packet filter selects all ARP packets.
+
+ bpf.Assemble([]bpf.Instruction{
+ // Load "EtherType" field from the ethernet header.
+ bpf.LoadAbsolute{Off: 12, Size: 2},
+ // Skip over the next instruction if EtherType is not ARP.
+ bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1},
+ // Verdict is "send up to 4k of the packet to userspace."
+ bpf.RetConstant{Val: 4096},
+ // Verdict is "ignore packet."
+ bpf.RetConstant{Val: 0},
+ })
+
+This packet filter captures a random 1% sample of traffic.
+
+ bpf.Assemble([]bpf.Instruction{
+ // Get a 32-bit random number from the Linux kernel.
+ bpf.LoadExtension{Num: bpf.ExtRand},
+ // 1% dice roll?
+ bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1},
+ // Capture.
+ bpf.RetConstant{Val: 4096},
+ // Ignore.
+ bpf.RetConstant{Val: 0},
+ })
+*/
+package bpf // import "golang.org/x/net/bpf"
diff --git a/vendor/golang.org/x/net/bpf/instructions.go b/vendor/golang.org/x/net/bpf/instructions.go
new file mode 100644
index 00000000..3cffcaa0
--- /dev/null
+++ b/vendor/golang.org/x/net/bpf/instructions.go
@@ -0,0 +1,726 @@
+// 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 bpf
+
+import "fmt"
+
+// An Instruction is one instruction executed by the BPF virtual
+// machine.
+type Instruction interface {
+ // Assemble assembles the Instruction into a RawInstruction.
+ Assemble() (RawInstruction, error)
+}
+
+// A RawInstruction is a raw BPF virtual machine instruction.
+type RawInstruction struct {
+ // Operation to execute.
+ Op uint16
+ // For conditional jump instructions, the number of instructions
+ // to skip if the condition is true/false.
+ Jt uint8
+ Jf uint8
+ // Constant parameter. The meaning depends on the Op.
+ K uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
+
+// Disassemble parses ri into an Instruction and returns it. If ri is
+// not recognized by this package, ri itself is returned.
+func (ri RawInstruction) Disassemble() Instruction {
+ switch ri.Op & opMaskCls {
+ case opClsLoadA, opClsLoadX:
+ reg := Register(ri.Op & opMaskLoadDest)
+ sz := 0
+ switch ri.Op & opMaskLoadWidth {
+ case opLoadWidth4:
+ sz = 4
+ case opLoadWidth2:
+ sz = 2
+ case opLoadWidth1:
+ sz = 1
+ default:
+ return ri
+ }
+ switch ri.Op & opMaskLoadMode {
+ case opAddrModeImmediate:
+ if sz != 4 {
+ return ri
+ }
+ return LoadConstant{Dst: reg, Val: ri.K}
+ case opAddrModeScratch:
+ if sz != 4 || ri.K > 15 {
+ return ri
+ }
+ return LoadScratch{Dst: reg, N: int(ri.K)}
+ case opAddrModeAbsolute:
+ if ri.K > extOffset+0xffffffff {
+ return LoadExtension{Num: Extension(-extOffset + ri.K)}
+ }
+ return LoadAbsolute{Size: sz, Off: ri.K}
+ case opAddrModeIndirect:
+ return LoadIndirect{Size: sz, Off: ri.K}
+ case opAddrModePacketLen:
+ if sz != 4 {
+ return ri
+ }
+ return LoadExtension{Num: ExtLen}
+ case opAddrModeMemShift:
+ return LoadMemShift{Off: ri.K}
+ default:
+ return ri
+ }
+
+ case opClsStoreA:
+ if ri.Op != opClsStoreA || ri.K > 15 {
+ return ri
+ }
+ return StoreScratch{Src: RegA, N: int(ri.K)}
+
+ case opClsStoreX:
+ if ri.Op != opClsStoreX || ri.K > 15 {
+ return ri
+ }
+ return StoreScratch{Src: RegX, N: int(ri.K)}
+
+ case opClsALU:
+ switch op := ALUOp(ri.Op & opMaskOperator); op {
+ case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
+ switch operand := opOperand(ri.Op & opMaskOperand); operand {
+ case opOperandX:
+ return ALUOpX{Op: op}
+ case opOperandConstant:
+ return ALUOpConstant{Op: op, Val: ri.K}
+ default:
+ return ri
+ }
+ case aluOpNeg:
+ return NegateA{}
+ default:
+ return ri
+ }
+
+ case opClsJump:
+ switch op := jumpOp(ri.Op & opMaskOperator); op {
+ case opJumpAlways:
+ return Jump{Skip: ri.K}
+ case opJumpEqual, opJumpGT, opJumpGE, opJumpSet:
+ cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf)
+ switch operand := opOperand(ri.Op & opMaskOperand); operand {
+ case opOperandX:
+ return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse}
+ case opOperandConstant:
+ return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse}
+ default:
+ return ri
+ }
+ default:
+ return ri
+ }
+
+ case opClsReturn:
+ switch ri.Op {
+ case opClsReturn | opRetSrcA:
+ return RetA{}
+ case opClsReturn | opRetSrcConstant:
+ return RetConstant{Val: ri.K}
+ default:
+ return ri
+ }
+
+ case opClsMisc:
+ switch ri.Op {
+ case opClsMisc | opMiscTAX:
+ return TAX{}
+ case opClsMisc | opMiscTXA:
+ return TXA{}
+ default:
+ return ri
+ }
+
+ default:
+ panic("unreachable") // switch is exhaustive on the bit pattern
+ }
+}
+
+func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) {
+ var test JumpTest
+
+ // Decode "fake" jump conditions that don't appear in machine code
+ // Ensures the Assemble -> Disassemble stage recreates the same instructions
+ // See https://github.com/golang/go/issues/18470
+ if skipTrue == 0 {
+ switch op {
+ case opJumpEqual:
+ test = JumpNotEqual
+ case opJumpGT:
+ test = JumpLessOrEqual
+ case opJumpGE:
+ test = JumpLessThan
+ case opJumpSet:
+ test = JumpBitsNotSet
+ }
+
+ return test, skipFalse, 0
+ }
+
+ switch op {
+ case opJumpEqual:
+ test = JumpEqual
+ case opJumpGT:
+ test = JumpGreaterThan
+ case opJumpGE:
+ test = JumpGreaterOrEqual
+ case opJumpSet:
+ test = JumpBitsSet
+ }
+
+ return test, skipTrue, skipFalse
+}
+
+// LoadConstant loads Val into register Dst.
+type LoadConstant struct {
+ Dst Register
+ Val uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadConstant) Assemble() (RawInstruction, error) {
+ return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
+}
+
+// String returns the instruction in assembler notation.
+func (a LoadConstant) String() string {
+ switch a.Dst {
+ case RegA:
+ return fmt.Sprintf("ld #%d", a.Val)
+ case RegX:
+ return fmt.Sprintf("ldx #%d", a.Val)
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// LoadScratch loads scratch[N] into register Dst.
+type LoadScratch struct {
+ Dst Register
+ N int // 0-15
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadScratch) Assemble() (RawInstruction, error) {
+ if a.N < 0 || a.N > 15 {
+ return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
+ }
+ return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
+}
+
+// String returns the instruction in assembler notation.
+func (a LoadScratch) String() string {
+ switch a.Dst {
+ case RegA:
+ return fmt.Sprintf("ld M[%d]", a.N)
+ case RegX:
+ return fmt.Sprintf("ldx M[%d]", a.N)
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
+// register A.
+type LoadAbsolute struct {
+ Off uint32
+ Size int // 1, 2 or 4
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadAbsolute) Assemble() (RawInstruction, error) {
+ return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
+}
+
+// String returns the instruction in assembler notation.
+func (a LoadAbsolute) String() string {
+ switch a.Size {
+ case 1: // byte
+ return fmt.Sprintf("ldb [%d]", a.Off)
+ case 2: // half word
+ return fmt.Sprintf("ldh [%d]", a.Off)
+ case 4: // word
+ if a.Off > extOffset+0xffffffff {
+ return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
+ }
+ return fmt.Sprintf("ld [%d]", a.Off)
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
+// into register A.
+type LoadIndirect struct {
+ Off uint32
+ Size int // 1, 2 or 4
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadIndirect) Assemble() (RawInstruction, error) {
+ return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
+}
+
+// String returns the instruction in assembler notation.
+func (a LoadIndirect) String() string {
+ switch a.Size {
+ case 1: // byte
+ return fmt.Sprintf("ldb [x + %d]", a.Off)
+ case 2: // half word
+ return fmt.Sprintf("ldh [x + %d]", a.Off)
+ case 4: // word
+ return fmt.Sprintf("ld [x + %d]", a.Off)
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
+// by 4 and stores the result in register X.
+//
+// This instruction is mainly useful to load into X the length of an
+// IPv4 packet header in a single instruction, rather than have to do
+// the arithmetic on the header's first byte by hand.
+type LoadMemShift struct {
+ Off uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadMemShift) Assemble() (RawInstruction, error) {
+ return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
+}
+
+// String returns the instruction in assembler notation.
+func (a LoadMemShift) String() string {
+ return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
+}
+
+// LoadExtension invokes a linux-specific extension and stores the
+// result in register A.
+type LoadExtension struct {
+ Num Extension
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a LoadExtension) Assemble() (RawInstruction, error) {
+ if a.Num == ExtLen {
+ return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
+ }
+ return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
+}
+
+// String returns the instruction in assembler notation.
+func (a LoadExtension) String() string {
+ switch a.Num {
+ case ExtLen:
+ return "ld #len"
+ case ExtProto:
+ return "ld #proto"
+ case ExtType:
+ return "ld #type"
+ case ExtPayloadOffset:
+ return "ld #poff"
+ case ExtInterfaceIndex:
+ return "ld #ifidx"
+ case ExtNetlinkAttr:
+ return "ld #nla"
+ case ExtNetlinkAttrNested:
+ return "ld #nlan"
+ case ExtMark:
+ return "ld #mark"
+ case ExtQueue:
+ return "ld #queue"
+ case ExtLinkLayerType:
+ return "ld #hatype"
+ case ExtRXHash:
+ return "ld #rxhash"
+ case ExtCPUID:
+ return "ld #cpu"
+ case ExtVLANTag:
+ return "ld #vlan_tci"
+ case ExtVLANTagPresent:
+ return "ld #vlan_avail"
+ case ExtVLANProto:
+ return "ld #vlan_tpid"
+ case ExtRand:
+ return "ld #rand"
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// StoreScratch stores register Src into scratch[N].
+type StoreScratch struct {
+ Src Register
+ N int // 0-15
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a StoreScratch) Assemble() (RawInstruction, error) {
+ if a.N < 0 || a.N > 15 {
+ return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
+ }
+ var op uint16
+ switch a.Src {
+ case RegA:
+ op = opClsStoreA
+ case RegX:
+ op = opClsStoreX
+ default:
+ return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
+ }
+
+ return RawInstruction{
+ Op: op,
+ K: uint32(a.N),
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a StoreScratch) String() string {
+ switch a.Src {
+ case RegA:
+ return fmt.Sprintf("st M[%d]", a.N)
+ case RegX:
+ return fmt.Sprintf("stx M[%d]", a.N)
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// ALUOpConstant executes A = A Val.
+type ALUOpConstant struct {
+ Op ALUOp
+ Val uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a ALUOpConstant) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op),
+ K: a.Val,
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a ALUOpConstant) String() string {
+ switch a.Op {
+ case ALUOpAdd:
+ return fmt.Sprintf("add #%d", a.Val)
+ case ALUOpSub:
+ return fmt.Sprintf("sub #%d", a.Val)
+ case ALUOpMul:
+ return fmt.Sprintf("mul #%d", a.Val)
+ case ALUOpDiv:
+ return fmt.Sprintf("div #%d", a.Val)
+ case ALUOpMod:
+ return fmt.Sprintf("mod #%d", a.Val)
+ case ALUOpAnd:
+ return fmt.Sprintf("and #%d", a.Val)
+ case ALUOpOr:
+ return fmt.Sprintf("or #%d", a.Val)
+ case ALUOpXor:
+ return fmt.Sprintf("xor #%d", a.Val)
+ case ALUOpShiftLeft:
+ return fmt.Sprintf("lsh #%d", a.Val)
+ case ALUOpShiftRight:
+ return fmt.Sprintf("rsh #%d", a.Val)
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// ALUOpX executes A = A X
+type ALUOpX struct {
+ Op ALUOp
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a ALUOpX) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsALU | uint16(opOperandX) | uint16(a.Op),
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a ALUOpX) String() string {
+ switch a.Op {
+ case ALUOpAdd:
+ return "add x"
+ case ALUOpSub:
+ return "sub x"
+ case ALUOpMul:
+ return "mul x"
+ case ALUOpDiv:
+ return "div x"
+ case ALUOpMod:
+ return "mod x"
+ case ALUOpAnd:
+ return "and x"
+ case ALUOpOr:
+ return "or x"
+ case ALUOpXor:
+ return "xor x"
+ case ALUOpShiftLeft:
+ return "lsh x"
+ case ALUOpShiftRight:
+ return "rsh x"
+ default:
+ return fmt.Sprintf("unknown instruction: %#v", a)
+ }
+}
+
+// NegateA executes A = -A.
+type NegateA struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a NegateA) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsALU | uint16(aluOpNeg),
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a NegateA) String() string {
+ return fmt.Sprintf("neg")
+}
+
+// Jump skips the following Skip instructions in the program.
+type Jump struct {
+ Skip uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a Jump) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsJump | uint16(opJumpAlways),
+ K: a.Skip,
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a Jump) String() string {
+ return fmt.Sprintf("ja %d", a.Skip)
+}
+
+// JumpIf skips the following Skip instructions in the program if A
+// Val is true.
+type JumpIf struct {
+ Cond JumpTest
+ Val uint32
+ SkipTrue uint8
+ SkipFalse uint8
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a JumpIf) Assemble() (RawInstruction, error) {
+ return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse)
+}
+
+// String returns the instruction in assembler notation.
+func (a JumpIf) String() string {
+ return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse)
+}
+
+// JumpIfX skips the following Skip instructions in the program if A
+// X is true.
+type JumpIfX struct {
+ Cond JumpTest
+ SkipTrue uint8
+ SkipFalse uint8
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a JumpIfX) Assemble() (RawInstruction, error) {
+ return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse)
+}
+
+// String returns the instruction in assembler notation.
+func (a JumpIfX) String() string {
+ return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse)
+}
+
+// jumpToRaw assembles a jump instruction into a RawInstruction
+func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) {
+ var (
+ cond jumpOp
+ flip bool
+ )
+ switch test {
+ case JumpEqual:
+ cond = opJumpEqual
+ case JumpNotEqual:
+ cond, flip = opJumpEqual, true
+ case JumpGreaterThan:
+ cond = opJumpGT
+ case JumpLessThan:
+ cond, flip = opJumpGE, true
+ case JumpGreaterOrEqual:
+ cond = opJumpGE
+ case JumpLessOrEqual:
+ cond, flip = opJumpGT, true
+ case JumpBitsSet:
+ cond = opJumpSet
+ case JumpBitsNotSet:
+ cond, flip = opJumpSet, true
+ default:
+ return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test)
+ }
+ jt, jf := skipTrue, skipFalse
+ if flip {
+ jt, jf = jf, jt
+ }
+ return RawInstruction{
+ Op: opClsJump | uint16(cond) | uint16(operand),
+ Jt: jt,
+ Jf: jf,
+ K: k,
+ }, nil
+}
+
+// jumpToString converts a jump instruction to assembler notation
+func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string {
+ switch cond {
+ // K == A
+ case JumpEqual:
+ return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq")
+ // K != A
+ case JumpNotEqual:
+ return fmt.Sprintf("jneq %s,%d", operand, skipTrue)
+ // K > A
+ case JumpGreaterThan:
+ return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle")
+ // K < A
+ case JumpLessThan:
+ return fmt.Sprintf("jlt %s,%d", operand, skipTrue)
+ // K >= A
+ case JumpGreaterOrEqual:
+ return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt")
+ // K <= A
+ case JumpLessOrEqual:
+ return fmt.Sprintf("jle %s,%d", operand, skipTrue)
+ // K & A != 0
+ case JumpBitsSet:
+ if skipFalse > 0 {
+ return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse)
+ }
+ return fmt.Sprintf("jset %s,%d", operand, skipTrue)
+ // K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
+ case JumpBitsNotSet:
+ return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue)
+ default:
+ return fmt.Sprintf("unknown JumpTest %#v", cond)
+ }
+}
+
+func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string {
+ if skipTrue > 0 {
+ if skipFalse > 0 {
+ return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse)
+ }
+ return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue)
+ }
+ return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse)
+}
+
+// RetA exits the BPF program, returning the value of register A.
+type RetA struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a RetA) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsReturn | opRetSrcA,
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a RetA) String() string {
+ return fmt.Sprintf("ret a")
+}
+
+// RetConstant exits the BPF program, returning a constant value.
+type RetConstant struct {
+ Val uint32
+}
+
+// Assemble implements the Instruction Assemble method.
+func (a RetConstant) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsReturn | opRetSrcConstant,
+ K: a.Val,
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a RetConstant) String() string {
+ return fmt.Sprintf("ret #%d", a.Val)
+}
+
+// TXA copies the value of register X to register A.
+type TXA struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a TXA) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsMisc | opMiscTXA,
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a TXA) String() string {
+ return fmt.Sprintf("txa")
+}
+
+// TAX copies the value of register A to register X.
+type TAX struct{}
+
+// Assemble implements the Instruction Assemble method.
+func (a TAX) Assemble() (RawInstruction, error) {
+ return RawInstruction{
+ Op: opClsMisc | opMiscTAX,
+ }, nil
+}
+
+// String returns the instruction in assembler notation.
+func (a TAX) String() string {
+ return fmt.Sprintf("tax")
+}
+
+func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
+ var (
+ cls uint16
+ sz uint16
+ )
+ switch dst {
+ case RegA:
+ cls = opClsLoadA
+ case RegX:
+ cls = opClsLoadX
+ default:
+ return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
+ }
+ switch loadSize {
+ case 1:
+ sz = opLoadWidth1
+ case 2:
+ sz = opLoadWidth2
+ case 4:
+ sz = opLoadWidth4
+ default:
+ return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
+ }
+ return RawInstruction{
+ Op: cls | sz | mode,
+ K: k,
+ }, nil
+}
diff --git a/vendor/golang.org/x/net/bpf/setter.go b/vendor/golang.org/x/net/bpf/setter.go
new file mode 100644
index 00000000..43e35f0a
--- /dev/null
+++ b/vendor/golang.org/x/net/bpf/setter.go
@@ -0,0 +1,10 @@
+// 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.
+
+package bpf
+
+// A Setter is a type which can attach a compiled BPF filter to itself.
+type Setter interface {
+ SetBPF(filter []RawInstruction) error
+}
diff --git a/vendor/golang.org/x/net/bpf/vm.go b/vendor/golang.org/x/net/bpf/vm.go
new file mode 100644
index 00000000..73f57f1f
--- /dev/null
+++ b/vendor/golang.org/x/net/bpf/vm.go
@@ -0,0 +1,150 @@
+// 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 bpf
+
+import (
+ "errors"
+ "fmt"
+)
+
+// A VM is an emulated BPF virtual machine.
+type VM struct {
+ filter []Instruction
+}
+
+// NewVM returns a new VM using the input BPF program.
+func NewVM(filter []Instruction) (*VM, error) {
+ if len(filter) == 0 {
+ return nil, errors.New("one or more Instructions must be specified")
+ }
+
+ for i, ins := range filter {
+ check := len(filter) - (i + 1)
+ switch ins := ins.(type) {
+ // Check for out-of-bounds jumps in instructions
+ case Jump:
+ if check <= int(ins.Skip) {
+ return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
+ }
+ case JumpIf:
+ if check <= int(ins.SkipTrue) {
+ return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
+ }
+ if check <= int(ins.SkipFalse) {
+ return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
+ }
+ case JumpIfX:
+ if check <= int(ins.SkipTrue) {
+ return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
+ }
+ if check <= int(ins.SkipFalse) {
+ return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
+ }
+ // Check for division or modulus by zero
+ case ALUOpConstant:
+ if ins.Val != 0 {
+ break
+ }
+
+ switch ins.Op {
+ case ALUOpDiv, ALUOpMod:
+ return nil, errors.New("cannot divide by zero using ALUOpConstant")
+ }
+ // Check for unknown extensions
+ case LoadExtension:
+ switch ins.Num {
+ case ExtLen:
+ default:
+ return nil, fmt.Errorf("extension %d not implemented", ins.Num)
+ }
+ }
+ }
+
+ // Make sure last instruction is a return instruction
+ switch filter[len(filter)-1].(type) {
+ case RetA, RetConstant:
+ default:
+ return nil, errors.New("BPF program must end with RetA or RetConstant")
+ }
+
+ // Though our VM works using disassembled instructions, we
+ // attempt to assemble the input filter anyway to ensure it is compatible
+ // with an operating system VM.
+ _, err := Assemble(filter)
+
+ return &VM{
+ filter: filter,
+ }, err
+}
+
+// Run runs the VM's BPF program against the input bytes.
+// Run returns the number of bytes accepted by the BPF program, and any errors
+// which occurred while processing the program.
+func (v *VM) Run(in []byte) (int, error) {
+ var (
+ // Registers of the virtual machine
+ regA uint32
+ regX uint32
+ regScratch [16]uint32
+
+ // OK is true if the program should continue processing the next
+ // instruction, or false if not, causing the loop to break
+ ok = true
+ )
+
+ // TODO(mdlayher): implement:
+ // - NegateA:
+ // - would require a change from uint32 registers to int32
+ // registers
+
+ // TODO(mdlayher): add interop tests that check signedness of ALU
+ // operations against kernel implementation, and make sure Go
+ // implementation matches behavior
+
+ for i := 0; i < len(v.filter) && ok; i++ {
+ ins := v.filter[i]
+
+ switch ins := ins.(type) {
+ case ALUOpConstant:
+ regA = aluOpConstant(ins, regA)
+ case ALUOpX:
+ regA, ok = aluOpX(ins, regA, regX)
+ case Jump:
+ i += int(ins.Skip)
+ case JumpIf:
+ jump := jumpIf(ins, regA)
+ i += jump
+ case JumpIfX:
+ jump := jumpIfX(ins, regA, regX)
+ i += jump
+ case LoadAbsolute:
+ regA, ok = loadAbsolute(ins, in)
+ case LoadConstant:
+ regA, regX = loadConstant(ins, regA, regX)
+ case LoadExtension:
+ regA = loadExtension(ins, in)
+ case LoadIndirect:
+ regA, ok = loadIndirect(ins, in, regX)
+ case LoadMemShift:
+ regX, ok = loadMemShift(ins, in)
+ case LoadScratch:
+ regA, regX = loadScratch(ins, regScratch, regA, regX)
+ case RetA:
+ return int(regA), nil
+ case RetConstant:
+ return int(ins.Val), nil
+ case StoreScratch:
+ regScratch = storeScratch(ins, regScratch, regA, regX)
+ case TAX:
+ regX = regA
+ case TXA:
+ regA = regX
+ default:
+ return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
+ }
+ }
+
+ return 0, nil
+}
diff --git a/vendor/golang.org/x/net/bpf/vm_instructions.go b/vendor/golang.org/x/net/bpf/vm_instructions.go
new file mode 100644
index 00000000..0aa307c0
--- /dev/null
+++ b/vendor/golang.org/x/net/bpf/vm_instructions.go
@@ -0,0 +1,182 @@
+// 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 bpf
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
+ return aluOpCommon(ins.Op, regA, ins.Val)
+}
+
+func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
+ // Guard against division or modulus by zero by terminating
+ // the program, as the OS BPF VM does
+ if regX == 0 {
+ switch ins.Op {
+ case ALUOpDiv, ALUOpMod:
+ return 0, false
+ }
+ }
+
+ return aluOpCommon(ins.Op, regA, regX), true
+}
+
+func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
+ switch op {
+ case ALUOpAdd:
+ return regA + value
+ case ALUOpSub:
+ return regA - value
+ case ALUOpMul:
+ return regA * value
+ case ALUOpDiv:
+ // Division by zero not permitted by NewVM and aluOpX checks
+ return regA / value
+ case ALUOpOr:
+ return regA | value
+ case ALUOpAnd:
+ return regA & value
+ case ALUOpShiftLeft:
+ return regA << value
+ case ALUOpShiftRight:
+ return regA >> value
+ case ALUOpMod:
+ // Modulus by zero not permitted by NewVM and aluOpX checks
+ return regA % value
+ case ALUOpXor:
+ return regA ^ value
+ default:
+ return regA
+ }
+}
+
+func jumpIf(ins JumpIf, regA uint32) int {
+ return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
+}
+
+func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
+ return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
+}
+
+func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int {
+ var ok bool
+
+ switch cond {
+ case JumpEqual:
+ ok = regA == value
+ case JumpNotEqual:
+ ok = regA != value
+ case JumpGreaterThan:
+ ok = regA > value
+ case JumpLessThan:
+ ok = regA < value
+ case JumpGreaterOrEqual:
+ ok = regA >= value
+ case JumpLessOrEqual:
+ ok = regA <= value
+ case JumpBitsSet:
+ ok = (regA & value) != 0
+ case JumpBitsNotSet:
+ ok = (regA & value) == 0
+ }
+
+ if ok {
+ return int(skipTrue)
+ }
+
+ return int(skipFalse)
+}
+
+func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
+ offset := int(ins.Off)
+ size := ins.Size
+
+ return loadCommon(in, offset, size)
+}
+
+func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
+ switch ins.Dst {
+ case RegA:
+ regA = ins.Val
+ case RegX:
+ regX = ins.Val
+ }
+
+ return regA, regX
+}
+
+func loadExtension(ins LoadExtension, in []byte) uint32 {
+ switch ins.Num {
+ case ExtLen:
+ return uint32(len(in))
+ default:
+ panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
+ }
+}
+
+func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
+ offset := int(ins.Off) + int(regX)
+ size := ins.Size
+
+ return loadCommon(in, offset, size)
+}
+
+func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
+ offset := int(ins.Off)
+
+ // Size of LoadMemShift is always 1 byte
+ if !inBounds(len(in), offset, 1) {
+ return 0, false
+ }
+
+ // Mask off high 4 bits and multiply low 4 bits by 4
+ return uint32(in[offset]&0x0f) * 4, true
+}
+
+func inBounds(inLen int, offset int, size int) bool {
+ return offset+size <= inLen
+}
+
+func loadCommon(in []byte, offset int, size int) (uint32, bool) {
+ if !inBounds(len(in), offset, size) {
+ return 0, false
+ }
+
+ switch size {
+ case 1:
+ return uint32(in[offset]), true
+ case 2:
+ return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
+ case 4:
+ return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
+ default:
+ panic(fmt.Sprintf("invalid load size: %d", size))
+ }
+}
+
+func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
+ switch ins.Dst {
+ case RegA:
+ regA = regScratch[ins.N]
+ case RegX:
+ regX = regScratch[ins.N]
+ }
+
+ return regA, regX
+}
+
+func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
+ switch ins.Src {
+ case RegA:
+ regScratch[ins.N] = regA
+ case RegX:
+ regScratch[ins.N] = regX
+ }
+
+ return regScratch
+}
diff --git a/vendor/golang.org/x/net/html/atom/atom.go b/vendor/golang.org/x/net/html/atom/atom.go
new file mode 100644
index 00000000..cd0a8ac1
--- /dev/null
+++ b/vendor/golang.org/x/net/html/atom/atom.go
@@ -0,0 +1,78 @@
+// Copyright 2012 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 atom provides integer codes (also known as atoms) for a fixed set of
+// frequently occurring HTML strings: tag names and attribute keys such as "p"
+// and "id".
+//
+// Sharing an atom's name between all elements with the same tag can result in
+// fewer string allocations when tokenizing and parsing HTML. Integer
+// comparisons are also generally faster than string comparisons.
+//
+// The value of an atom's particular code is not guaranteed to stay the same
+// between versions of this package. Neither is any ordering guaranteed:
+// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
+// be dense. The only guarantees are that e.g. looking up "div" will yield
+// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
+package atom // import "golang.org/x/net/html/atom"
+
+// Atom is an integer code for a string. The zero value maps to "".
+type Atom uint32
+
+// String returns the atom's name.
+func (a Atom) String() string {
+ start := uint32(a >> 8)
+ n := uint32(a & 0xff)
+ if start+n > uint32(len(atomText)) {
+ return ""
+ }
+ return atomText[start : start+n]
+}
+
+func (a Atom) string() string {
+ return atomText[a>>8 : a>>8+a&0xff]
+}
+
+// fnv computes the FNV hash with an arbitrary starting value h.
+func fnv(h uint32, s []byte) uint32 {
+ for i := range s {
+ h ^= uint32(s[i])
+ h *= 16777619
+ }
+ return h
+}
+
+func match(s string, t []byte) bool {
+ for i, c := range t {
+ if s[i] != c {
+ return false
+ }
+ }
+ return true
+}
+
+// Lookup returns the atom whose name is s. It returns zero if there is no
+// such atom. The lookup is case sensitive.
+func Lookup(s []byte) Atom {
+ if len(s) == 0 || len(s) > maxAtomLen {
+ return 0
+ }
+ h := fnv(hash0, s)
+ if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
+ return a
+ }
+ if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
+ return a
+ }
+ return 0
+}
+
+// String returns a string whose contents are equal to s. In that sense, it is
+// equivalent to string(s) but may be more efficient.
+func String(s []byte) string {
+ if a := Lookup(s); a != 0 {
+ return a.String()
+ }
+ return string(s)
+}
diff --git a/vendor/golang.org/x/net/html/atom/table.go b/vendor/golang.org/x/net/html/atom/table.go
new file mode 100644
index 00000000..b460e6f7
--- /dev/null
+++ b/vendor/golang.org/x/net/html/atom/table.go
@@ -0,0 +1,785 @@
+// Code generated by go generate gen.go; DO NOT EDIT.
+
+//go:generate go run gen.go
+
+package atom
+
+const (
+ A Atom = 0x1
+ Abbr Atom = 0x4
+ Accept Atom = 0x1a06
+ AcceptCharset Atom = 0x1a0e
+ Accesskey Atom = 0x2c09
+ Acronym Atom = 0xaa07
+ Action Atom = 0x26506
+ Address Atom = 0x6f107
+ Align Atom = 0xb105
+ Allowfullscreen Atom = 0x3280f
+ Allowpaymentrequest Atom = 0xc113
+ Allowusermedia Atom = 0xdd0e
+ Alt Atom = 0xf303
+ Annotation Atom = 0x1c90a
+ AnnotationXml Atom = 0x1c90e
+ Applet Atom = 0x30806
+ Area Atom = 0x35004
+ Article Atom = 0x3f607
+ As Atom = 0x3c02
+ Aside Atom = 0x10705
+ Async Atom = 0xff05
+ Audio Atom = 0x11505
+ Autocomplete Atom = 0x26b0c
+ Autofocus Atom = 0x12109
+ Autoplay Atom = 0x13c08
+ B Atom = 0x101
+ Base Atom = 0x3b04
+ Basefont Atom = 0x3b08
+ Bdi Atom = 0xba03
+ Bdo Atom = 0x14b03
+ Bgsound Atom = 0x15e07
+ Big Atom = 0x17003
+ Blink Atom = 0x17305
+ Blockquote Atom = 0x1870a
+ Body Atom = 0x2804
+ Br Atom = 0x202
+ Button Atom = 0x19106
+ Canvas Atom = 0x10306
+ Caption Atom = 0x22407
+ Center Atom = 0x21306
+ Challenge Atom = 0x28e09
+ Charset Atom = 0x2107
+ Checked Atom = 0x5b507
+ Cite Atom = 0x19c04
+ Class Atom = 0x55805
+ Code Atom = 0x5ee04
+ Col Atom = 0x1ab03
+ Colgroup Atom = 0x1ab08
+ Color Atom = 0x1bf05
+ Cols Atom = 0x1c404
+ Colspan Atom = 0x1c407
+ Command Atom = 0x1d707
+ Content Atom = 0x57b07
+ Contenteditable Atom = 0x57b0f
+ Contextmenu Atom = 0x37a0b
+ Controls Atom = 0x1de08
+ Coords Atom = 0x1f006
+ Crossorigin Atom = 0x1fa0b
+ Data Atom = 0x49904
+ Datalist Atom = 0x49908
+ Datetime Atom = 0x2ab08
+ Dd Atom = 0x2bf02
+ Default Atom = 0x10a07
+ Defer Atom = 0x5f005
+ Del Atom = 0x44c03
+ Desc Atom = 0x55504
+ Details Atom = 0x7207
+ Dfn Atom = 0x8703
+ Dialog Atom = 0xbb06
+ Dir Atom = 0x9303
+ Dirname Atom = 0x9307
+ Disabled Atom = 0x16408
+ Div Atom = 0x16b03
+ Dl Atom = 0x5d602
+ Download Atom = 0x45d08
+ Draggable Atom = 0x17a09
+ Dropzone Atom = 0x3ff08
+ Dt Atom = 0x64002
+ Em Atom = 0x6e02
+ Embed Atom = 0x6e05
+ Enctype Atom = 0x28007
+ Face Atom = 0x21104
+ Fieldset Atom = 0x21908
+ Figcaption Atom = 0x2210a
+ Figure Atom = 0x23b06
+ Font Atom = 0x3f04
+ Footer Atom = 0xf606
+ For Atom = 0x24703
+ ForeignObject Atom = 0x2470d
+ Foreignobject Atom = 0x2540d
+ Form Atom = 0x26104
+ Formaction Atom = 0x2610a
+ Formenctype Atom = 0x27c0b
+ Formmethod Atom = 0x2970a
+ Formnovalidate Atom = 0x2a10e
+ Formtarget Atom = 0x2b30a
+ Frame Atom = 0x8b05
+ Frameset Atom = 0x8b08
+ H1 Atom = 0x15c02
+ H2 Atom = 0x56102
+ H3 Atom = 0x2cd02
+ H4 Atom = 0x2fc02
+ H5 Atom = 0x33f02
+ H6 Atom = 0x34902
+ Head Atom = 0x32004
+ Header Atom = 0x32006
+ Headers Atom = 0x32007
+ Height Atom = 0x5206
+ Hgroup Atom = 0x64206
+ Hidden Atom = 0x2bd06
+ High Atom = 0x2ca04
+ Hr Atom = 0x15702
+ Href Atom = 0x2cf04
+ Hreflang Atom = 0x2cf08
+ Html Atom = 0x5604
+ HttpEquiv Atom = 0x2d70a
+ I Atom = 0x601
+ Icon Atom = 0x57a04
+ Id Atom = 0x10902
+ Iframe Atom = 0x2eb06
+ Image Atom = 0x2f105
+ Img Atom = 0x2f603
+ Input Atom = 0x44505
+ Inputmode Atom = 0x44509
+ Ins Atom = 0x20303
+ Integrity Atom = 0x23209
+ Is Atom = 0x16502
+ Isindex Atom = 0x2fe07
+ Ismap Atom = 0x30505
+ Itemid Atom = 0x38506
+ Itemprop Atom = 0x19d08
+ Itemref Atom = 0x3c707
+ Itemscope Atom = 0x66f09
+ Itemtype Atom = 0x30e08
+ Kbd Atom = 0xb903
+ Keygen Atom = 0x3206
+ Keytype Atom = 0xd607
+ Kind Atom = 0x17704
+ Label Atom = 0x5905
+ Lang Atom = 0x2d304
+ Legend Atom = 0x18106
+ Li Atom = 0xb202
+ Link Atom = 0x17404
+ List Atom = 0x49d04
+ Listing Atom = 0x49d07
+ Loop Atom = 0x5d04
+ Low Atom = 0xc303
+ Main Atom = 0x1004
+ Malignmark Atom = 0xb00a
+ Manifest Atom = 0x6d508
+ Map Atom = 0x30703
+ Mark Atom = 0xb604
+ Marquee Atom = 0x31607
+ Math Atom = 0x31d04
+ Max Atom = 0x33703
+ Maxlength Atom = 0x33709
+ Media Atom = 0xe605
+ Mediagroup Atom = 0xe60a
+ Menu Atom = 0x38104
+ Menuitem Atom = 0x38108
+ Meta Atom = 0x4ac04
+ Meter Atom = 0x9805
+ Method Atom = 0x29b06
+ Mglyph Atom = 0x2f706
+ Mi Atom = 0x34102
+ Min Atom = 0x34103
+ Minlength Atom = 0x34109
+ Mn Atom = 0x2a402
+ Mo Atom = 0xa402
+ Ms Atom = 0x67202
+ Mtext Atom = 0x34b05
+ Multiple Atom = 0x35908
+ Muted Atom = 0x36105
+ Name Atom = 0x9604
+ Nav Atom = 0x1303
+ Nobr Atom = 0x3704
+ Noembed Atom = 0x6c07
+ Noframes Atom = 0x8908
+ Nomodule Atom = 0xa208
+ Nonce Atom = 0x1a605
+ Noscript Atom = 0x2c208
+ Novalidate Atom = 0x2a50a
+ Object Atom = 0x25b06
+ Ol Atom = 0x13702
+ Onabort Atom = 0x19507
+ Onafterprint Atom = 0x2290c
+ Onautocomplete Atom = 0x2690e
+ Onautocompleteerror Atom = 0x26913
+ Onauxclick Atom = 0x6140a
+ Onbeforeprint Atom = 0x69c0d
+ Onbeforeunload Atom = 0x6e50e
+ Onblur Atom = 0x1ea06
+ Oncancel Atom = 0x11908
+ Oncanplay Atom = 0x14d09
+ Oncanplaythrough Atom = 0x14d10
+ Onchange Atom = 0x41508
+ Onclick Atom = 0x2e407
+ Onclose Atom = 0x36607
+ Oncontextmenu Atom = 0x3780d
+ Oncopy Atom = 0x38b06
+ Oncuechange Atom = 0x3910b
+ Oncut Atom = 0x39c05
+ Ondblclick Atom = 0x3a10a
+ Ondrag Atom = 0x3ab06
+ Ondragend Atom = 0x3ab09
+ Ondragenter Atom = 0x3b40b
+ Ondragexit Atom = 0x3bf0a
+ Ondragleave Atom = 0x3d90b
+ Ondragover Atom = 0x3e40a
+ Ondragstart Atom = 0x3ee0b
+ Ondrop Atom = 0x3fd06
+ Ondurationchange Atom = 0x40d10
+ Onemptied Atom = 0x40409
+ Onended Atom = 0x41d07
+ Onerror Atom = 0x42407
+ Onfocus Atom = 0x42b07
+ Onhashchange Atom = 0x4370c
+ Oninput Atom = 0x44307
+ Oninvalid Atom = 0x44f09
+ Onkeydown Atom = 0x45809
+ Onkeypress Atom = 0x4650a
+ Onkeyup Atom = 0x47407
+ Onlanguagechange Atom = 0x48110
+ Onload Atom = 0x49106
+ Onloadeddata Atom = 0x4910c
+ Onloadedmetadata Atom = 0x4a410
+ Onloadend Atom = 0x4ba09
+ Onloadstart Atom = 0x4c30b
+ Onmessage Atom = 0x4ce09
+ Onmessageerror Atom = 0x4ce0e
+ Onmousedown Atom = 0x4dc0b
+ Onmouseenter Atom = 0x4e70c
+ Onmouseleave Atom = 0x4f30c
+ Onmousemove Atom = 0x4ff0b
+ Onmouseout Atom = 0x50a0a
+ Onmouseover Atom = 0x5170b
+ Onmouseup Atom = 0x52209
+ Onmousewheel Atom = 0x5300c
+ Onoffline Atom = 0x53c09
+ Ononline Atom = 0x54508
+ Onpagehide Atom = 0x54d0a
+ Onpageshow Atom = 0x5630a
+ Onpaste Atom = 0x56f07
+ Onpause Atom = 0x58a07
+ Onplay Atom = 0x59406
+ Onplaying Atom = 0x59409
+ Onpopstate Atom = 0x59d0a
+ Onprogress Atom = 0x5a70a
+ Onratechange Atom = 0x5bc0c
+ Onrejectionhandled Atom = 0x5c812
+ Onreset Atom = 0x5da07
+ Onresize Atom = 0x5e108
+ Onscroll Atom = 0x5f508
+ Onsecuritypolicyviolation Atom = 0x5fd19
+ Onseeked Atom = 0x61e08
+ Onseeking Atom = 0x62609
+ Onselect Atom = 0x62f08
+ Onshow Atom = 0x63906
+ Onsort Atom = 0x64d06
+ Onstalled Atom = 0x65709
+ Onstorage Atom = 0x66009
+ Onsubmit Atom = 0x66908
+ Onsuspend Atom = 0x67909
+ Ontimeupdate Atom = 0x400c
+ Ontoggle Atom = 0x68208
+ Onunhandledrejection Atom = 0x68a14
+ Onunload Atom = 0x6a908
+ Onvolumechange Atom = 0x6b10e
+ Onwaiting Atom = 0x6bf09
+ Onwheel Atom = 0x6c807
+ Open Atom = 0x1a304
+ Optgroup Atom = 0x5f08
+ Optimum Atom = 0x6cf07
+ Option Atom = 0x6e106
+ Output Atom = 0x51106
+ P Atom = 0xc01
+ Param Atom = 0xc05
+ Pattern Atom = 0x6607
+ Picture Atom = 0x7b07
+ Ping Atom = 0xef04
+ Placeholder Atom = 0x1310b
+ Plaintext Atom = 0x1b209
+ Playsinline Atom = 0x1400b
+ Poster Atom = 0x64706
+ Pre Atom = 0x46a03
+ Preload Atom = 0x47a07
+ Progress Atom = 0x5a908
+ Prompt Atom = 0x52a06
+ Public Atom = 0x57606
+ Q Atom = 0xcf01
+ Radiogroup Atom = 0x30a
+ Rb Atom = 0x3a02
+ Readonly Atom = 0x35108
+ Referrerpolicy Atom = 0x3cb0e
+ Rel Atom = 0x47b03
+ Required Atom = 0x23f08
+ Reversed Atom = 0x8008
+ Rows Atom = 0x9c04
+ Rowspan Atom = 0x9c07
+ Rp Atom = 0x22f02
+ Rt Atom = 0x19a02
+ Rtc Atom = 0x19a03
+ Ruby Atom = 0xfb04
+ S Atom = 0x2501
+ Samp Atom = 0x7804
+ Sandbox Atom = 0x12907
+ Scope Atom = 0x67305
+ Scoped Atom = 0x67306
+ Script Atom = 0x2c406
+ Seamless Atom = 0x36b08
+ Search Atom = 0x55c06
+ Section Atom = 0x1e507
+ Select Atom = 0x63106
+ Selected Atom = 0x63108
+ Shape Atom = 0x1f505
+ Size Atom = 0x5e504
+ Sizes Atom = 0x5e505
+ Slot Atom = 0x20504
+ Small Atom = 0x32605
+ Sortable Atom = 0x64f08
+ Sorted Atom = 0x37206
+ Source Atom = 0x43106
+ Spacer Atom = 0x46e06
+ Span Atom = 0x9f04
+ Spellcheck Atom = 0x5b00a
+ Src Atom = 0x5e903
+ Srcdoc Atom = 0x5e906
+ Srclang Atom = 0x6f707
+ Srcset Atom = 0x6fe06
+ Start Atom = 0x3f405
+ Step Atom = 0x57304
+ Strike Atom = 0xd206
+ Strong Atom = 0x6db06
+ Style Atom = 0x70405
+ Sub Atom = 0x66b03
+ Summary Atom = 0x70907
+ Sup Atom = 0x71003
+ Svg Atom = 0x71303
+ System Atom = 0x71606
+ Tabindex Atom = 0x4b208
+ Table Atom = 0x58505
+ Target Atom = 0x2b706
+ Tbody Atom = 0x2705
+ Td Atom = 0x9202
+ Template Atom = 0x71908
+ Textarea Atom = 0x34c08
+ Tfoot Atom = 0xf505
+ Th Atom = 0x15602
+ Thead Atom = 0x31f05
+ Time Atom = 0x4204
+ Title Atom = 0x11005
+ Tr Atom = 0xcc02
+ Track Atom = 0x1ba05
+ Translate Atom = 0x20809
+ Tt Atom = 0x6802
+ Type Atom = 0xd904
+ Typemustmatch Atom = 0x2830d
+ U Atom = 0xb01
+ Ul Atom = 0xa702
+ Updateviacache Atom = 0x460e
+ Usemap Atom = 0x58e06
+ Value Atom = 0x1505
+ Var Atom = 0x16d03
+ Video Atom = 0x2e005
+ Wbr Atom = 0x56c03
+ Width Atom = 0x63e05
+ Workertype Atom = 0x7210a
+ Wrap Atom = 0x72b04
+ Xmp Atom = 0x12f03
+)
+
+const hash0 = 0x84f70e16
+
+const maxAtomLen = 25
+
+var table = [1 << 9]Atom{
+ 0x1: 0x3ff08, // dropzone
+ 0x2: 0x3b08, // basefont
+ 0x3: 0x23209, // integrity
+ 0x4: 0x43106, // source
+ 0x5: 0x2c09, // accesskey
+ 0x6: 0x1a06, // accept
+ 0x7: 0x6c807, // onwheel
+ 0xb: 0x47407, // onkeyup
+ 0xc: 0x32007, // headers
+ 0xd: 0x67306, // scoped
+ 0xe: 0x67909, // onsuspend
+ 0xf: 0x8908, // noframes
+ 0x10: 0x1fa0b, // crossorigin
+ 0x11: 0x2e407, // onclick
+ 0x12: 0x3f405, // start
+ 0x13: 0x37a0b, // contextmenu
+ 0x14: 0x5e903, // src
+ 0x15: 0x1c404, // cols
+ 0x16: 0xbb06, // dialog
+ 0x17: 0x47a07, // preload
+ 0x18: 0x3c707, // itemref
+ 0x1b: 0x2f105, // image
+ 0x1d: 0x4ba09, // onloadend
+ 0x1e: 0x45d08, // download
+ 0x1f: 0x46a03, // pre
+ 0x23: 0x2970a, // formmethod
+ 0x24: 0x71303, // svg
+ 0x25: 0xcf01, // q
+ 0x26: 0x64002, // dt
+ 0x27: 0x1de08, // controls
+ 0x2a: 0x2804, // body
+ 0x2b: 0xd206, // strike
+ 0x2c: 0x3910b, // oncuechange
+ 0x2d: 0x4c30b, // onloadstart
+ 0x2e: 0x2fe07, // isindex
+ 0x2f: 0xb202, // li
+ 0x30: 0x1400b, // playsinline
+ 0x31: 0x34102, // mi
+ 0x32: 0x30806, // applet
+ 0x33: 0x4ce09, // onmessage
+ 0x35: 0x13702, // ol
+ 0x36: 0x1a304, // open
+ 0x39: 0x14d09, // oncanplay
+ 0x3a: 0x6bf09, // onwaiting
+ 0x3b: 0x11908, // oncancel
+ 0x3c: 0x6a908, // onunload
+ 0x3e: 0x53c09, // onoffline
+ 0x3f: 0x1a0e, // accept-charset
+ 0x40: 0x32004, // head
+ 0x42: 0x3ab09, // ondragend
+ 0x43: 0x1310b, // placeholder
+ 0x44: 0x2b30a, // formtarget
+ 0x45: 0x2540d, // foreignobject
+ 0x47: 0x400c, // ontimeupdate
+ 0x48: 0xdd0e, // allowusermedia
+ 0x4a: 0x69c0d, // onbeforeprint
+ 0x4b: 0x5604, // html
+ 0x4c: 0x9f04, // span
+ 0x4d: 0x64206, // hgroup
+ 0x4e: 0x16408, // disabled
+ 0x4f: 0x4204, // time
+ 0x51: 0x42b07, // onfocus
+ 0x53: 0xb00a, // malignmark
+ 0x55: 0x4650a, // onkeypress
+ 0x56: 0x55805, // class
+ 0x57: 0x1ab08, // colgroup
+ 0x58: 0x33709, // maxlength
+ 0x59: 0x5a908, // progress
+ 0x5b: 0x70405, // style
+ 0x5c: 0x2a10e, // formnovalidate
+ 0x5e: 0x38b06, // oncopy
+ 0x60: 0x26104, // form
+ 0x61: 0xf606, // footer
+ 0x64: 0x30a, // radiogroup
+ 0x66: 0xfb04, // ruby
+ 0x67: 0x4ff0b, // onmousemove
+ 0x68: 0x19d08, // itemprop
+ 0x69: 0x2d70a, // http-equiv
+ 0x6a: 0x15602, // th
+ 0x6c: 0x6e02, // em
+ 0x6d: 0x38108, // menuitem
+ 0x6e: 0x63106, // select
+ 0x6f: 0x48110, // onlanguagechange
+ 0x70: 0x31f05, // thead
+ 0x71: 0x15c02, // h1
+ 0x72: 0x5e906, // srcdoc
+ 0x75: 0x9604, // name
+ 0x76: 0x19106, // button
+ 0x77: 0x55504, // desc
+ 0x78: 0x17704, // kind
+ 0x79: 0x1bf05, // color
+ 0x7c: 0x58e06, // usemap
+ 0x7d: 0x30e08, // itemtype
+ 0x7f: 0x6d508, // manifest
+ 0x81: 0x5300c, // onmousewheel
+ 0x82: 0x4dc0b, // onmousedown
+ 0x84: 0xc05, // param
+ 0x85: 0x2e005, // video
+ 0x86: 0x4910c, // onloadeddata
+ 0x87: 0x6f107, // address
+ 0x8c: 0xef04, // ping
+ 0x8d: 0x24703, // for
+ 0x8f: 0x62f08, // onselect
+ 0x90: 0x30703, // map
+ 0x92: 0xc01, // p
+ 0x93: 0x8008, // reversed
+ 0x94: 0x54d0a, // onpagehide
+ 0x95: 0x3206, // keygen
+ 0x96: 0x34109, // minlength
+ 0x97: 0x3e40a, // ondragover
+ 0x98: 0x42407, // onerror
+ 0x9a: 0x2107, // charset
+ 0x9b: 0x29b06, // method
+ 0x9c: 0x101, // b
+ 0x9d: 0x68208, // ontoggle
+ 0x9e: 0x2bd06, // hidden
+ 0xa0: 0x3f607, // article
+ 0xa2: 0x63906, // onshow
+ 0xa3: 0x64d06, // onsort
+ 0xa5: 0x57b0f, // contenteditable
+ 0xa6: 0x66908, // onsubmit
+ 0xa8: 0x44f09, // oninvalid
+ 0xaa: 0x202, // br
+ 0xab: 0x10902, // id
+ 0xac: 0x5d04, // loop
+ 0xad: 0x5630a, // onpageshow
+ 0xb0: 0x2cf04, // href
+ 0xb2: 0x2210a, // figcaption
+ 0xb3: 0x2690e, // onautocomplete
+ 0xb4: 0x49106, // onload
+ 0xb6: 0x9c04, // rows
+ 0xb7: 0x1a605, // nonce
+ 0xb8: 0x68a14, // onunhandledrejection
+ 0xbb: 0x21306, // center
+ 0xbc: 0x59406, // onplay
+ 0xbd: 0x33f02, // h5
+ 0xbe: 0x49d07, // listing
+ 0xbf: 0x57606, // public
+ 0xc2: 0x23b06, // figure
+ 0xc3: 0x57a04, // icon
+ 0xc4: 0x1ab03, // col
+ 0xc5: 0x47b03, // rel
+ 0xc6: 0xe605, // media
+ 0xc7: 0x12109, // autofocus
+ 0xc8: 0x19a02, // rt
+ 0xca: 0x2d304, // lang
+ 0xcc: 0x49908, // datalist
+ 0xce: 0x2eb06, // iframe
+ 0xcf: 0x36105, // muted
+ 0xd0: 0x6140a, // onauxclick
+ 0xd2: 0x3c02, // as
+ 0xd6: 0x3fd06, // ondrop
+ 0xd7: 0x1c90a, // annotation
+ 0xd8: 0x21908, // fieldset
+ 0xdb: 0x2cf08, // hreflang
+ 0xdc: 0x4e70c, // onmouseenter
+ 0xdd: 0x2a402, // mn
+ 0xde: 0xe60a, // mediagroup
+ 0xdf: 0x9805, // meter
+ 0xe0: 0x56c03, // wbr
+ 0xe2: 0x63e05, // width
+ 0xe3: 0x2290c, // onafterprint
+ 0xe4: 0x30505, // ismap
+ 0xe5: 0x1505, // value
+ 0xe7: 0x1303, // nav
+ 0xe8: 0x54508, // ononline
+ 0xe9: 0xb604, // mark
+ 0xea: 0xc303, // low
+ 0xeb: 0x3ee0b, // ondragstart
+ 0xef: 0x12f03, // xmp
+ 0xf0: 0x22407, // caption
+ 0xf1: 0xd904, // type
+ 0xf2: 0x70907, // summary
+ 0xf3: 0x6802, // tt
+ 0xf4: 0x20809, // translate
+ 0xf5: 0x1870a, // blockquote
+ 0xf8: 0x15702, // hr
+ 0xfa: 0x2705, // tbody
+ 0xfc: 0x7b07, // picture
+ 0xfd: 0x5206, // height
+ 0xfe: 0x19c04, // cite
+ 0xff: 0x2501, // s
+ 0x101: 0xff05, // async
+ 0x102: 0x56f07, // onpaste
+ 0x103: 0x19507, // onabort
+ 0x104: 0x2b706, // target
+ 0x105: 0x14b03, // bdo
+ 0x106: 0x1f006, // coords
+ 0x107: 0x5e108, // onresize
+ 0x108: 0x71908, // template
+ 0x10a: 0x3a02, // rb
+ 0x10b: 0x2a50a, // novalidate
+ 0x10c: 0x460e, // updateviacache
+ 0x10d: 0x71003, // sup
+ 0x10e: 0x6c07, // noembed
+ 0x10f: 0x16b03, // div
+ 0x110: 0x6f707, // srclang
+ 0x111: 0x17a09, // draggable
+ 0x112: 0x67305, // scope
+ 0x113: 0x5905, // label
+ 0x114: 0x22f02, // rp
+ 0x115: 0x23f08, // required
+ 0x116: 0x3780d, // oncontextmenu
+ 0x117: 0x5e504, // size
+ 0x118: 0x5b00a, // spellcheck
+ 0x119: 0x3f04, // font
+ 0x11a: 0x9c07, // rowspan
+ 0x11b: 0x10a07, // default
+ 0x11d: 0x44307, // oninput
+ 0x11e: 0x38506, // itemid
+ 0x11f: 0x5ee04, // code
+ 0x120: 0xaa07, // acronym
+ 0x121: 0x3b04, // base
+ 0x125: 0x2470d, // foreignObject
+ 0x126: 0x2ca04, // high
+ 0x127: 0x3cb0e, // referrerpolicy
+ 0x128: 0x33703, // max
+ 0x129: 0x59d0a, // onpopstate
+ 0x12a: 0x2fc02, // h4
+ 0x12b: 0x4ac04, // meta
+ 0x12c: 0x17305, // blink
+ 0x12e: 0x5f508, // onscroll
+ 0x12f: 0x59409, // onplaying
+ 0x130: 0xc113, // allowpaymentrequest
+ 0x131: 0x19a03, // rtc
+ 0x132: 0x72b04, // wrap
+ 0x134: 0x8b08, // frameset
+ 0x135: 0x32605, // small
+ 0x137: 0x32006, // header
+ 0x138: 0x40409, // onemptied
+ 0x139: 0x34902, // h6
+ 0x13a: 0x35908, // multiple
+ 0x13c: 0x52a06, // prompt
+ 0x13f: 0x28e09, // challenge
+ 0x141: 0x4370c, // onhashchange
+ 0x142: 0x57b07, // content
+ 0x143: 0x1c90e, // annotation-xml
+ 0x144: 0x36607, // onclose
+ 0x145: 0x14d10, // oncanplaythrough
+ 0x148: 0x5170b, // onmouseover
+ 0x149: 0x64f08, // sortable
+ 0x14a: 0xa402, // mo
+ 0x14b: 0x2cd02, // h3
+ 0x14c: 0x2c406, // script
+ 0x14d: 0x41d07, // onended
+ 0x14f: 0x64706, // poster
+ 0x150: 0x7210a, // workertype
+ 0x153: 0x1f505, // shape
+ 0x154: 0x4, // abbr
+ 0x155: 0x1, // a
+ 0x156: 0x2bf02, // dd
+ 0x157: 0x71606, // system
+ 0x158: 0x4ce0e, // onmessageerror
+ 0x159: 0x36b08, // seamless
+ 0x15a: 0x2610a, // formaction
+ 0x15b: 0x6e106, // option
+ 0x15c: 0x31d04, // math
+ 0x15d: 0x62609, // onseeking
+ 0x15e: 0x39c05, // oncut
+ 0x15f: 0x44c03, // del
+ 0x160: 0x11005, // title
+ 0x161: 0x11505, // audio
+ 0x162: 0x63108, // selected
+ 0x165: 0x3b40b, // ondragenter
+ 0x166: 0x46e06, // spacer
+ 0x167: 0x4a410, // onloadedmetadata
+ 0x168: 0x44505, // input
+ 0x16a: 0x58505, // table
+ 0x16b: 0x41508, // onchange
+ 0x16e: 0x5f005, // defer
+ 0x171: 0x50a0a, // onmouseout
+ 0x172: 0x20504, // slot
+ 0x175: 0x3704, // nobr
+ 0x177: 0x1d707, // command
+ 0x17a: 0x7207, // details
+ 0x17b: 0x38104, // menu
+ 0x17c: 0xb903, // kbd
+ 0x17d: 0x57304, // step
+ 0x17e: 0x20303, // ins
+ 0x17f: 0x13c08, // autoplay
+ 0x182: 0x34103, // min
+ 0x183: 0x17404, // link
+ 0x185: 0x40d10, // ondurationchange
+ 0x186: 0x9202, // td
+ 0x187: 0x8b05, // frame
+ 0x18a: 0x2ab08, // datetime
+ 0x18b: 0x44509, // inputmode
+ 0x18c: 0x35108, // readonly
+ 0x18d: 0x21104, // face
+ 0x18f: 0x5e505, // sizes
+ 0x191: 0x4b208, // tabindex
+ 0x192: 0x6db06, // strong
+ 0x193: 0xba03, // bdi
+ 0x194: 0x6fe06, // srcset
+ 0x196: 0x67202, // ms
+ 0x197: 0x5b507, // checked
+ 0x198: 0xb105, // align
+ 0x199: 0x1e507, // section
+ 0x19b: 0x6e05, // embed
+ 0x19d: 0x15e07, // bgsound
+ 0x1a2: 0x49d04, // list
+ 0x1a3: 0x61e08, // onseeked
+ 0x1a4: 0x66009, // onstorage
+ 0x1a5: 0x2f603, // img
+ 0x1a6: 0xf505, // tfoot
+ 0x1a9: 0x26913, // onautocompleteerror
+ 0x1aa: 0x5fd19, // onsecuritypolicyviolation
+ 0x1ad: 0x9303, // dir
+ 0x1ae: 0x9307, // dirname
+ 0x1b0: 0x5a70a, // onprogress
+ 0x1b2: 0x65709, // onstalled
+ 0x1b5: 0x66f09, // itemscope
+ 0x1b6: 0x49904, // data
+ 0x1b7: 0x3d90b, // ondragleave
+ 0x1b8: 0x56102, // h2
+ 0x1b9: 0x2f706, // mglyph
+ 0x1ba: 0x16502, // is
+ 0x1bb: 0x6e50e, // onbeforeunload
+ 0x1bc: 0x2830d, // typemustmatch
+ 0x1bd: 0x3ab06, // ondrag
+ 0x1be: 0x5da07, // onreset
+ 0x1c0: 0x51106, // output
+ 0x1c1: 0x12907, // sandbox
+ 0x1c2: 0x1b209, // plaintext
+ 0x1c4: 0x34c08, // textarea
+ 0x1c7: 0xd607, // keytype
+ 0x1c8: 0x34b05, // mtext
+ 0x1c9: 0x6b10e, // onvolumechange
+ 0x1ca: 0x1ea06, // onblur
+ 0x1cb: 0x58a07, // onpause
+ 0x1cd: 0x5bc0c, // onratechange
+ 0x1ce: 0x10705, // aside
+ 0x1cf: 0x6cf07, // optimum
+ 0x1d1: 0x45809, // onkeydown
+ 0x1d2: 0x1c407, // colspan
+ 0x1d3: 0x1004, // main
+ 0x1d4: 0x66b03, // sub
+ 0x1d5: 0x25b06, // object
+ 0x1d6: 0x55c06, // search
+ 0x1d7: 0x37206, // sorted
+ 0x1d8: 0x17003, // big
+ 0x1d9: 0xb01, // u
+ 0x1db: 0x26b0c, // autocomplete
+ 0x1dc: 0xcc02, // tr
+ 0x1dd: 0xf303, // alt
+ 0x1df: 0x7804, // samp
+ 0x1e0: 0x5c812, // onrejectionhandled
+ 0x1e1: 0x4f30c, // onmouseleave
+ 0x1e2: 0x28007, // enctype
+ 0x1e3: 0xa208, // nomodule
+ 0x1e5: 0x3280f, // allowfullscreen
+ 0x1e6: 0x5f08, // optgroup
+ 0x1e8: 0x27c0b, // formenctype
+ 0x1e9: 0x18106, // legend
+ 0x1ea: 0x10306, // canvas
+ 0x1eb: 0x6607, // pattern
+ 0x1ec: 0x2c208, // noscript
+ 0x1ed: 0x601, // i
+ 0x1ee: 0x5d602, // dl
+ 0x1ef: 0xa702, // ul
+ 0x1f2: 0x52209, // onmouseup
+ 0x1f4: 0x1ba05, // track
+ 0x1f7: 0x3a10a, // ondblclick
+ 0x1f8: 0x3bf0a, // ondragexit
+ 0x1fa: 0x8703, // dfn
+ 0x1fc: 0x26506, // action
+ 0x1fd: 0x35004, // area
+ 0x1fe: 0x31607, // marquee
+ 0x1ff: 0x16d03, // var
+}
+
+const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" +
+ "asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" +
+ "sampictureversedfnoframesetdirnameterowspanomoduleacronymali" +
+ "gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" +
+ "ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" +
+ "dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" +
+ "bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" +
+ "penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" +
+ "ntrolsectionblurcoordshapecrossoriginslotranslatefacenterfie" +
+ "ldsetfigcaptionafterprintegrityfigurequiredforeignObjectfore" +
+ "ignobjectformactionautocompleteerrorformenctypemustmatchalle" +
+ "ngeformmethodformnovalidatetimeformtargethiddenoscripthigh3h" +
+ "reflanghttp-equivideonclickiframeimageimglyph4isindexismappl" +
+ "etitemtypemarqueematheadersmallowfullscreenmaxlength5minleng" +
+ "th6mtextareadonlymultiplemutedoncloseamlessortedoncontextmen" +
+ "uitemidoncopyoncuechangeoncutondblclickondragendondragentero" +
+ "ndragexitemreferrerpolicyondragleaveondragoverondragstarticl" +
+ "eondropzonemptiedondurationchangeonendedonerroronfocusourceo" +
+ "nhashchangeoninputmodeloninvalidonkeydownloadonkeypresspacer" +
+ "onkeyupreloadonlanguagechangeonloadeddatalistingonloadedmeta" +
+ "databindexonloadendonloadstartonmessageerroronmousedownonmou" +
+ "seenteronmouseleaveonmousemoveonmouseoutputonmouseoveronmous" +
+ "eupromptonmousewheelonofflineononlineonpagehidesclassearch2o" +
+ "npageshowbronpastepublicontenteditableonpausemaponplayingonp" +
+ "opstateonprogresspellcheckedonratechangeonrejectionhandledon" +
+ "resetonresizesrcdocodeferonscrollonsecuritypolicyviolationau" +
+ "xclickonseekedonseekingonselectedonshowidthgrouposteronsorta" +
+ "bleonstalledonstorageonsubmitemscopedonsuspendontoggleonunha" +
+ "ndledrejectionbeforeprintonunloadonvolumechangeonwaitingonwh" +
+ "eeloptimumanifestrongoptionbeforeunloaddressrclangsrcsetstyl" +
+ "esummarysupsvgsystemplateworkertypewrap"
diff --git a/vendor/golang.org/x/net/html/charset/charset.go b/vendor/golang.org/x/net/html/charset/charset.go
new file mode 100644
index 00000000..13bed159
--- /dev/null
+++ b/vendor/golang.org/x/net/html/charset/charset.go
@@ -0,0 +1,257 @@
+// Copyright 2013 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 charset provides common text encodings for HTML documents.
+//
+// The mapping from encoding labels to encodings is defined at
+// https://encoding.spec.whatwg.org/.
+package charset // import "golang.org/x/net/html/charset"
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "mime"
+ "strings"
+ "unicode/utf8"
+
+ "golang.org/x/net/html"
+ "golang.org/x/text/encoding"
+ "golang.org/x/text/encoding/charmap"
+ "golang.org/x/text/encoding/htmlindex"
+ "golang.org/x/text/transform"
+)
+
+// Lookup returns the encoding with the specified label, and its canonical
+// name. It returns nil and the empty string if label is not one of the
+// standard encodings for HTML. Matching is case-insensitive and ignores
+// leading and trailing whitespace. Encoders will use HTML escape sequences for
+// runes that are not supported by the character set.
+func Lookup(label string) (e encoding.Encoding, name string) {
+ e, err := htmlindex.Get(label)
+ if err != nil {
+ return nil, ""
+ }
+ name, _ = htmlindex.Name(e)
+ return &htmlEncoding{e}, name
+}
+
+type htmlEncoding struct{ encoding.Encoding }
+
+func (h *htmlEncoding) NewEncoder() *encoding.Encoder {
+ // HTML requires a non-terminating legacy encoder. We use HTML escapes to
+ // substitute unsupported code points.
+ return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder())
+}
+
+// DetermineEncoding determines the encoding of an HTML document by examining
+// up to the first 1024 bytes of content and the declared Content-Type.
+//
+// See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding
+func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) {
+ if len(content) > 1024 {
+ content = content[:1024]
+ }
+
+ for _, b := range boms {
+ if bytes.HasPrefix(content, b.bom) {
+ e, name = Lookup(b.enc)
+ return e, name, true
+ }
+ }
+
+ if _, params, err := mime.ParseMediaType(contentType); err == nil {
+ if cs, ok := params["charset"]; ok {
+ if e, name = Lookup(cs); e != nil {
+ return e, name, true
+ }
+ }
+ }
+
+ if len(content) > 0 {
+ e, name = prescan(content)
+ if e != nil {
+ return e, name, false
+ }
+ }
+
+ // Try to detect UTF-8.
+ // First eliminate any partial rune at the end.
+ for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- {
+ b := content[i]
+ if b < 0x80 {
+ break
+ }
+ if utf8.RuneStart(b) {
+ content = content[:i]
+ break
+ }
+ }
+ hasHighBit := false
+ for _, c := range content {
+ if c >= 0x80 {
+ hasHighBit = true
+ break
+ }
+ }
+ if hasHighBit && utf8.Valid(content) {
+ return encoding.Nop, "utf-8", false
+ }
+
+ // TODO: change default depending on user's locale?
+ return charmap.Windows1252, "windows-1252", false
+}
+
+// NewReader returns an io.Reader that converts the content of r to UTF-8.
+// It calls DetermineEncoding to find out what r's encoding is.
+func NewReader(r io.Reader, contentType string) (io.Reader, error) {
+ preview := make([]byte, 1024)
+ n, err := io.ReadFull(r, preview)
+ switch {
+ case err == io.ErrUnexpectedEOF:
+ preview = preview[:n]
+ r = bytes.NewReader(preview)
+ case err != nil:
+ return nil, err
+ default:
+ r = io.MultiReader(bytes.NewReader(preview), r)
+ }
+
+ if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop {
+ r = transform.NewReader(r, e.NewDecoder())
+ }
+ return r, nil
+}
+
+// NewReaderLabel returns a reader that converts from the specified charset to
+// UTF-8. It uses Lookup to find the encoding that corresponds to label, and
+// returns an error if Lookup returns nil. It is suitable for use as
+// encoding/xml.Decoder's CharsetReader function.
+func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
+ e, _ := Lookup(label)
+ if e == nil {
+ return nil, fmt.Errorf("unsupported charset: %q", label)
+ }
+ return transform.NewReader(input, e.NewDecoder()), nil
+}
+
+func prescan(content []byte) (e encoding.Encoding, name string) {
+ z := html.NewTokenizer(bytes.NewReader(content))
+ for {
+ switch z.Next() {
+ case html.ErrorToken:
+ return nil, ""
+
+ case html.StartTagToken, html.SelfClosingTagToken:
+ tagName, hasAttr := z.TagName()
+ if !bytes.Equal(tagName, []byte("meta")) {
+ continue
+ }
+ attrList := make(map[string]bool)
+ gotPragma := false
+
+ const (
+ dontKnow = iota
+ doNeedPragma
+ doNotNeedPragma
+ )
+ needPragma := dontKnow
+
+ name = ""
+ e = nil
+ for hasAttr {
+ var key, val []byte
+ key, val, hasAttr = z.TagAttr()
+ ks := string(key)
+ if attrList[ks] {
+ continue
+ }
+ attrList[ks] = true
+ for i, c := range val {
+ if 'A' <= c && c <= 'Z' {
+ val[i] = c + 0x20
+ }
+ }
+
+ switch ks {
+ case "http-equiv":
+ if bytes.Equal(val, []byte("content-type")) {
+ gotPragma = true
+ }
+
+ case "content":
+ if e == nil {
+ name = fromMetaElement(string(val))
+ if name != "" {
+ e, name = Lookup(name)
+ if e != nil {
+ needPragma = doNeedPragma
+ }
+ }
+ }
+
+ case "charset":
+ e, name = Lookup(string(val))
+ needPragma = doNotNeedPragma
+ }
+ }
+
+ if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma {
+ continue
+ }
+
+ if strings.HasPrefix(name, "utf-16") {
+ name = "utf-8"
+ e = encoding.Nop
+ }
+
+ if e != nil {
+ return e, name
+ }
+ }
+ }
+}
+
+func fromMetaElement(s string) string {
+ for s != "" {
+ csLoc := strings.Index(s, "charset")
+ if csLoc == -1 {
+ return ""
+ }
+ s = s[csLoc+len("charset"):]
+ s = strings.TrimLeft(s, " \t\n\f\r")
+ if !strings.HasPrefix(s, "=") {
+ continue
+ }
+ s = s[1:]
+ s = strings.TrimLeft(s, " \t\n\f\r")
+ if s == "" {
+ return ""
+ }
+ if q := s[0]; q == '"' || q == '\'' {
+ s = s[1:]
+ closeQuote := strings.IndexRune(s, rune(q))
+ if closeQuote == -1 {
+ return ""
+ }
+ return s[:closeQuote]
+ }
+
+ end := strings.IndexAny(s, "; \t\n\f\r")
+ if end == -1 {
+ end = len(s)
+ }
+ return s[:end]
+ }
+ return ""
+}
+
+var boms = []struct {
+ bom []byte
+ enc string
+}{
+ {[]byte{0xfe, 0xff}, "utf-16be"},
+ {[]byte{0xff, 0xfe}, "utf-16le"},
+ {[]byte{0xef, 0xbb, 0xbf}, "utf-8"},
+}
diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go
new file mode 100644
index 00000000..ff7acf2d
--- /dev/null
+++ b/vendor/golang.org/x/net/html/const.go
@@ -0,0 +1,111 @@
+// 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 html
+
+// Section 12.2.4.2 of the HTML5 specification says "The following elements
+// have varying levels of special parsing rules".
+// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
+var isSpecialElementMap = map[string]bool{
+ "address": true,
+ "applet": true,
+ "area": true,
+ "article": true,
+ "aside": true,
+ "base": true,
+ "basefont": true,
+ "bgsound": true,
+ "blockquote": true,
+ "body": true,
+ "br": true,
+ "button": true,
+ "caption": true,
+ "center": true,
+ "col": true,
+ "colgroup": true,
+ "dd": true,
+ "details": true,
+ "dir": true,
+ "div": true,
+ "dl": true,
+ "dt": true,
+ "embed": true,
+ "fieldset": true,
+ "figcaption": true,
+ "figure": true,
+ "footer": true,
+ "form": true,
+ "frame": true,
+ "frameset": true,
+ "h1": true,
+ "h2": true,
+ "h3": true,
+ "h4": true,
+ "h5": true,
+ "h6": true,
+ "head": true,
+ "header": true,
+ "hgroup": true,
+ "hr": true,
+ "html": true,
+ "iframe": true,
+ "img": true,
+ "input": true,
+ "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
+ "li": true,
+ "link": true,
+ "listing": true,
+ "main": true,
+ "marquee": true,
+ "menu": true,
+ "meta": true,
+ "nav": true,
+ "noembed": true,
+ "noframes": true,
+ "noscript": true,
+ "object": true,
+ "ol": true,
+ "p": true,
+ "param": true,
+ "plaintext": true,
+ "pre": true,
+ "script": true,
+ "section": true,
+ "select": true,
+ "source": true,
+ "style": true,
+ "summary": true,
+ "table": true,
+ "tbody": true,
+ "td": true,
+ "template": true,
+ "textarea": true,
+ "tfoot": true,
+ "th": true,
+ "thead": true,
+ "title": true,
+ "tr": true,
+ "track": true,
+ "ul": true,
+ "wbr": true,
+ "xmp": true,
+}
+
+func isSpecialElement(element *Node) bool {
+ switch element.Namespace {
+ case "", "html":
+ return isSpecialElementMap[element.Data]
+ case "math":
+ switch element.Data {
+ case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
+ return true
+ }
+ case "svg":
+ switch element.Data {
+ case "foreignObject", "desc", "title":
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/golang.org/x/net/html/doc.go b/vendor/golang.org/x/net/html/doc.go
new file mode 100644
index 00000000..885c4c59
--- /dev/null
+++ b/vendor/golang.org/x/net/html/doc.go
@@ -0,0 +1,122 @@
+// 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 html implements an HTML5-compliant tokenizer and parser.
+
+Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
+caller's responsibility to ensure that r provides UTF-8 encoded HTML.
+
+ z := html.NewTokenizer(r)
+
+Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
+which parses the next token and returns its type, or an error:
+
+ for {
+ tt := z.Next()
+ if tt == html.ErrorToken {
+ // ...
+ return ...
+ }
+ // Process the current token.
+ }
+
+There are two APIs for retrieving the current token. The high-level API is to
+call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
+allow optionally calling Raw after Next but before Token, Text, TagName, or
+TagAttr. In EBNF notation, the valid call sequence per token is:
+
+ Next {Raw} [ Token | Text | TagName {TagAttr} ]
+
+Token returns an independent data structure that completely describes a token.
+Entities (such as "<") are unescaped, tag names and attribute keys are
+lower-cased, and attributes are collected into a []Attribute. For example:
+
+ for {
+ if z.Next() == html.ErrorToken {
+ // Returning io.EOF indicates success.
+ return z.Err()
+ }
+ emitToken(z.Token())
+ }
+
+The low-level API performs fewer allocations and copies, but the contents of
+the []byte values returned by Text, TagName and TagAttr may change on the next
+call to Next. For example, to extract an HTML page's anchor text:
+
+ depth := 0
+ for {
+ tt := z.Next()
+ switch tt {
+ case html.ErrorToken:
+ return z.Err()
+ case html.TextToken:
+ if depth > 0 {
+ // emitBytes should copy the []byte it receives,
+ // if it doesn't process it immediately.
+ emitBytes(z.Text())
+ }
+ case html.StartTagToken, html.EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == html.StartTagToken {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+
+Parsing is done by calling Parse with an io.Reader, which returns the root of
+the parse tree (the document element) as a *Node. It is the caller's
+responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
+example, to process each anchor node in depth-first order:
+
+ doc, err := html.Parse(r)
+ if err != nil {
+ // ...
+ }
+ for n := range doc.Descendants() {
+ if n.Type == html.ElementNode && n.Data == "a" {
+ // Do something with n...
+ }
+ }
+
+The relevant specifications include:
+https://html.spec.whatwg.org/multipage/syntax.html and
+https://html.spec.whatwg.org/multipage/syntax.html#tokenization
+
+# Security Considerations
+
+Care should be taken when parsing and interpreting HTML, whether full documents
+or fragments, within the framework of the HTML specification, especially with
+regard to untrusted inputs.
+
+This package provides both a tokenizer and a parser, which implement the
+tokenization, and tokenization and tree construction stages of the WHATWG HTML
+parsing specification respectively. While the tokenizer parses and normalizes
+individual HTML tokens, only the parser constructs the DOM tree from the
+tokenized HTML, as described in the tree construction stage of the
+specification, dynamically modifying or extending the document's DOM tree.
+
+If your use case requires semantically well-formed HTML documents, as defined by
+the WHATWG specification, the parser should be used rather than the tokenizer.
+
+In security contexts, if trust decisions are being made using the tokenized or
+parsed content, the input must be re-serialized (for instance by using Render or
+Token.String) in order for those trust decisions to hold, as the process of
+tokenization or parsing may alter the content.
+*/
+package html // import "golang.org/x/net/html"
+
+// The tokenization algorithm implemented by this package is not a line-by-line
+// transliteration of the relatively verbose state-machine in the WHATWG
+// specification. A more direct approach is used instead, where the program
+// counter implies the state, such as whether it is tokenizing a tag or a text
+// node. Specification compliance is verified by checking expected and actual
+// outputs over a test suite rather than aiming for algorithmic fidelity.
+
+// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
+// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/vendor/golang.org/x/net/html/doctype.go b/vendor/golang.org/x/net/html/doctype.go
new file mode 100644
index 00000000..bca3ae9a
--- /dev/null
+++ b/vendor/golang.org/x/net/html/doctype.go
@@ -0,0 +1,156 @@
+// 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 html
+
+import (
+ "strings"
+)
+
+// parseDoctype parses the data from a DoctypeToken into a name,
+// public identifier, and system identifier. It returns a Node whose Type
+// is DoctypeNode, whose Data is the name, and which has attributes
+// named "system" and "public" for the two identifiers if they were present.
+// quirks is whether the document should be parsed in "quirks mode".
+func parseDoctype(s string) (n *Node, quirks bool) {
+ n = &Node{Type: DoctypeNode}
+
+ // Find the name.
+ space := strings.IndexAny(s, whitespace)
+ if space == -1 {
+ space = len(s)
+ }
+ n.Data = s[:space]
+ // The comparison to "html" is case-sensitive.
+ if n.Data != "html" {
+ quirks = true
+ }
+ n.Data = strings.ToLower(n.Data)
+ s = strings.TrimLeft(s[space:], whitespace)
+
+ if len(s) < 6 {
+ // It can't start with "PUBLIC" or "SYSTEM".
+ // Ignore the rest of the string.
+ return n, quirks || s != ""
+ }
+
+ key := strings.ToLower(s[:6])
+ s = s[6:]
+ for key == "public" || key == "system" {
+ s = strings.TrimLeft(s, whitespace)
+ if s == "" {
+ break
+ }
+ quote := s[0]
+ if quote != '"' && quote != '\'' {
+ break
+ }
+ s = s[1:]
+ q := strings.IndexRune(s, rune(quote))
+ var id string
+ if q == -1 {
+ id = s
+ s = ""
+ } else {
+ id = s[:q]
+ s = s[q+1:]
+ }
+ n.Attr = append(n.Attr, Attribute{Key: key, Val: id})
+ if key == "public" {
+ key = "system"
+ } else {
+ key = ""
+ }
+ }
+
+ if key != "" || s != "" {
+ quirks = true
+ } else if len(n.Attr) > 0 {
+ if n.Attr[0].Key == "public" {
+ public := strings.ToLower(n.Attr[0].Val)
+ switch public {
+ case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html":
+ quirks = true
+ default:
+ for _, q := range quirkyIDs {
+ if strings.HasPrefix(public, q) {
+ quirks = true
+ break
+ }
+ }
+ }
+ // The following two public IDs only cause quirks mode if there is no system ID.
+ if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") ||
+ strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) {
+ quirks = true
+ }
+ }
+ if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
+ strings.EqualFold(lastAttr.Val, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
+ quirks = true
+ }
+ }
+
+ return n, quirks
+}
+
+// quirkyIDs is a list of public doctype identifiers that cause a document
+// to be interpreted in quirks mode. The identifiers should be in lower case.
+var quirkyIDs = []string{
+ "+//silmaril//dtd html pro v0r11 19970101//",
+ "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
+ "-//as//dtd html 3.0 aswedit + extensions//",
+ "-//ietf//dtd html 2.0 level 1//",
+ "-//ietf//dtd html 2.0 level 2//",
+ "-//ietf//dtd html 2.0 strict level 1//",
+ "-//ietf//dtd html 2.0 strict level 2//",
+ "-//ietf//dtd html 2.0 strict//",
+ "-//ietf//dtd html 2.0//",
+ "-//ietf//dtd html 2.1e//",
+ "-//ietf//dtd html 3.0//",
+ "-//ietf//dtd html 3.2 final//",
+ "-//ietf//dtd html 3.2//",
+ "-//ietf//dtd html 3//",
+ "-//ietf//dtd html level 0//",
+ "-//ietf//dtd html level 1//",
+ "-//ietf//dtd html level 2//",
+ "-//ietf//dtd html level 3//",
+ "-//ietf//dtd html strict level 0//",
+ "-//ietf//dtd html strict level 1//",
+ "-//ietf//dtd html strict level 2//",
+ "-//ietf//dtd html strict level 3//",
+ "-//ietf//dtd html strict//",
+ "-//ietf//dtd html//",
+ "-//metrius//dtd metrius presentational//",
+ "-//microsoft//dtd internet explorer 2.0 html strict//",
+ "-//microsoft//dtd internet explorer 2.0 html//",
+ "-//microsoft//dtd internet explorer 2.0 tables//",
+ "-//microsoft//dtd internet explorer 3.0 html strict//",
+ "-//microsoft//dtd internet explorer 3.0 html//",
+ "-//microsoft//dtd internet explorer 3.0 tables//",
+ "-//netscape comm. corp.//dtd html//",
+ "-//netscape comm. corp.//dtd strict html//",
+ "-//o'reilly and associates//dtd html 2.0//",
+ "-//o'reilly and associates//dtd html extended 1.0//",
+ "-//o'reilly and associates//dtd html extended relaxed 1.0//",
+ "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
+ "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
+ "-//spyglass//dtd html 2.0 extended//",
+ "-//sq//dtd html 2.0 hotmetal + extensions//",
+ "-//sun microsystems corp.//dtd hotjava html//",
+ "-//sun microsystems corp.//dtd hotjava strict html//",
+ "-//w3c//dtd html 3 1995-03-24//",
+ "-//w3c//dtd html 3.2 draft//",
+ "-//w3c//dtd html 3.2 final//",
+ "-//w3c//dtd html 3.2//",
+ "-//w3c//dtd html 3.2s draft//",
+ "-//w3c//dtd html 4.0 frameset//",
+ "-//w3c//dtd html 4.0 transitional//",
+ "-//w3c//dtd html experimental 19960712//",
+ "-//w3c//dtd html experimental 970421//",
+ "-//w3c//dtd w3 html//",
+ "-//w3o//dtd w3 html 3.0//",
+ "-//webtechs//dtd mozilla html 2.0//",
+ "-//webtechs//dtd mozilla html//",
+}
diff --git a/vendor/golang.org/x/net/html/entity.go b/vendor/golang.org/x/net/html/entity.go
new file mode 100644
index 00000000..b628880a
--- /dev/null
+++ b/vendor/golang.org/x/net/html/entity.go
@@ -0,0 +1,2253 @@
+// 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 html
+
+// All entities that do not end with ';' are 6 or fewer bytes long.
+const longestEntityWithoutSemicolon = 6
+
+// entity is a map from HTML entity names to their values. The semicolon matters:
+// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references
+// lists both "amp" and "amp;" as two separate entries.
+//
+// Note that the HTML5 list is larger than the HTML4 list at
+// http://www.w3.org/TR/html4/sgml/entities.html
+var entity = map[string]rune{
+ "AElig;": '\U000000C6',
+ "AMP;": '\U00000026',
+ "Aacute;": '\U000000C1',
+ "Abreve;": '\U00000102',
+ "Acirc;": '\U000000C2',
+ "Acy;": '\U00000410',
+ "Afr;": '\U0001D504',
+ "Agrave;": '\U000000C0',
+ "Alpha;": '\U00000391',
+ "Amacr;": '\U00000100',
+ "And;": '\U00002A53',
+ "Aogon;": '\U00000104',
+ "Aopf;": '\U0001D538',
+ "ApplyFunction;": '\U00002061',
+ "Aring;": '\U000000C5',
+ "Ascr;": '\U0001D49C',
+ "Assign;": '\U00002254',
+ "Atilde;": '\U000000C3',
+ "Auml;": '\U000000C4',
+ "Backslash;": '\U00002216',
+ "Barv;": '\U00002AE7',
+ "Barwed;": '\U00002306',
+ "Bcy;": '\U00000411',
+ "Because;": '\U00002235',
+ "Bernoullis;": '\U0000212C',
+ "Beta;": '\U00000392',
+ "Bfr;": '\U0001D505',
+ "Bopf;": '\U0001D539',
+ "Breve;": '\U000002D8',
+ "Bscr;": '\U0000212C',
+ "Bumpeq;": '\U0000224E',
+ "CHcy;": '\U00000427',
+ "COPY;": '\U000000A9',
+ "Cacute;": '\U00000106',
+ "Cap;": '\U000022D2',
+ "CapitalDifferentialD;": '\U00002145',
+ "Cayleys;": '\U0000212D',
+ "Ccaron;": '\U0000010C',
+ "Ccedil;": '\U000000C7',
+ "Ccirc;": '\U00000108',
+ "Cconint;": '\U00002230',
+ "Cdot;": '\U0000010A',
+ "Cedilla;": '\U000000B8',
+ "CenterDot;": '\U000000B7',
+ "Cfr;": '\U0000212D',
+ "Chi;": '\U000003A7',
+ "CircleDot;": '\U00002299',
+ "CircleMinus;": '\U00002296',
+ "CirclePlus;": '\U00002295',
+ "CircleTimes;": '\U00002297',
+ "ClockwiseContourIntegral;": '\U00002232',
+ "CloseCurlyDoubleQuote;": '\U0000201D',
+ "CloseCurlyQuote;": '\U00002019',
+ "Colon;": '\U00002237',
+ "Colone;": '\U00002A74',
+ "Congruent;": '\U00002261',
+ "Conint;": '\U0000222F',
+ "ContourIntegral;": '\U0000222E',
+ "Copf;": '\U00002102',
+ "Coproduct;": '\U00002210',
+ "CounterClockwiseContourIntegral;": '\U00002233',
+ "Cross;": '\U00002A2F',
+ "Cscr;": '\U0001D49E',
+ "Cup;": '\U000022D3',
+ "CupCap;": '\U0000224D',
+ "DD;": '\U00002145',
+ "DDotrahd;": '\U00002911',
+ "DJcy;": '\U00000402',
+ "DScy;": '\U00000405',
+ "DZcy;": '\U0000040F',
+ "Dagger;": '\U00002021',
+ "Darr;": '\U000021A1',
+ "Dashv;": '\U00002AE4',
+ "Dcaron;": '\U0000010E',
+ "Dcy;": '\U00000414',
+ "Del;": '\U00002207',
+ "Delta;": '\U00000394',
+ "Dfr;": '\U0001D507',
+ "DiacriticalAcute;": '\U000000B4',
+ "DiacriticalDot;": '\U000002D9',
+ "DiacriticalDoubleAcute;": '\U000002DD',
+ "DiacriticalGrave;": '\U00000060',
+ "DiacriticalTilde;": '\U000002DC',
+ "Diamond;": '\U000022C4',
+ "DifferentialD;": '\U00002146',
+ "Dopf;": '\U0001D53B',
+ "Dot;": '\U000000A8',
+ "DotDot;": '\U000020DC',
+ "DotEqual;": '\U00002250',
+ "DoubleContourIntegral;": '\U0000222F',
+ "DoubleDot;": '\U000000A8',
+ "DoubleDownArrow;": '\U000021D3',
+ "DoubleLeftArrow;": '\U000021D0',
+ "DoubleLeftRightArrow;": '\U000021D4',
+ "DoubleLeftTee;": '\U00002AE4',
+ "DoubleLongLeftArrow;": '\U000027F8',
+ "DoubleLongLeftRightArrow;": '\U000027FA',
+ "DoubleLongRightArrow;": '\U000027F9',
+ "DoubleRightArrow;": '\U000021D2',
+ "DoubleRightTee;": '\U000022A8',
+ "DoubleUpArrow;": '\U000021D1',
+ "DoubleUpDownArrow;": '\U000021D5',
+ "DoubleVerticalBar;": '\U00002225',
+ "DownArrow;": '\U00002193',
+ "DownArrowBar;": '\U00002913',
+ "DownArrowUpArrow;": '\U000021F5',
+ "DownBreve;": '\U00000311',
+ "DownLeftRightVector;": '\U00002950',
+ "DownLeftTeeVector;": '\U0000295E',
+ "DownLeftVector;": '\U000021BD',
+ "DownLeftVectorBar;": '\U00002956',
+ "DownRightTeeVector;": '\U0000295F',
+ "DownRightVector;": '\U000021C1',
+ "DownRightVectorBar;": '\U00002957',
+ "DownTee;": '\U000022A4',
+ "DownTeeArrow;": '\U000021A7',
+ "Downarrow;": '\U000021D3',
+ "Dscr;": '\U0001D49F',
+ "Dstrok;": '\U00000110',
+ "ENG;": '\U0000014A',
+ "ETH;": '\U000000D0',
+ "Eacute;": '\U000000C9',
+ "Ecaron;": '\U0000011A',
+ "Ecirc;": '\U000000CA',
+ "Ecy;": '\U0000042D',
+ "Edot;": '\U00000116',
+ "Efr;": '\U0001D508',
+ "Egrave;": '\U000000C8',
+ "Element;": '\U00002208',
+ "Emacr;": '\U00000112',
+ "EmptySmallSquare;": '\U000025FB',
+ "EmptyVerySmallSquare;": '\U000025AB',
+ "Eogon;": '\U00000118',
+ "Eopf;": '\U0001D53C',
+ "Epsilon;": '\U00000395',
+ "Equal;": '\U00002A75',
+ "EqualTilde;": '\U00002242',
+ "Equilibrium;": '\U000021CC',
+ "Escr;": '\U00002130',
+ "Esim;": '\U00002A73',
+ "Eta;": '\U00000397',
+ "Euml;": '\U000000CB',
+ "Exists;": '\U00002203',
+ "ExponentialE;": '\U00002147',
+ "Fcy;": '\U00000424',
+ "Ffr;": '\U0001D509',
+ "FilledSmallSquare;": '\U000025FC',
+ "FilledVerySmallSquare;": '\U000025AA',
+ "Fopf;": '\U0001D53D',
+ "ForAll;": '\U00002200',
+ "Fouriertrf;": '\U00002131',
+ "Fscr;": '\U00002131',
+ "GJcy;": '\U00000403',
+ "GT;": '\U0000003E',
+ "Gamma;": '\U00000393',
+ "Gammad;": '\U000003DC',
+ "Gbreve;": '\U0000011E',
+ "Gcedil;": '\U00000122',
+ "Gcirc;": '\U0000011C',
+ "Gcy;": '\U00000413',
+ "Gdot;": '\U00000120',
+ "Gfr;": '\U0001D50A',
+ "Gg;": '\U000022D9',
+ "Gopf;": '\U0001D53E',
+ "GreaterEqual;": '\U00002265',
+ "GreaterEqualLess;": '\U000022DB',
+ "GreaterFullEqual;": '\U00002267',
+ "GreaterGreater;": '\U00002AA2',
+ "GreaterLess;": '\U00002277',
+ "GreaterSlantEqual;": '\U00002A7E',
+ "GreaterTilde;": '\U00002273',
+ "Gscr;": '\U0001D4A2',
+ "Gt;": '\U0000226B',
+ "HARDcy;": '\U0000042A',
+ "Hacek;": '\U000002C7',
+ "Hat;": '\U0000005E',
+ "Hcirc;": '\U00000124',
+ "Hfr;": '\U0000210C',
+ "HilbertSpace;": '\U0000210B',
+ "Hopf;": '\U0000210D',
+ "HorizontalLine;": '\U00002500',
+ "Hscr;": '\U0000210B',
+ "Hstrok;": '\U00000126',
+ "HumpDownHump;": '\U0000224E',
+ "HumpEqual;": '\U0000224F',
+ "IEcy;": '\U00000415',
+ "IJlig;": '\U00000132',
+ "IOcy;": '\U00000401',
+ "Iacute;": '\U000000CD',
+ "Icirc;": '\U000000CE',
+ "Icy;": '\U00000418',
+ "Idot;": '\U00000130',
+ "Ifr;": '\U00002111',
+ "Igrave;": '\U000000CC',
+ "Im;": '\U00002111',
+ "Imacr;": '\U0000012A',
+ "ImaginaryI;": '\U00002148',
+ "Implies;": '\U000021D2',
+ "Int;": '\U0000222C',
+ "Integral;": '\U0000222B',
+ "Intersection;": '\U000022C2',
+ "InvisibleComma;": '\U00002063',
+ "InvisibleTimes;": '\U00002062',
+ "Iogon;": '\U0000012E',
+ "Iopf;": '\U0001D540',
+ "Iota;": '\U00000399',
+ "Iscr;": '\U00002110',
+ "Itilde;": '\U00000128',
+ "Iukcy;": '\U00000406',
+ "Iuml;": '\U000000CF',
+ "Jcirc;": '\U00000134',
+ "Jcy;": '\U00000419',
+ "Jfr;": '\U0001D50D',
+ "Jopf;": '\U0001D541',
+ "Jscr;": '\U0001D4A5',
+ "Jsercy;": '\U00000408',
+ "Jukcy;": '\U00000404',
+ "KHcy;": '\U00000425',
+ "KJcy;": '\U0000040C',
+ "Kappa;": '\U0000039A',
+ "Kcedil;": '\U00000136',
+ "Kcy;": '\U0000041A',
+ "Kfr;": '\U0001D50E',
+ "Kopf;": '\U0001D542',
+ "Kscr;": '\U0001D4A6',
+ "LJcy;": '\U00000409',
+ "LT;": '\U0000003C',
+ "Lacute;": '\U00000139',
+ "Lambda;": '\U0000039B',
+ "Lang;": '\U000027EA',
+ "Laplacetrf;": '\U00002112',
+ "Larr;": '\U0000219E',
+ "Lcaron;": '\U0000013D',
+ "Lcedil;": '\U0000013B',
+ "Lcy;": '\U0000041B',
+ "LeftAngleBracket;": '\U000027E8',
+ "LeftArrow;": '\U00002190',
+ "LeftArrowBar;": '\U000021E4',
+ "LeftArrowRightArrow;": '\U000021C6',
+ "LeftCeiling;": '\U00002308',
+ "LeftDoubleBracket;": '\U000027E6',
+ "LeftDownTeeVector;": '\U00002961',
+ "LeftDownVector;": '\U000021C3',
+ "LeftDownVectorBar;": '\U00002959',
+ "LeftFloor;": '\U0000230A',
+ "LeftRightArrow;": '\U00002194',
+ "LeftRightVector;": '\U0000294E',
+ "LeftTee;": '\U000022A3',
+ "LeftTeeArrow;": '\U000021A4',
+ "LeftTeeVector;": '\U0000295A',
+ "LeftTriangle;": '\U000022B2',
+ "LeftTriangleBar;": '\U000029CF',
+ "LeftTriangleEqual;": '\U000022B4',
+ "LeftUpDownVector;": '\U00002951',
+ "LeftUpTeeVector;": '\U00002960',
+ "LeftUpVector;": '\U000021BF',
+ "LeftUpVectorBar;": '\U00002958',
+ "LeftVector;": '\U000021BC',
+ "LeftVectorBar;": '\U00002952',
+ "Leftarrow;": '\U000021D0',
+ "Leftrightarrow;": '\U000021D4',
+ "LessEqualGreater;": '\U000022DA',
+ "LessFullEqual;": '\U00002266',
+ "LessGreater;": '\U00002276',
+ "LessLess;": '\U00002AA1',
+ "LessSlantEqual;": '\U00002A7D',
+ "LessTilde;": '\U00002272',
+ "Lfr;": '\U0001D50F',
+ "Ll;": '\U000022D8',
+ "Lleftarrow;": '\U000021DA',
+ "Lmidot;": '\U0000013F',
+ "LongLeftArrow;": '\U000027F5',
+ "LongLeftRightArrow;": '\U000027F7',
+ "LongRightArrow;": '\U000027F6',
+ "Longleftarrow;": '\U000027F8',
+ "Longleftrightarrow;": '\U000027FA',
+ "Longrightarrow;": '\U000027F9',
+ "Lopf;": '\U0001D543',
+ "LowerLeftArrow;": '\U00002199',
+ "LowerRightArrow;": '\U00002198',
+ "Lscr;": '\U00002112',
+ "Lsh;": '\U000021B0',
+ "Lstrok;": '\U00000141',
+ "Lt;": '\U0000226A',
+ "Map;": '\U00002905',
+ "Mcy;": '\U0000041C',
+ "MediumSpace;": '\U0000205F',
+ "Mellintrf;": '\U00002133',
+ "Mfr;": '\U0001D510',
+ "MinusPlus;": '\U00002213',
+ "Mopf;": '\U0001D544',
+ "Mscr;": '\U00002133',
+ "Mu;": '\U0000039C',
+ "NJcy;": '\U0000040A',
+ "Nacute;": '\U00000143',
+ "Ncaron;": '\U00000147',
+ "Ncedil;": '\U00000145',
+ "Ncy;": '\U0000041D',
+ "NegativeMediumSpace;": '\U0000200B',
+ "NegativeThickSpace;": '\U0000200B',
+ "NegativeThinSpace;": '\U0000200B',
+ "NegativeVeryThinSpace;": '\U0000200B',
+ "NestedGreaterGreater;": '\U0000226B',
+ "NestedLessLess;": '\U0000226A',
+ "NewLine;": '\U0000000A',
+ "Nfr;": '\U0001D511',
+ "NoBreak;": '\U00002060',
+ "NonBreakingSpace;": '\U000000A0',
+ "Nopf;": '\U00002115',
+ "Not;": '\U00002AEC',
+ "NotCongruent;": '\U00002262',
+ "NotCupCap;": '\U0000226D',
+ "NotDoubleVerticalBar;": '\U00002226',
+ "NotElement;": '\U00002209',
+ "NotEqual;": '\U00002260',
+ "NotExists;": '\U00002204',
+ "NotGreater;": '\U0000226F',
+ "NotGreaterEqual;": '\U00002271',
+ "NotGreaterLess;": '\U00002279',
+ "NotGreaterTilde;": '\U00002275',
+ "NotLeftTriangle;": '\U000022EA',
+ "NotLeftTriangleEqual;": '\U000022EC',
+ "NotLess;": '\U0000226E',
+ "NotLessEqual;": '\U00002270',
+ "NotLessGreater;": '\U00002278',
+ "NotLessTilde;": '\U00002274',
+ "NotPrecedes;": '\U00002280',
+ "NotPrecedesSlantEqual;": '\U000022E0',
+ "NotReverseElement;": '\U0000220C',
+ "NotRightTriangle;": '\U000022EB',
+ "NotRightTriangleEqual;": '\U000022ED',
+ "NotSquareSubsetEqual;": '\U000022E2',
+ "NotSquareSupersetEqual;": '\U000022E3',
+ "NotSubsetEqual;": '\U00002288',
+ "NotSucceeds;": '\U00002281',
+ "NotSucceedsSlantEqual;": '\U000022E1',
+ "NotSupersetEqual;": '\U00002289',
+ "NotTilde;": '\U00002241',
+ "NotTildeEqual;": '\U00002244',
+ "NotTildeFullEqual;": '\U00002247',
+ "NotTildeTilde;": '\U00002249',
+ "NotVerticalBar;": '\U00002224',
+ "Nscr;": '\U0001D4A9',
+ "Ntilde;": '\U000000D1',
+ "Nu;": '\U0000039D',
+ "OElig;": '\U00000152',
+ "Oacute;": '\U000000D3',
+ "Ocirc;": '\U000000D4',
+ "Ocy;": '\U0000041E',
+ "Odblac;": '\U00000150',
+ "Ofr;": '\U0001D512',
+ "Ograve;": '\U000000D2',
+ "Omacr;": '\U0000014C',
+ "Omega;": '\U000003A9',
+ "Omicron;": '\U0000039F',
+ "Oopf;": '\U0001D546',
+ "OpenCurlyDoubleQuote;": '\U0000201C',
+ "OpenCurlyQuote;": '\U00002018',
+ "Or;": '\U00002A54',
+ "Oscr;": '\U0001D4AA',
+ "Oslash;": '\U000000D8',
+ "Otilde;": '\U000000D5',
+ "Otimes;": '\U00002A37',
+ "Ouml;": '\U000000D6',
+ "OverBar;": '\U0000203E',
+ "OverBrace;": '\U000023DE',
+ "OverBracket;": '\U000023B4',
+ "OverParenthesis;": '\U000023DC',
+ "PartialD;": '\U00002202',
+ "Pcy;": '\U0000041F',
+ "Pfr;": '\U0001D513',
+ "Phi;": '\U000003A6',
+ "Pi;": '\U000003A0',
+ "PlusMinus;": '\U000000B1',
+ "Poincareplane;": '\U0000210C',
+ "Popf;": '\U00002119',
+ "Pr;": '\U00002ABB',
+ "Precedes;": '\U0000227A',
+ "PrecedesEqual;": '\U00002AAF',
+ "PrecedesSlantEqual;": '\U0000227C',
+ "PrecedesTilde;": '\U0000227E',
+ "Prime;": '\U00002033',
+ "Product;": '\U0000220F',
+ "Proportion;": '\U00002237',
+ "Proportional;": '\U0000221D',
+ "Pscr;": '\U0001D4AB',
+ "Psi;": '\U000003A8',
+ "QUOT;": '\U00000022',
+ "Qfr;": '\U0001D514',
+ "Qopf;": '\U0000211A',
+ "Qscr;": '\U0001D4AC',
+ "RBarr;": '\U00002910',
+ "REG;": '\U000000AE',
+ "Racute;": '\U00000154',
+ "Rang;": '\U000027EB',
+ "Rarr;": '\U000021A0',
+ "Rarrtl;": '\U00002916',
+ "Rcaron;": '\U00000158',
+ "Rcedil;": '\U00000156',
+ "Rcy;": '\U00000420',
+ "Re;": '\U0000211C',
+ "ReverseElement;": '\U0000220B',
+ "ReverseEquilibrium;": '\U000021CB',
+ "ReverseUpEquilibrium;": '\U0000296F',
+ "Rfr;": '\U0000211C',
+ "Rho;": '\U000003A1',
+ "RightAngleBracket;": '\U000027E9',
+ "RightArrow;": '\U00002192',
+ "RightArrowBar;": '\U000021E5',
+ "RightArrowLeftArrow;": '\U000021C4',
+ "RightCeiling;": '\U00002309',
+ "RightDoubleBracket;": '\U000027E7',
+ "RightDownTeeVector;": '\U0000295D',
+ "RightDownVector;": '\U000021C2',
+ "RightDownVectorBar;": '\U00002955',
+ "RightFloor;": '\U0000230B',
+ "RightTee;": '\U000022A2',
+ "RightTeeArrow;": '\U000021A6',
+ "RightTeeVector;": '\U0000295B',
+ "RightTriangle;": '\U000022B3',
+ "RightTriangleBar;": '\U000029D0',
+ "RightTriangleEqual;": '\U000022B5',
+ "RightUpDownVector;": '\U0000294F',
+ "RightUpTeeVector;": '\U0000295C',
+ "RightUpVector;": '\U000021BE',
+ "RightUpVectorBar;": '\U00002954',
+ "RightVector;": '\U000021C0',
+ "RightVectorBar;": '\U00002953',
+ "Rightarrow;": '\U000021D2',
+ "Ropf;": '\U0000211D',
+ "RoundImplies;": '\U00002970',
+ "Rrightarrow;": '\U000021DB',
+ "Rscr;": '\U0000211B',
+ "Rsh;": '\U000021B1',
+ "RuleDelayed;": '\U000029F4',
+ "SHCHcy;": '\U00000429',
+ "SHcy;": '\U00000428',
+ "SOFTcy;": '\U0000042C',
+ "Sacute;": '\U0000015A',
+ "Sc;": '\U00002ABC',
+ "Scaron;": '\U00000160',
+ "Scedil;": '\U0000015E',
+ "Scirc;": '\U0000015C',
+ "Scy;": '\U00000421',
+ "Sfr;": '\U0001D516',
+ "ShortDownArrow;": '\U00002193',
+ "ShortLeftArrow;": '\U00002190',
+ "ShortRightArrow;": '\U00002192',
+ "ShortUpArrow;": '\U00002191',
+ "Sigma;": '\U000003A3',
+ "SmallCircle;": '\U00002218',
+ "Sopf;": '\U0001D54A',
+ "Sqrt;": '\U0000221A',
+ "Square;": '\U000025A1',
+ "SquareIntersection;": '\U00002293',
+ "SquareSubset;": '\U0000228F',
+ "SquareSubsetEqual;": '\U00002291',
+ "SquareSuperset;": '\U00002290',
+ "SquareSupersetEqual;": '\U00002292',
+ "SquareUnion;": '\U00002294',
+ "Sscr;": '\U0001D4AE',
+ "Star;": '\U000022C6',
+ "Sub;": '\U000022D0',
+ "Subset;": '\U000022D0',
+ "SubsetEqual;": '\U00002286',
+ "Succeeds;": '\U0000227B',
+ "SucceedsEqual;": '\U00002AB0',
+ "SucceedsSlantEqual;": '\U0000227D',
+ "SucceedsTilde;": '\U0000227F',
+ "SuchThat;": '\U0000220B',
+ "Sum;": '\U00002211',
+ "Sup;": '\U000022D1',
+ "Superset;": '\U00002283',
+ "SupersetEqual;": '\U00002287',
+ "Supset;": '\U000022D1',
+ "THORN;": '\U000000DE',
+ "TRADE;": '\U00002122',
+ "TSHcy;": '\U0000040B',
+ "TScy;": '\U00000426',
+ "Tab;": '\U00000009',
+ "Tau;": '\U000003A4',
+ "Tcaron;": '\U00000164',
+ "Tcedil;": '\U00000162',
+ "Tcy;": '\U00000422',
+ "Tfr;": '\U0001D517',
+ "Therefore;": '\U00002234',
+ "Theta;": '\U00000398',
+ "ThinSpace;": '\U00002009',
+ "Tilde;": '\U0000223C',
+ "TildeEqual;": '\U00002243',
+ "TildeFullEqual;": '\U00002245',
+ "TildeTilde;": '\U00002248',
+ "Topf;": '\U0001D54B',
+ "TripleDot;": '\U000020DB',
+ "Tscr;": '\U0001D4AF',
+ "Tstrok;": '\U00000166',
+ "Uacute;": '\U000000DA',
+ "Uarr;": '\U0000219F',
+ "Uarrocir;": '\U00002949',
+ "Ubrcy;": '\U0000040E',
+ "Ubreve;": '\U0000016C',
+ "Ucirc;": '\U000000DB',
+ "Ucy;": '\U00000423',
+ "Udblac;": '\U00000170',
+ "Ufr;": '\U0001D518',
+ "Ugrave;": '\U000000D9',
+ "Umacr;": '\U0000016A',
+ "UnderBar;": '\U0000005F',
+ "UnderBrace;": '\U000023DF',
+ "UnderBracket;": '\U000023B5',
+ "UnderParenthesis;": '\U000023DD',
+ "Union;": '\U000022C3',
+ "UnionPlus;": '\U0000228E',
+ "Uogon;": '\U00000172',
+ "Uopf;": '\U0001D54C',
+ "UpArrow;": '\U00002191',
+ "UpArrowBar;": '\U00002912',
+ "UpArrowDownArrow;": '\U000021C5',
+ "UpDownArrow;": '\U00002195',
+ "UpEquilibrium;": '\U0000296E',
+ "UpTee;": '\U000022A5',
+ "UpTeeArrow;": '\U000021A5',
+ "Uparrow;": '\U000021D1',
+ "Updownarrow;": '\U000021D5',
+ "UpperLeftArrow;": '\U00002196',
+ "UpperRightArrow;": '\U00002197',
+ "Upsi;": '\U000003D2',
+ "Upsilon;": '\U000003A5',
+ "Uring;": '\U0000016E',
+ "Uscr;": '\U0001D4B0',
+ "Utilde;": '\U00000168',
+ "Uuml;": '\U000000DC',
+ "VDash;": '\U000022AB',
+ "Vbar;": '\U00002AEB',
+ "Vcy;": '\U00000412',
+ "Vdash;": '\U000022A9',
+ "Vdashl;": '\U00002AE6',
+ "Vee;": '\U000022C1',
+ "Verbar;": '\U00002016',
+ "Vert;": '\U00002016',
+ "VerticalBar;": '\U00002223',
+ "VerticalLine;": '\U0000007C',
+ "VerticalSeparator;": '\U00002758',
+ "VerticalTilde;": '\U00002240',
+ "VeryThinSpace;": '\U0000200A',
+ "Vfr;": '\U0001D519',
+ "Vopf;": '\U0001D54D',
+ "Vscr;": '\U0001D4B1',
+ "Vvdash;": '\U000022AA',
+ "Wcirc;": '\U00000174',
+ "Wedge;": '\U000022C0',
+ "Wfr;": '\U0001D51A',
+ "Wopf;": '\U0001D54E',
+ "Wscr;": '\U0001D4B2',
+ "Xfr;": '\U0001D51B',
+ "Xi;": '\U0000039E',
+ "Xopf;": '\U0001D54F',
+ "Xscr;": '\U0001D4B3',
+ "YAcy;": '\U0000042F',
+ "YIcy;": '\U00000407',
+ "YUcy;": '\U0000042E',
+ "Yacute;": '\U000000DD',
+ "Ycirc;": '\U00000176',
+ "Ycy;": '\U0000042B',
+ "Yfr;": '\U0001D51C',
+ "Yopf;": '\U0001D550',
+ "Yscr;": '\U0001D4B4',
+ "Yuml;": '\U00000178',
+ "ZHcy;": '\U00000416',
+ "Zacute;": '\U00000179',
+ "Zcaron;": '\U0000017D',
+ "Zcy;": '\U00000417',
+ "Zdot;": '\U0000017B',
+ "ZeroWidthSpace;": '\U0000200B',
+ "Zeta;": '\U00000396',
+ "Zfr;": '\U00002128',
+ "Zopf;": '\U00002124',
+ "Zscr;": '\U0001D4B5',
+ "aacute;": '\U000000E1',
+ "abreve;": '\U00000103',
+ "ac;": '\U0000223E',
+ "acd;": '\U0000223F',
+ "acirc;": '\U000000E2',
+ "acute;": '\U000000B4',
+ "acy;": '\U00000430',
+ "aelig;": '\U000000E6',
+ "af;": '\U00002061',
+ "afr;": '\U0001D51E',
+ "agrave;": '\U000000E0',
+ "alefsym;": '\U00002135',
+ "aleph;": '\U00002135',
+ "alpha;": '\U000003B1',
+ "amacr;": '\U00000101',
+ "amalg;": '\U00002A3F',
+ "amp;": '\U00000026',
+ "and;": '\U00002227',
+ "andand;": '\U00002A55',
+ "andd;": '\U00002A5C',
+ "andslope;": '\U00002A58',
+ "andv;": '\U00002A5A',
+ "ang;": '\U00002220',
+ "ange;": '\U000029A4',
+ "angle;": '\U00002220',
+ "angmsd;": '\U00002221',
+ "angmsdaa;": '\U000029A8',
+ "angmsdab;": '\U000029A9',
+ "angmsdac;": '\U000029AA',
+ "angmsdad;": '\U000029AB',
+ "angmsdae;": '\U000029AC',
+ "angmsdaf;": '\U000029AD',
+ "angmsdag;": '\U000029AE',
+ "angmsdah;": '\U000029AF',
+ "angrt;": '\U0000221F',
+ "angrtvb;": '\U000022BE',
+ "angrtvbd;": '\U0000299D',
+ "angsph;": '\U00002222',
+ "angst;": '\U000000C5',
+ "angzarr;": '\U0000237C',
+ "aogon;": '\U00000105',
+ "aopf;": '\U0001D552',
+ "ap;": '\U00002248',
+ "apE;": '\U00002A70',
+ "apacir;": '\U00002A6F',
+ "ape;": '\U0000224A',
+ "apid;": '\U0000224B',
+ "apos;": '\U00000027',
+ "approx;": '\U00002248',
+ "approxeq;": '\U0000224A',
+ "aring;": '\U000000E5',
+ "ascr;": '\U0001D4B6',
+ "ast;": '\U0000002A',
+ "asymp;": '\U00002248',
+ "asympeq;": '\U0000224D',
+ "atilde;": '\U000000E3',
+ "auml;": '\U000000E4',
+ "awconint;": '\U00002233',
+ "awint;": '\U00002A11',
+ "bNot;": '\U00002AED',
+ "backcong;": '\U0000224C',
+ "backepsilon;": '\U000003F6',
+ "backprime;": '\U00002035',
+ "backsim;": '\U0000223D',
+ "backsimeq;": '\U000022CD',
+ "barvee;": '\U000022BD',
+ "barwed;": '\U00002305',
+ "barwedge;": '\U00002305',
+ "bbrk;": '\U000023B5',
+ "bbrktbrk;": '\U000023B6',
+ "bcong;": '\U0000224C',
+ "bcy;": '\U00000431',
+ "bdquo;": '\U0000201E',
+ "becaus;": '\U00002235',
+ "because;": '\U00002235',
+ "bemptyv;": '\U000029B0',
+ "bepsi;": '\U000003F6',
+ "bernou;": '\U0000212C',
+ "beta;": '\U000003B2',
+ "beth;": '\U00002136',
+ "between;": '\U0000226C',
+ "bfr;": '\U0001D51F',
+ "bigcap;": '\U000022C2',
+ "bigcirc;": '\U000025EF',
+ "bigcup;": '\U000022C3',
+ "bigodot;": '\U00002A00',
+ "bigoplus;": '\U00002A01',
+ "bigotimes;": '\U00002A02',
+ "bigsqcup;": '\U00002A06',
+ "bigstar;": '\U00002605',
+ "bigtriangledown;": '\U000025BD',
+ "bigtriangleup;": '\U000025B3',
+ "biguplus;": '\U00002A04',
+ "bigvee;": '\U000022C1',
+ "bigwedge;": '\U000022C0',
+ "bkarow;": '\U0000290D',
+ "blacklozenge;": '\U000029EB',
+ "blacksquare;": '\U000025AA',
+ "blacktriangle;": '\U000025B4',
+ "blacktriangledown;": '\U000025BE',
+ "blacktriangleleft;": '\U000025C2',
+ "blacktriangleright;": '\U000025B8',
+ "blank;": '\U00002423',
+ "blk12;": '\U00002592',
+ "blk14;": '\U00002591',
+ "blk34;": '\U00002593',
+ "block;": '\U00002588',
+ "bnot;": '\U00002310',
+ "bopf;": '\U0001D553',
+ "bot;": '\U000022A5',
+ "bottom;": '\U000022A5',
+ "bowtie;": '\U000022C8',
+ "boxDL;": '\U00002557',
+ "boxDR;": '\U00002554',
+ "boxDl;": '\U00002556',
+ "boxDr;": '\U00002553',
+ "boxH;": '\U00002550',
+ "boxHD;": '\U00002566',
+ "boxHU;": '\U00002569',
+ "boxHd;": '\U00002564',
+ "boxHu;": '\U00002567',
+ "boxUL;": '\U0000255D',
+ "boxUR;": '\U0000255A',
+ "boxUl;": '\U0000255C',
+ "boxUr;": '\U00002559',
+ "boxV;": '\U00002551',
+ "boxVH;": '\U0000256C',
+ "boxVL;": '\U00002563',
+ "boxVR;": '\U00002560',
+ "boxVh;": '\U0000256B',
+ "boxVl;": '\U00002562',
+ "boxVr;": '\U0000255F',
+ "boxbox;": '\U000029C9',
+ "boxdL;": '\U00002555',
+ "boxdR;": '\U00002552',
+ "boxdl;": '\U00002510',
+ "boxdr;": '\U0000250C',
+ "boxh;": '\U00002500',
+ "boxhD;": '\U00002565',
+ "boxhU;": '\U00002568',
+ "boxhd;": '\U0000252C',
+ "boxhu;": '\U00002534',
+ "boxminus;": '\U0000229F',
+ "boxplus;": '\U0000229E',
+ "boxtimes;": '\U000022A0',
+ "boxuL;": '\U0000255B',
+ "boxuR;": '\U00002558',
+ "boxul;": '\U00002518',
+ "boxur;": '\U00002514',
+ "boxv;": '\U00002502',
+ "boxvH;": '\U0000256A',
+ "boxvL;": '\U00002561',
+ "boxvR;": '\U0000255E',
+ "boxvh;": '\U0000253C',
+ "boxvl;": '\U00002524',
+ "boxvr;": '\U0000251C',
+ "bprime;": '\U00002035',
+ "breve;": '\U000002D8',
+ "brvbar;": '\U000000A6',
+ "bscr;": '\U0001D4B7',
+ "bsemi;": '\U0000204F',
+ "bsim;": '\U0000223D',
+ "bsime;": '\U000022CD',
+ "bsol;": '\U0000005C',
+ "bsolb;": '\U000029C5',
+ "bsolhsub;": '\U000027C8',
+ "bull;": '\U00002022',
+ "bullet;": '\U00002022',
+ "bump;": '\U0000224E',
+ "bumpE;": '\U00002AAE',
+ "bumpe;": '\U0000224F',
+ "bumpeq;": '\U0000224F',
+ "cacute;": '\U00000107',
+ "cap;": '\U00002229',
+ "capand;": '\U00002A44',
+ "capbrcup;": '\U00002A49',
+ "capcap;": '\U00002A4B',
+ "capcup;": '\U00002A47',
+ "capdot;": '\U00002A40',
+ "caret;": '\U00002041',
+ "caron;": '\U000002C7',
+ "ccaps;": '\U00002A4D',
+ "ccaron;": '\U0000010D',
+ "ccedil;": '\U000000E7',
+ "ccirc;": '\U00000109',
+ "ccups;": '\U00002A4C',
+ "ccupssm;": '\U00002A50',
+ "cdot;": '\U0000010B',
+ "cedil;": '\U000000B8',
+ "cemptyv;": '\U000029B2',
+ "cent;": '\U000000A2',
+ "centerdot;": '\U000000B7',
+ "cfr;": '\U0001D520',
+ "chcy;": '\U00000447',
+ "check;": '\U00002713',
+ "checkmark;": '\U00002713',
+ "chi;": '\U000003C7',
+ "cir;": '\U000025CB',
+ "cirE;": '\U000029C3',
+ "circ;": '\U000002C6',
+ "circeq;": '\U00002257',
+ "circlearrowleft;": '\U000021BA',
+ "circlearrowright;": '\U000021BB',
+ "circledR;": '\U000000AE',
+ "circledS;": '\U000024C8',
+ "circledast;": '\U0000229B',
+ "circledcirc;": '\U0000229A',
+ "circleddash;": '\U0000229D',
+ "cire;": '\U00002257',
+ "cirfnint;": '\U00002A10',
+ "cirmid;": '\U00002AEF',
+ "cirscir;": '\U000029C2',
+ "clubs;": '\U00002663',
+ "clubsuit;": '\U00002663',
+ "colon;": '\U0000003A',
+ "colone;": '\U00002254',
+ "coloneq;": '\U00002254',
+ "comma;": '\U0000002C',
+ "commat;": '\U00000040',
+ "comp;": '\U00002201',
+ "compfn;": '\U00002218',
+ "complement;": '\U00002201',
+ "complexes;": '\U00002102',
+ "cong;": '\U00002245',
+ "congdot;": '\U00002A6D',
+ "conint;": '\U0000222E',
+ "copf;": '\U0001D554',
+ "coprod;": '\U00002210',
+ "copy;": '\U000000A9',
+ "copysr;": '\U00002117',
+ "crarr;": '\U000021B5',
+ "cross;": '\U00002717',
+ "cscr;": '\U0001D4B8',
+ "csub;": '\U00002ACF',
+ "csube;": '\U00002AD1',
+ "csup;": '\U00002AD0',
+ "csupe;": '\U00002AD2',
+ "ctdot;": '\U000022EF',
+ "cudarrl;": '\U00002938',
+ "cudarrr;": '\U00002935',
+ "cuepr;": '\U000022DE',
+ "cuesc;": '\U000022DF',
+ "cularr;": '\U000021B6',
+ "cularrp;": '\U0000293D',
+ "cup;": '\U0000222A',
+ "cupbrcap;": '\U00002A48',
+ "cupcap;": '\U00002A46',
+ "cupcup;": '\U00002A4A',
+ "cupdot;": '\U0000228D',
+ "cupor;": '\U00002A45',
+ "curarr;": '\U000021B7',
+ "curarrm;": '\U0000293C',
+ "curlyeqprec;": '\U000022DE',
+ "curlyeqsucc;": '\U000022DF',
+ "curlyvee;": '\U000022CE',
+ "curlywedge;": '\U000022CF',
+ "curren;": '\U000000A4',
+ "curvearrowleft;": '\U000021B6',
+ "curvearrowright;": '\U000021B7',
+ "cuvee;": '\U000022CE',
+ "cuwed;": '\U000022CF',
+ "cwconint;": '\U00002232',
+ "cwint;": '\U00002231',
+ "cylcty;": '\U0000232D',
+ "dArr;": '\U000021D3',
+ "dHar;": '\U00002965',
+ "dagger;": '\U00002020',
+ "daleth;": '\U00002138',
+ "darr;": '\U00002193',
+ "dash;": '\U00002010',
+ "dashv;": '\U000022A3',
+ "dbkarow;": '\U0000290F',
+ "dblac;": '\U000002DD',
+ "dcaron;": '\U0000010F',
+ "dcy;": '\U00000434',
+ "dd;": '\U00002146',
+ "ddagger;": '\U00002021',
+ "ddarr;": '\U000021CA',
+ "ddotseq;": '\U00002A77',
+ "deg;": '\U000000B0',
+ "delta;": '\U000003B4',
+ "demptyv;": '\U000029B1',
+ "dfisht;": '\U0000297F',
+ "dfr;": '\U0001D521',
+ "dharl;": '\U000021C3',
+ "dharr;": '\U000021C2',
+ "diam;": '\U000022C4',
+ "diamond;": '\U000022C4',
+ "diamondsuit;": '\U00002666',
+ "diams;": '\U00002666',
+ "die;": '\U000000A8',
+ "digamma;": '\U000003DD',
+ "disin;": '\U000022F2',
+ "div;": '\U000000F7',
+ "divide;": '\U000000F7',
+ "divideontimes;": '\U000022C7',
+ "divonx;": '\U000022C7',
+ "djcy;": '\U00000452',
+ "dlcorn;": '\U0000231E',
+ "dlcrop;": '\U0000230D',
+ "dollar;": '\U00000024',
+ "dopf;": '\U0001D555',
+ "dot;": '\U000002D9',
+ "doteq;": '\U00002250',
+ "doteqdot;": '\U00002251',
+ "dotminus;": '\U00002238',
+ "dotplus;": '\U00002214',
+ "dotsquare;": '\U000022A1',
+ "doublebarwedge;": '\U00002306',
+ "downarrow;": '\U00002193',
+ "downdownarrows;": '\U000021CA',
+ "downharpoonleft;": '\U000021C3',
+ "downharpoonright;": '\U000021C2',
+ "drbkarow;": '\U00002910',
+ "drcorn;": '\U0000231F',
+ "drcrop;": '\U0000230C',
+ "dscr;": '\U0001D4B9',
+ "dscy;": '\U00000455',
+ "dsol;": '\U000029F6',
+ "dstrok;": '\U00000111',
+ "dtdot;": '\U000022F1',
+ "dtri;": '\U000025BF',
+ "dtrif;": '\U000025BE',
+ "duarr;": '\U000021F5',
+ "duhar;": '\U0000296F',
+ "dwangle;": '\U000029A6',
+ "dzcy;": '\U0000045F',
+ "dzigrarr;": '\U000027FF',
+ "eDDot;": '\U00002A77',
+ "eDot;": '\U00002251',
+ "eacute;": '\U000000E9',
+ "easter;": '\U00002A6E',
+ "ecaron;": '\U0000011B',
+ "ecir;": '\U00002256',
+ "ecirc;": '\U000000EA',
+ "ecolon;": '\U00002255',
+ "ecy;": '\U0000044D',
+ "edot;": '\U00000117',
+ "ee;": '\U00002147',
+ "efDot;": '\U00002252',
+ "efr;": '\U0001D522',
+ "eg;": '\U00002A9A',
+ "egrave;": '\U000000E8',
+ "egs;": '\U00002A96',
+ "egsdot;": '\U00002A98',
+ "el;": '\U00002A99',
+ "elinters;": '\U000023E7',
+ "ell;": '\U00002113',
+ "els;": '\U00002A95',
+ "elsdot;": '\U00002A97',
+ "emacr;": '\U00000113',
+ "empty;": '\U00002205',
+ "emptyset;": '\U00002205',
+ "emptyv;": '\U00002205',
+ "emsp;": '\U00002003',
+ "emsp13;": '\U00002004',
+ "emsp14;": '\U00002005',
+ "eng;": '\U0000014B',
+ "ensp;": '\U00002002',
+ "eogon;": '\U00000119',
+ "eopf;": '\U0001D556',
+ "epar;": '\U000022D5',
+ "eparsl;": '\U000029E3',
+ "eplus;": '\U00002A71',
+ "epsi;": '\U000003B5',
+ "epsilon;": '\U000003B5',
+ "epsiv;": '\U000003F5',
+ "eqcirc;": '\U00002256',
+ "eqcolon;": '\U00002255',
+ "eqsim;": '\U00002242',
+ "eqslantgtr;": '\U00002A96',
+ "eqslantless;": '\U00002A95',
+ "equals;": '\U0000003D',
+ "equest;": '\U0000225F',
+ "equiv;": '\U00002261',
+ "equivDD;": '\U00002A78',
+ "eqvparsl;": '\U000029E5',
+ "erDot;": '\U00002253',
+ "erarr;": '\U00002971',
+ "escr;": '\U0000212F',
+ "esdot;": '\U00002250',
+ "esim;": '\U00002242',
+ "eta;": '\U000003B7',
+ "eth;": '\U000000F0',
+ "euml;": '\U000000EB',
+ "euro;": '\U000020AC',
+ "excl;": '\U00000021',
+ "exist;": '\U00002203',
+ "expectation;": '\U00002130',
+ "exponentiale;": '\U00002147',
+ "fallingdotseq;": '\U00002252',
+ "fcy;": '\U00000444',
+ "female;": '\U00002640',
+ "ffilig;": '\U0000FB03',
+ "fflig;": '\U0000FB00',
+ "ffllig;": '\U0000FB04',
+ "ffr;": '\U0001D523',
+ "filig;": '\U0000FB01',
+ "flat;": '\U0000266D',
+ "fllig;": '\U0000FB02',
+ "fltns;": '\U000025B1',
+ "fnof;": '\U00000192',
+ "fopf;": '\U0001D557',
+ "forall;": '\U00002200',
+ "fork;": '\U000022D4',
+ "forkv;": '\U00002AD9',
+ "fpartint;": '\U00002A0D',
+ "frac12;": '\U000000BD',
+ "frac13;": '\U00002153',
+ "frac14;": '\U000000BC',
+ "frac15;": '\U00002155',
+ "frac16;": '\U00002159',
+ "frac18;": '\U0000215B',
+ "frac23;": '\U00002154',
+ "frac25;": '\U00002156',
+ "frac34;": '\U000000BE',
+ "frac35;": '\U00002157',
+ "frac38;": '\U0000215C',
+ "frac45;": '\U00002158',
+ "frac56;": '\U0000215A',
+ "frac58;": '\U0000215D',
+ "frac78;": '\U0000215E',
+ "frasl;": '\U00002044',
+ "frown;": '\U00002322',
+ "fscr;": '\U0001D4BB',
+ "gE;": '\U00002267',
+ "gEl;": '\U00002A8C',
+ "gacute;": '\U000001F5',
+ "gamma;": '\U000003B3',
+ "gammad;": '\U000003DD',
+ "gap;": '\U00002A86',
+ "gbreve;": '\U0000011F',
+ "gcirc;": '\U0000011D',
+ "gcy;": '\U00000433',
+ "gdot;": '\U00000121',
+ "ge;": '\U00002265',
+ "gel;": '\U000022DB',
+ "geq;": '\U00002265',
+ "geqq;": '\U00002267',
+ "geqslant;": '\U00002A7E',
+ "ges;": '\U00002A7E',
+ "gescc;": '\U00002AA9',
+ "gesdot;": '\U00002A80',
+ "gesdoto;": '\U00002A82',
+ "gesdotol;": '\U00002A84',
+ "gesles;": '\U00002A94',
+ "gfr;": '\U0001D524',
+ "gg;": '\U0000226B',
+ "ggg;": '\U000022D9',
+ "gimel;": '\U00002137',
+ "gjcy;": '\U00000453',
+ "gl;": '\U00002277',
+ "glE;": '\U00002A92',
+ "gla;": '\U00002AA5',
+ "glj;": '\U00002AA4',
+ "gnE;": '\U00002269',
+ "gnap;": '\U00002A8A',
+ "gnapprox;": '\U00002A8A',
+ "gne;": '\U00002A88',
+ "gneq;": '\U00002A88',
+ "gneqq;": '\U00002269',
+ "gnsim;": '\U000022E7',
+ "gopf;": '\U0001D558',
+ "grave;": '\U00000060',
+ "gscr;": '\U0000210A',
+ "gsim;": '\U00002273',
+ "gsime;": '\U00002A8E',
+ "gsiml;": '\U00002A90',
+ "gt;": '\U0000003E',
+ "gtcc;": '\U00002AA7',
+ "gtcir;": '\U00002A7A',
+ "gtdot;": '\U000022D7',
+ "gtlPar;": '\U00002995',
+ "gtquest;": '\U00002A7C',
+ "gtrapprox;": '\U00002A86',
+ "gtrarr;": '\U00002978',
+ "gtrdot;": '\U000022D7',
+ "gtreqless;": '\U000022DB',
+ "gtreqqless;": '\U00002A8C',
+ "gtrless;": '\U00002277',
+ "gtrsim;": '\U00002273',
+ "hArr;": '\U000021D4',
+ "hairsp;": '\U0000200A',
+ "half;": '\U000000BD',
+ "hamilt;": '\U0000210B',
+ "hardcy;": '\U0000044A',
+ "harr;": '\U00002194',
+ "harrcir;": '\U00002948',
+ "harrw;": '\U000021AD',
+ "hbar;": '\U0000210F',
+ "hcirc;": '\U00000125',
+ "hearts;": '\U00002665',
+ "heartsuit;": '\U00002665',
+ "hellip;": '\U00002026',
+ "hercon;": '\U000022B9',
+ "hfr;": '\U0001D525',
+ "hksearow;": '\U00002925',
+ "hkswarow;": '\U00002926',
+ "hoarr;": '\U000021FF',
+ "homtht;": '\U0000223B',
+ "hookleftarrow;": '\U000021A9',
+ "hookrightarrow;": '\U000021AA',
+ "hopf;": '\U0001D559',
+ "horbar;": '\U00002015',
+ "hscr;": '\U0001D4BD',
+ "hslash;": '\U0000210F',
+ "hstrok;": '\U00000127',
+ "hybull;": '\U00002043',
+ "hyphen;": '\U00002010',
+ "iacute;": '\U000000ED',
+ "ic;": '\U00002063',
+ "icirc;": '\U000000EE',
+ "icy;": '\U00000438',
+ "iecy;": '\U00000435',
+ "iexcl;": '\U000000A1',
+ "iff;": '\U000021D4',
+ "ifr;": '\U0001D526',
+ "igrave;": '\U000000EC',
+ "ii;": '\U00002148',
+ "iiiint;": '\U00002A0C',
+ "iiint;": '\U0000222D',
+ "iinfin;": '\U000029DC',
+ "iiota;": '\U00002129',
+ "ijlig;": '\U00000133',
+ "imacr;": '\U0000012B',
+ "image;": '\U00002111',
+ "imagline;": '\U00002110',
+ "imagpart;": '\U00002111',
+ "imath;": '\U00000131',
+ "imof;": '\U000022B7',
+ "imped;": '\U000001B5',
+ "in;": '\U00002208',
+ "incare;": '\U00002105',
+ "infin;": '\U0000221E',
+ "infintie;": '\U000029DD',
+ "inodot;": '\U00000131',
+ "int;": '\U0000222B',
+ "intcal;": '\U000022BA',
+ "integers;": '\U00002124',
+ "intercal;": '\U000022BA',
+ "intlarhk;": '\U00002A17',
+ "intprod;": '\U00002A3C',
+ "iocy;": '\U00000451',
+ "iogon;": '\U0000012F',
+ "iopf;": '\U0001D55A',
+ "iota;": '\U000003B9',
+ "iprod;": '\U00002A3C',
+ "iquest;": '\U000000BF',
+ "iscr;": '\U0001D4BE',
+ "isin;": '\U00002208',
+ "isinE;": '\U000022F9',
+ "isindot;": '\U000022F5',
+ "isins;": '\U000022F4',
+ "isinsv;": '\U000022F3',
+ "isinv;": '\U00002208',
+ "it;": '\U00002062',
+ "itilde;": '\U00000129',
+ "iukcy;": '\U00000456',
+ "iuml;": '\U000000EF',
+ "jcirc;": '\U00000135',
+ "jcy;": '\U00000439',
+ "jfr;": '\U0001D527',
+ "jmath;": '\U00000237',
+ "jopf;": '\U0001D55B',
+ "jscr;": '\U0001D4BF',
+ "jsercy;": '\U00000458',
+ "jukcy;": '\U00000454',
+ "kappa;": '\U000003BA',
+ "kappav;": '\U000003F0',
+ "kcedil;": '\U00000137',
+ "kcy;": '\U0000043A',
+ "kfr;": '\U0001D528',
+ "kgreen;": '\U00000138',
+ "khcy;": '\U00000445',
+ "kjcy;": '\U0000045C',
+ "kopf;": '\U0001D55C',
+ "kscr;": '\U0001D4C0',
+ "lAarr;": '\U000021DA',
+ "lArr;": '\U000021D0',
+ "lAtail;": '\U0000291B',
+ "lBarr;": '\U0000290E',
+ "lE;": '\U00002266',
+ "lEg;": '\U00002A8B',
+ "lHar;": '\U00002962',
+ "lacute;": '\U0000013A',
+ "laemptyv;": '\U000029B4',
+ "lagran;": '\U00002112',
+ "lambda;": '\U000003BB',
+ "lang;": '\U000027E8',
+ "langd;": '\U00002991',
+ "langle;": '\U000027E8',
+ "lap;": '\U00002A85',
+ "laquo;": '\U000000AB',
+ "larr;": '\U00002190',
+ "larrb;": '\U000021E4',
+ "larrbfs;": '\U0000291F',
+ "larrfs;": '\U0000291D',
+ "larrhk;": '\U000021A9',
+ "larrlp;": '\U000021AB',
+ "larrpl;": '\U00002939',
+ "larrsim;": '\U00002973',
+ "larrtl;": '\U000021A2',
+ "lat;": '\U00002AAB',
+ "latail;": '\U00002919',
+ "late;": '\U00002AAD',
+ "lbarr;": '\U0000290C',
+ "lbbrk;": '\U00002772',
+ "lbrace;": '\U0000007B',
+ "lbrack;": '\U0000005B',
+ "lbrke;": '\U0000298B',
+ "lbrksld;": '\U0000298F',
+ "lbrkslu;": '\U0000298D',
+ "lcaron;": '\U0000013E',
+ "lcedil;": '\U0000013C',
+ "lceil;": '\U00002308',
+ "lcub;": '\U0000007B',
+ "lcy;": '\U0000043B',
+ "ldca;": '\U00002936',
+ "ldquo;": '\U0000201C',
+ "ldquor;": '\U0000201E',
+ "ldrdhar;": '\U00002967',
+ "ldrushar;": '\U0000294B',
+ "ldsh;": '\U000021B2',
+ "le;": '\U00002264',
+ "leftarrow;": '\U00002190',
+ "leftarrowtail;": '\U000021A2',
+ "leftharpoondown;": '\U000021BD',
+ "leftharpoonup;": '\U000021BC',
+ "leftleftarrows;": '\U000021C7',
+ "leftrightarrow;": '\U00002194',
+ "leftrightarrows;": '\U000021C6',
+ "leftrightharpoons;": '\U000021CB',
+ "leftrightsquigarrow;": '\U000021AD',
+ "leftthreetimes;": '\U000022CB',
+ "leg;": '\U000022DA',
+ "leq;": '\U00002264',
+ "leqq;": '\U00002266',
+ "leqslant;": '\U00002A7D',
+ "les;": '\U00002A7D',
+ "lescc;": '\U00002AA8',
+ "lesdot;": '\U00002A7F',
+ "lesdoto;": '\U00002A81',
+ "lesdotor;": '\U00002A83',
+ "lesges;": '\U00002A93',
+ "lessapprox;": '\U00002A85',
+ "lessdot;": '\U000022D6',
+ "lesseqgtr;": '\U000022DA',
+ "lesseqqgtr;": '\U00002A8B',
+ "lessgtr;": '\U00002276',
+ "lesssim;": '\U00002272',
+ "lfisht;": '\U0000297C',
+ "lfloor;": '\U0000230A',
+ "lfr;": '\U0001D529',
+ "lg;": '\U00002276',
+ "lgE;": '\U00002A91',
+ "lhard;": '\U000021BD',
+ "lharu;": '\U000021BC',
+ "lharul;": '\U0000296A',
+ "lhblk;": '\U00002584',
+ "ljcy;": '\U00000459',
+ "ll;": '\U0000226A',
+ "llarr;": '\U000021C7',
+ "llcorner;": '\U0000231E',
+ "llhard;": '\U0000296B',
+ "lltri;": '\U000025FA',
+ "lmidot;": '\U00000140',
+ "lmoust;": '\U000023B0',
+ "lmoustache;": '\U000023B0',
+ "lnE;": '\U00002268',
+ "lnap;": '\U00002A89',
+ "lnapprox;": '\U00002A89',
+ "lne;": '\U00002A87',
+ "lneq;": '\U00002A87',
+ "lneqq;": '\U00002268',
+ "lnsim;": '\U000022E6',
+ "loang;": '\U000027EC',
+ "loarr;": '\U000021FD',
+ "lobrk;": '\U000027E6',
+ "longleftarrow;": '\U000027F5',
+ "longleftrightarrow;": '\U000027F7',
+ "longmapsto;": '\U000027FC',
+ "longrightarrow;": '\U000027F6',
+ "looparrowleft;": '\U000021AB',
+ "looparrowright;": '\U000021AC',
+ "lopar;": '\U00002985',
+ "lopf;": '\U0001D55D',
+ "loplus;": '\U00002A2D',
+ "lotimes;": '\U00002A34',
+ "lowast;": '\U00002217',
+ "lowbar;": '\U0000005F',
+ "loz;": '\U000025CA',
+ "lozenge;": '\U000025CA',
+ "lozf;": '\U000029EB',
+ "lpar;": '\U00000028',
+ "lparlt;": '\U00002993',
+ "lrarr;": '\U000021C6',
+ "lrcorner;": '\U0000231F',
+ "lrhar;": '\U000021CB',
+ "lrhard;": '\U0000296D',
+ "lrm;": '\U0000200E',
+ "lrtri;": '\U000022BF',
+ "lsaquo;": '\U00002039',
+ "lscr;": '\U0001D4C1',
+ "lsh;": '\U000021B0',
+ "lsim;": '\U00002272',
+ "lsime;": '\U00002A8D',
+ "lsimg;": '\U00002A8F',
+ "lsqb;": '\U0000005B',
+ "lsquo;": '\U00002018',
+ "lsquor;": '\U0000201A',
+ "lstrok;": '\U00000142',
+ "lt;": '\U0000003C',
+ "ltcc;": '\U00002AA6',
+ "ltcir;": '\U00002A79',
+ "ltdot;": '\U000022D6',
+ "lthree;": '\U000022CB',
+ "ltimes;": '\U000022C9',
+ "ltlarr;": '\U00002976',
+ "ltquest;": '\U00002A7B',
+ "ltrPar;": '\U00002996',
+ "ltri;": '\U000025C3',
+ "ltrie;": '\U000022B4',
+ "ltrif;": '\U000025C2',
+ "lurdshar;": '\U0000294A',
+ "luruhar;": '\U00002966',
+ "mDDot;": '\U0000223A',
+ "macr;": '\U000000AF',
+ "male;": '\U00002642',
+ "malt;": '\U00002720',
+ "maltese;": '\U00002720',
+ "map;": '\U000021A6',
+ "mapsto;": '\U000021A6',
+ "mapstodown;": '\U000021A7',
+ "mapstoleft;": '\U000021A4',
+ "mapstoup;": '\U000021A5',
+ "marker;": '\U000025AE',
+ "mcomma;": '\U00002A29',
+ "mcy;": '\U0000043C',
+ "mdash;": '\U00002014',
+ "measuredangle;": '\U00002221',
+ "mfr;": '\U0001D52A',
+ "mho;": '\U00002127',
+ "micro;": '\U000000B5',
+ "mid;": '\U00002223',
+ "midast;": '\U0000002A',
+ "midcir;": '\U00002AF0',
+ "middot;": '\U000000B7',
+ "minus;": '\U00002212',
+ "minusb;": '\U0000229F',
+ "minusd;": '\U00002238',
+ "minusdu;": '\U00002A2A',
+ "mlcp;": '\U00002ADB',
+ "mldr;": '\U00002026',
+ "mnplus;": '\U00002213',
+ "models;": '\U000022A7',
+ "mopf;": '\U0001D55E',
+ "mp;": '\U00002213',
+ "mscr;": '\U0001D4C2',
+ "mstpos;": '\U0000223E',
+ "mu;": '\U000003BC',
+ "multimap;": '\U000022B8',
+ "mumap;": '\U000022B8',
+ "nLeftarrow;": '\U000021CD',
+ "nLeftrightarrow;": '\U000021CE',
+ "nRightarrow;": '\U000021CF',
+ "nVDash;": '\U000022AF',
+ "nVdash;": '\U000022AE',
+ "nabla;": '\U00002207',
+ "nacute;": '\U00000144',
+ "nap;": '\U00002249',
+ "napos;": '\U00000149',
+ "napprox;": '\U00002249',
+ "natur;": '\U0000266E',
+ "natural;": '\U0000266E',
+ "naturals;": '\U00002115',
+ "nbsp;": '\U000000A0',
+ "ncap;": '\U00002A43',
+ "ncaron;": '\U00000148',
+ "ncedil;": '\U00000146',
+ "ncong;": '\U00002247',
+ "ncup;": '\U00002A42',
+ "ncy;": '\U0000043D',
+ "ndash;": '\U00002013',
+ "ne;": '\U00002260',
+ "neArr;": '\U000021D7',
+ "nearhk;": '\U00002924',
+ "nearr;": '\U00002197',
+ "nearrow;": '\U00002197',
+ "nequiv;": '\U00002262',
+ "nesear;": '\U00002928',
+ "nexist;": '\U00002204',
+ "nexists;": '\U00002204',
+ "nfr;": '\U0001D52B',
+ "nge;": '\U00002271',
+ "ngeq;": '\U00002271',
+ "ngsim;": '\U00002275',
+ "ngt;": '\U0000226F',
+ "ngtr;": '\U0000226F',
+ "nhArr;": '\U000021CE',
+ "nharr;": '\U000021AE',
+ "nhpar;": '\U00002AF2',
+ "ni;": '\U0000220B',
+ "nis;": '\U000022FC',
+ "nisd;": '\U000022FA',
+ "niv;": '\U0000220B',
+ "njcy;": '\U0000045A',
+ "nlArr;": '\U000021CD',
+ "nlarr;": '\U0000219A',
+ "nldr;": '\U00002025',
+ "nle;": '\U00002270',
+ "nleftarrow;": '\U0000219A',
+ "nleftrightarrow;": '\U000021AE',
+ "nleq;": '\U00002270',
+ "nless;": '\U0000226E',
+ "nlsim;": '\U00002274',
+ "nlt;": '\U0000226E',
+ "nltri;": '\U000022EA',
+ "nltrie;": '\U000022EC',
+ "nmid;": '\U00002224',
+ "nopf;": '\U0001D55F',
+ "not;": '\U000000AC',
+ "notin;": '\U00002209',
+ "notinva;": '\U00002209',
+ "notinvb;": '\U000022F7',
+ "notinvc;": '\U000022F6',
+ "notni;": '\U0000220C',
+ "notniva;": '\U0000220C',
+ "notnivb;": '\U000022FE',
+ "notnivc;": '\U000022FD',
+ "npar;": '\U00002226',
+ "nparallel;": '\U00002226',
+ "npolint;": '\U00002A14',
+ "npr;": '\U00002280',
+ "nprcue;": '\U000022E0',
+ "nprec;": '\U00002280',
+ "nrArr;": '\U000021CF',
+ "nrarr;": '\U0000219B',
+ "nrightarrow;": '\U0000219B',
+ "nrtri;": '\U000022EB',
+ "nrtrie;": '\U000022ED',
+ "nsc;": '\U00002281',
+ "nsccue;": '\U000022E1',
+ "nscr;": '\U0001D4C3',
+ "nshortmid;": '\U00002224',
+ "nshortparallel;": '\U00002226',
+ "nsim;": '\U00002241',
+ "nsime;": '\U00002244',
+ "nsimeq;": '\U00002244',
+ "nsmid;": '\U00002224',
+ "nspar;": '\U00002226',
+ "nsqsube;": '\U000022E2',
+ "nsqsupe;": '\U000022E3',
+ "nsub;": '\U00002284',
+ "nsube;": '\U00002288',
+ "nsubseteq;": '\U00002288',
+ "nsucc;": '\U00002281',
+ "nsup;": '\U00002285',
+ "nsupe;": '\U00002289',
+ "nsupseteq;": '\U00002289',
+ "ntgl;": '\U00002279',
+ "ntilde;": '\U000000F1',
+ "ntlg;": '\U00002278',
+ "ntriangleleft;": '\U000022EA',
+ "ntrianglelefteq;": '\U000022EC',
+ "ntriangleright;": '\U000022EB',
+ "ntrianglerighteq;": '\U000022ED',
+ "nu;": '\U000003BD',
+ "num;": '\U00000023',
+ "numero;": '\U00002116',
+ "numsp;": '\U00002007',
+ "nvDash;": '\U000022AD',
+ "nvHarr;": '\U00002904',
+ "nvdash;": '\U000022AC',
+ "nvinfin;": '\U000029DE',
+ "nvlArr;": '\U00002902',
+ "nvrArr;": '\U00002903',
+ "nwArr;": '\U000021D6',
+ "nwarhk;": '\U00002923',
+ "nwarr;": '\U00002196',
+ "nwarrow;": '\U00002196',
+ "nwnear;": '\U00002927',
+ "oS;": '\U000024C8',
+ "oacute;": '\U000000F3',
+ "oast;": '\U0000229B',
+ "ocir;": '\U0000229A',
+ "ocirc;": '\U000000F4',
+ "ocy;": '\U0000043E',
+ "odash;": '\U0000229D',
+ "odblac;": '\U00000151',
+ "odiv;": '\U00002A38',
+ "odot;": '\U00002299',
+ "odsold;": '\U000029BC',
+ "oelig;": '\U00000153',
+ "ofcir;": '\U000029BF',
+ "ofr;": '\U0001D52C',
+ "ogon;": '\U000002DB',
+ "ograve;": '\U000000F2',
+ "ogt;": '\U000029C1',
+ "ohbar;": '\U000029B5',
+ "ohm;": '\U000003A9',
+ "oint;": '\U0000222E',
+ "olarr;": '\U000021BA',
+ "olcir;": '\U000029BE',
+ "olcross;": '\U000029BB',
+ "oline;": '\U0000203E',
+ "olt;": '\U000029C0',
+ "omacr;": '\U0000014D',
+ "omega;": '\U000003C9',
+ "omicron;": '\U000003BF',
+ "omid;": '\U000029B6',
+ "ominus;": '\U00002296',
+ "oopf;": '\U0001D560',
+ "opar;": '\U000029B7',
+ "operp;": '\U000029B9',
+ "oplus;": '\U00002295',
+ "or;": '\U00002228',
+ "orarr;": '\U000021BB',
+ "ord;": '\U00002A5D',
+ "order;": '\U00002134',
+ "orderof;": '\U00002134',
+ "ordf;": '\U000000AA',
+ "ordm;": '\U000000BA',
+ "origof;": '\U000022B6',
+ "oror;": '\U00002A56',
+ "orslope;": '\U00002A57',
+ "orv;": '\U00002A5B',
+ "oscr;": '\U00002134',
+ "oslash;": '\U000000F8',
+ "osol;": '\U00002298',
+ "otilde;": '\U000000F5',
+ "otimes;": '\U00002297',
+ "otimesas;": '\U00002A36',
+ "ouml;": '\U000000F6',
+ "ovbar;": '\U0000233D',
+ "par;": '\U00002225',
+ "para;": '\U000000B6',
+ "parallel;": '\U00002225',
+ "parsim;": '\U00002AF3',
+ "parsl;": '\U00002AFD',
+ "part;": '\U00002202',
+ "pcy;": '\U0000043F',
+ "percnt;": '\U00000025',
+ "period;": '\U0000002E',
+ "permil;": '\U00002030',
+ "perp;": '\U000022A5',
+ "pertenk;": '\U00002031',
+ "pfr;": '\U0001D52D',
+ "phi;": '\U000003C6',
+ "phiv;": '\U000003D5',
+ "phmmat;": '\U00002133',
+ "phone;": '\U0000260E',
+ "pi;": '\U000003C0',
+ "pitchfork;": '\U000022D4',
+ "piv;": '\U000003D6',
+ "planck;": '\U0000210F',
+ "planckh;": '\U0000210E',
+ "plankv;": '\U0000210F',
+ "plus;": '\U0000002B',
+ "plusacir;": '\U00002A23',
+ "plusb;": '\U0000229E',
+ "pluscir;": '\U00002A22',
+ "plusdo;": '\U00002214',
+ "plusdu;": '\U00002A25',
+ "pluse;": '\U00002A72',
+ "plusmn;": '\U000000B1',
+ "plussim;": '\U00002A26',
+ "plustwo;": '\U00002A27',
+ "pm;": '\U000000B1',
+ "pointint;": '\U00002A15',
+ "popf;": '\U0001D561',
+ "pound;": '\U000000A3',
+ "pr;": '\U0000227A',
+ "prE;": '\U00002AB3',
+ "prap;": '\U00002AB7',
+ "prcue;": '\U0000227C',
+ "pre;": '\U00002AAF',
+ "prec;": '\U0000227A',
+ "precapprox;": '\U00002AB7',
+ "preccurlyeq;": '\U0000227C',
+ "preceq;": '\U00002AAF',
+ "precnapprox;": '\U00002AB9',
+ "precneqq;": '\U00002AB5',
+ "precnsim;": '\U000022E8',
+ "precsim;": '\U0000227E',
+ "prime;": '\U00002032',
+ "primes;": '\U00002119',
+ "prnE;": '\U00002AB5',
+ "prnap;": '\U00002AB9',
+ "prnsim;": '\U000022E8',
+ "prod;": '\U0000220F',
+ "profalar;": '\U0000232E',
+ "profline;": '\U00002312',
+ "profsurf;": '\U00002313',
+ "prop;": '\U0000221D',
+ "propto;": '\U0000221D',
+ "prsim;": '\U0000227E',
+ "prurel;": '\U000022B0',
+ "pscr;": '\U0001D4C5',
+ "psi;": '\U000003C8',
+ "puncsp;": '\U00002008',
+ "qfr;": '\U0001D52E',
+ "qint;": '\U00002A0C',
+ "qopf;": '\U0001D562',
+ "qprime;": '\U00002057',
+ "qscr;": '\U0001D4C6',
+ "quaternions;": '\U0000210D',
+ "quatint;": '\U00002A16',
+ "quest;": '\U0000003F',
+ "questeq;": '\U0000225F',
+ "quot;": '\U00000022',
+ "rAarr;": '\U000021DB',
+ "rArr;": '\U000021D2',
+ "rAtail;": '\U0000291C',
+ "rBarr;": '\U0000290F',
+ "rHar;": '\U00002964',
+ "racute;": '\U00000155',
+ "radic;": '\U0000221A',
+ "raemptyv;": '\U000029B3',
+ "rang;": '\U000027E9',
+ "rangd;": '\U00002992',
+ "range;": '\U000029A5',
+ "rangle;": '\U000027E9',
+ "raquo;": '\U000000BB',
+ "rarr;": '\U00002192',
+ "rarrap;": '\U00002975',
+ "rarrb;": '\U000021E5',
+ "rarrbfs;": '\U00002920',
+ "rarrc;": '\U00002933',
+ "rarrfs;": '\U0000291E',
+ "rarrhk;": '\U000021AA',
+ "rarrlp;": '\U000021AC',
+ "rarrpl;": '\U00002945',
+ "rarrsim;": '\U00002974',
+ "rarrtl;": '\U000021A3',
+ "rarrw;": '\U0000219D',
+ "ratail;": '\U0000291A',
+ "ratio;": '\U00002236',
+ "rationals;": '\U0000211A',
+ "rbarr;": '\U0000290D',
+ "rbbrk;": '\U00002773',
+ "rbrace;": '\U0000007D',
+ "rbrack;": '\U0000005D',
+ "rbrke;": '\U0000298C',
+ "rbrksld;": '\U0000298E',
+ "rbrkslu;": '\U00002990',
+ "rcaron;": '\U00000159',
+ "rcedil;": '\U00000157',
+ "rceil;": '\U00002309',
+ "rcub;": '\U0000007D',
+ "rcy;": '\U00000440',
+ "rdca;": '\U00002937',
+ "rdldhar;": '\U00002969',
+ "rdquo;": '\U0000201D',
+ "rdquor;": '\U0000201D',
+ "rdsh;": '\U000021B3',
+ "real;": '\U0000211C',
+ "realine;": '\U0000211B',
+ "realpart;": '\U0000211C',
+ "reals;": '\U0000211D',
+ "rect;": '\U000025AD',
+ "reg;": '\U000000AE',
+ "rfisht;": '\U0000297D',
+ "rfloor;": '\U0000230B',
+ "rfr;": '\U0001D52F',
+ "rhard;": '\U000021C1',
+ "rharu;": '\U000021C0',
+ "rharul;": '\U0000296C',
+ "rho;": '\U000003C1',
+ "rhov;": '\U000003F1',
+ "rightarrow;": '\U00002192',
+ "rightarrowtail;": '\U000021A3',
+ "rightharpoondown;": '\U000021C1',
+ "rightharpoonup;": '\U000021C0',
+ "rightleftarrows;": '\U000021C4',
+ "rightleftharpoons;": '\U000021CC',
+ "rightrightarrows;": '\U000021C9',
+ "rightsquigarrow;": '\U0000219D',
+ "rightthreetimes;": '\U000022CC',
+ "ring;": '\U000002DA',
+ "risingdotseq;": '\U00002253',
+ "rlarr;": '\U000021C4',
+ "rlhar;": '\U000021CC',
+ "rlm;": '\U0000200F',
+ "rmoust;": '\U000023B1',
+ "rmoustache;": '\U000023B1',
+ "rnmid;": '\U00002AEE',
+ "roang;": '\U000027ED',
+ "roarr;": '\U000021FE',
+ "robrk;": '\U000027E7',
+ "ropar;": '\U00002986',
+ "ropf;": '\U0001D563',
+ "roplus;": '\U00002A2E',
+ "rotimes;": '\U00002A35',
+ "rpar;": '\U00000029',
+ "rpargt;": '\U00002994',
+ "rppolint;": '\U00002A12',
+ "rrarr;": '\U000021C9',
+ "rsaquo;": '\U0000203A',
+ "rscr;": '\U0001D4C7',
+ "rsh;": '\U000021B1',
+ "rsqb;": '\U0000005D',
+ "rsquo;": '\U00002019',
+ "rsquor;": '\U00002019',
+ "rthree;": '\U000022CC',
+ "rtimes;": '\U000022CA',
+ "rtri;": '\U000025B9',
+ "rtrie;": '\U000022B5',
+ "rtrif;": '\U000025B8',
+ "rtriltri;": '\U000029CE',
+ "ruluhar;": '\U00002968',
+ "rx;": '\U0000211E',
+ "sacute;": '\U0000015B',
+ "sbquo;": '\U0000201A',
+ "sc;": '\U0000227B',
+ "scE;": '\U00002AB4',
+ "scap;": '\U00002AB8',
+ "scaron;": '\U00000161',
+ "sccue;": '\U0000227D',
+ "sce;": '\U00002AB0',
+ "scedil;": '\U0000015F',
+ "scirc;": '\U0000015D',
+ "scnE;": '\U00002AB6',
+ "scnap;": '\U00002ABA',
+ "scnsim;": '\U000022E9',
+ "scpolint;": '\U00002A13',
+ "scsim;": '\U0000227F',
+ "scy;": '\U00000441',
+ "sdot;": '\U000022C5',
+ "sdotb;": '\U000022A1',
+ "sdote;": '\U00002A66',
+ "seArr;": '\U000021D8',
+ "searhk;": '\U00002925',
+ "searr;": '\U00002198',
+ "searrow;": '\U00002198',
+ "sect;": '\U000000A7',
+ "semi;": '\U0000003B',
+ "seswar;": '\U00002929',
+ "setminus;": '\U00002216',
+ "setmn;": '\U00002216',
+ "sext;": '\U00002736',
+ "sfr;": '\U0001D530',
+ "sfrown;": '\U00002322',
+ "sharp;": '\U0000266F',
+ "shchcy;": '\U00000449',
+ "shcy;": '\U00000448',
+ "shortmid;": '\U00002223',
+ "shortparallel;": '\U00002225',
+ "shy;": '\U000000AD',
+ "sigma;": '\U000003C3',
+ "sigmaf;": '\U000003C2',
+ "sigmav;": '\U000003C2',
+ "sim;": '\U0000223C',
+ "simdot;": '\U00002A6A',
+ "sime;": '\U00002243',
+ "simeq;": '\U00002243',
+ "simg;": '\U00002A9E',
+ "simgE;": '\U00002AA0',
+ "siml;": '\U00002A9D',
+ "simlE;": '\U00002A9F',
+ "simne;": '\U00002246',
+ "simplus;": '\U00002A24',
+ "simrarr;": '\U00002972',
+ "slarr;": '\U00002190',
+ "smallsetminus;": '\U00002216',
+ "smashp;": '\U00002A33',
+ "smeparsl;": '\U000029E4',
+ "smid;": '\U00002223',
+ "smile;": '\U00002323',
+ "smt;": '\U00002AAA',
+ "smte;": '\U00002AAC',
+ "softcy;": '\U0000044C',
+ "sol;": '\U0000002F',
+ "solb;": '\U000029C4',
+ "solbar;": '\U0000233F',
+ "sopf;": '\U0001D564',
+ "spades;": '\U00002660',
+ "spadesuit;": '\U00002660',
+ "spar;": '\U00002225',
+ "sqcap;": '\U00002293',
+ "sqcup;": '\U00002294',
+ "sqsub;": '\U0000228F',
+ "sqsube;": '\U00002291',
+ "sqsubset;": '\U0000228F',
+ "sqsubseteq;": '\U00002291',
+ "sqsup;": '\U00002290',
+ "sqsupe;": '\U00002292',
+ "sqsupset;": '\U00002290',
+ "sqsupseteq;": '\U00002292',
+ "squ;": '\U000025A1',
+ "square;": '\U000025A1',
+ "squarf;": '\U000025AA',
+ "squf;": '\U000025AA',
+ "srarr;": '\U00002192',
+ "sscr;": '\U0001D4C8',
+ "ssetmn;": '\U00002216',
+ "ssmile;": '\U00002323',
+ "sstarf;": '\U000022C6',
+ "star;": '\U00002606',
+ "starf;": '\U00002605',
+ "straightepsilon;": '\U000003F5',
+ "straightphi;": '\U000003D5',
+ "strns;": '\U000000AF',
+ "sub;": '\U00002282',
+ "subE;": '\U00002AC5',
+ "subdot;": '\U00002ABD',
+ "sube;": '\U00002286',
+ "subedot;": '\U00002AC3',
+ "submult;": '\U00002AC1',
+ "subnE;": '\U00002ACB',
+ "subne;": '\U0000228A',
+ "subplus;": '\U00002ABF',
+ "subrarr;": '\U00002979',
+ "subset;": '\U00002282',
+ "subseteq;": '\U00002286',
+ "subseteqq;": '\U00002AC5',
+ "subsetneq;": '\U0000228A',
+ "subsetneqq;": '\U00002ACB',
+ "subsim;": '\U00002AC7',
+ "subsub;": '\U00002AD5',
+ "subsup;": '\U00002AD3',
+ "succ;": '\U0000227B',
+ "succapprox;": '\U00002AB8',
+ "succcurlyeq;": '\U0000227D',
+ "succeq;": '\U00002AB0',
+ "succnapprox;": '\U00002ABA',
+ "succneqq;": '\U00002AB6',
+ "succnsim;": '\U000022E9',
+ "succsim;": '\U0000227F',
+ "sum;": '\U00002211',
+ "sung;": '\U0000266A',
+ "sup;": '\U00002283',
+ "sup1;": '\U000000B9',
+ "sup2;": '\U000000B2',
+ "sup3;": '\U000000B3',
+ "supE;": '\U00002AC6',
+ "supdot;": '\U00002ABE',
+ "supdsub;": '\U00002AD8',
+ "supe;": '\U00002287',
+ "supedot;": '\U00002AC4',
+ "suphsol;": '\U000027C9',
+ "suphsub;": '\U00002AD7',
+ "suplarr;": '\U0000297B',
+ "supmult;": '\U00002AC2',
+ "supnE;": '\U00002ACC',
+ "supne;": '\U0000228B',
+ "supplus;": '\U00002AC0',
+ "supset;": '\U00002283',
+ "supseteq;": '\U00002287',
+ "supseteqq;": '\U00002AC6',
+ "supsetneq;": '\U0000228B',
+ "supsetneqq;": '\U00002ACC',
+ "supsim;": '\U00002AC8',
+ "supsub;": '\U00002AD4',
+ "supsup;": '\U00002AD6',
+ "swArr;": '\U000021D9',
+ "swarhk;": '\U00002926',
+ "swarr;": '\U00002199',
+ "swarrow;": '\U00002199',
+ "swnwar;": '\U0000292A',
+ "szlig;": '\U000000DF',
+ "target;": '\U00002316',
+ "tau;": '\U000003C4',
+ "tbrk;": '\U000023B4',
+ "tcaron;": '\U00000165',
+ "tcedil;": '\U00000163',
+ "tcy;": '\U00000442',
+ "tdot;": '\U000020DB',
+ "telrec;": '\U00002315',
+ "tfr;": '\U0001D531',
+ "there4;": '\U00002234',
+ "therefore;": '\U00002234',
+ "theta;": '\U000003B8',
+ "thetasym;": '\U000003D1',
+ "thetav;": '\U000003D1',
+ "thickapprox;": '\U00002248',
+ "thicksim;": '\U0000223C',
+ "thinsp;": '\U00002009',
+ "thkap;": '\U00002248',
+ "thksim;": '\U0000223C',
+ "thorn;": '\U000000FE',
+ "tilde;": '\U000002DC',
+ "times;": '\U000000D7',
+ "timesb;": '\U000022A0',
+ "timesbar;": '\U00002A31',
+ "timesd;": '\U00002A30',
+ "tint;": '\U0000222D',
+ "toea;": '\U00002928',
+ "top;": '\U000022A4',
+ "topbot;": '\U00002336',
+ "topcir;": '\U00002AF1',
+ "topf;": '\U0001D565',
+ "topfork;": '\U00002ADA',
+ "tosa;": '\U00002929',
+ "tprime;": '\U00002034',
+ "trade;": '\U00002122',
+ "triangle;": '\U000025B5',
+ "triangledown;": '\U000025BF',
+ "triangleleft;": '\U000025C3',
+ "trianglelefteq;": '\U000022B4',
+ "triangleq;": '\U0000225C',
+ "triangleright;": '\U000025B9',
+ "trianglerighteq;": '\U000022B5',
+ "tridot;": '\U000025EC',
+ "trie;": '\U0000225C',
+ "triminus;": '\U00002A3A',
+ "triplus;": '\U00002A39',
+ "trisb;": '\U000029CD',
+ "tritime;": '\U00002A3B',
+ "trpezium;": '\U000023E2',
+ "tscr;": '\U0001D4C9',
+ "tscy;": '\U00000446',
+ "tshcy;": '\U0000045B',
+ "tstrok;": '\U00000167',
+ "twixt;": '\U0000226C',
+ "twoheadleftarrow;": '\U0000219E',
+ "twoheadrightarrow;": '\U000021A0',
+ "uArr;": '\U000021D1',
+ "uHar;": '\U00002963',
+ "uacute;": '\U000000FA',
+ "uarr;": '\U00002191',
+ "ubrcy;": '\U0000045E',
+ "ubreve;": '\U0000016D',
+ "ucirc;": '\U000000FB',
+ "ucy;": '\U00000443',
+ "udarr;": '\U000021C5',
+ "udblac;": '\U00000171',
+ "udhar;": '\U0000296E',
+ "ufisht;": '\U0000297E',
+ "ufr;": '\U0001D532',
+ "ugrave;": '\U000000F9',
+ "uharl;": '\U000021BF',
+ "uharr;": '\U000021BE',
+ "uhblk;": '\U00002580',
+ "ulcorn;": '\U0000231C',
+ "ulcorner;": '\U0000231C',
+ "ulcrop;": '\U0000230F',
+ "ultri;": '\U000025F8',
+ "umacr;": '\U0000016B',
+ "uml;": '\U000000A8',
+ "uogon;": '\U00000173',
+ "uopf;": '\U0001D566',
+ "uparrow;": '\U00002191',
+ "updownarrow;": '\U00002195',
+ "upharpoonleft;": '\U000021BF',
+ "upharpoonright;": '\U000021BE',
+ "uplus;": '\U0000228E',
+ "upsi;": '\U000003C5',
+ "upsih;": '\U000003D2',
+ "upsilon;": '\U000003C5',
+ "upuparrows;": '\U000021C8',
+ "urcorn;": '\U0000231D',
+ "urcorner;": '\U0000231D',
+ "urcrop;": '\U0000230E',
+ "uring;": '\U0000016F',
+ "urtri;": '\U000025F9',
+ "uscr;": '\U0001D4CA',
+ "utdot;": '\U000022F0',
+ "utilde;": '\U00000169',
+ "utri;": '\U000025B5',
+ "utrif;": '\U000025B4',
+ "uuarr;": '\U000021C8',
+ "uuml;": '\U000000FC',
+ "uwangle;": '\U000029A7',
+ "vArr;": '\U000021D5',
+ "vBar;": '\U00002AE8',
+ "vBarv;": '\U00002AE9',
+ "vDash;": '\U000022A8',
+ "vangrt;": '\U0000299C',
+ "varepsilon;": '\U000003F5',
+ "varkappa;": '\U000003F0',
+ "varnothing;": '\U00002205',
+ "varphi;": '\U000003D5',
+ "varpi;": '\U000003D6',
+ "varpropto;": '\U0000221D',
+ "varr;": '\U00002195',
+ "varrho;": '\U000003F1',
+ "varsigma;": '\U000003C2',
+ "vartheta;": '\U000003D1',
+ "vartriangleleft;": '\U000022B2',
+ "vartriangleright;": '\U000022B3',
+ "vcy;": '\U00000432',
+ "vdash;": '\U000022A2',
+ "vee;": '\U00002228',
+ "veebar;": '\U000022BB',
+ "veeeq;": '\U0000225A',
+ "vellip;": '\U000022EE',
+ "verbar;": '\U0000007C',
+ "vert;": '\U0000007C',
+ "vfr;": '\U0001D533',
+ "vltri;": '\U000022B2',
+ "vopf;": '\U0001D567',
+ "vprop;": '\U0000221D',
+ "vrtri;": '\U000022B3',
+ "vscr;": '\U0001D4CB',
+ "vzigzag;": '\U0000299A',
+ "wcirc;": '\U00000175',
+ "wedbar;": '\U00002A5F',
+ "wedge;": '\U00002227',
+ "wedgeq;": '\U00002259',
+ "weierp;": '\U00002118',
+ "wfr;": '\U0001D534',
+ "wopf;": '\U0001D568',
+ "wp;": '\U00002118',
+ "wr;": '\U00002240',
+ "wreath;": '\U00002240',
+ "wscr;": '\U0001D4CC',
+ "xcap;": '\U000022C2',
+ "xcirc;": '\U000025EF',
+ "xcup;": '\U000022C3',
+ "xdtri;": '\U000025BD',
+ "xfr;": '\U0001D535',
+ "xhArr;": '\U000027FA',
+ "xharr;": '\U000027F7',
+ "xi;": '\U000003BE',
+ "xlArr;": '\U000027F8',
+ "xlarr;": '\U000027F5',
+ "xmap;": '\U000027FC',
+ "xnis;": '\U000022FB',
+ "xodot;": '\U00002A00',
+ "xopf;": '\U0001D569',
+ "xoplus;": '\U00002A01',
+ "xotime;": '\U00002A02',
+ "xrArr;": '\U000027F9',
+ "xrarr;": '\U000027F6',
+ "xscr;": '\U0001D4CD',
+ "xsqcup;": '\U00002A06',
+ "xuplus;": '\U00002A04',
+ "xutri;": '\U000025B3',
+ "xvee;": '\U000022C1',
+ "xwedge;": '\U000022C0',
+ "yacute;": '\U000000FD',
+ "yacy;": '\U0000044F',
+ "ycirc;": '\U00000177',
+ "ycy;": '\U0000044B',
+ "yen;": '\U000000A5',
+ "yfr;": '\U0001D536',
+ "yicy;": '\U00000457',
+ "yopf;": '\U0001D56A',
+ "yscr;": '\U0001D4CE',
+ "yucy;": '\U0000044E',
+ "yuml;": '\U000000FF',
+ "zacute;": '\U0000017A',
+ "zcaron;": '\U0000017E',
+ "zcy;": '\U00000437',
+ "zdot;": '\U0000017C',
+ "zeetrf;": '\U00002128',
+ "zeta;": '\U000003B6',
+ "zfr;": '\U0001D537',
+ "zhcy;": '\U00000436',
+ "zigrarr;": '\U000021DD',
+ "zopf;": '\U0001D56B',
+ "zscr;": '\U0001D4CF',
+ "zwj;": '\U0000200D',
+ "zwnj;": '\U0000200C',
+ "AElig": '\U000000C6',
+ "AMP": '\U00000026',
+ "Aacute": '\U000000C1',
+ "Acirc": '\U000000C2',
+ "Agrave": '\U000000C0',
+ "Aring": '\U000000C5',
+ "Atilde": '\U000000C3',
+ "Auml": '\U000000C4',
+ "COPY": '\U000000A9',
+ "Ccedil": '\U000000C7',
+ "ETH": '\U000000D0',
+ "Eacute": '\U000000C9',
+ "Ecirc": '\U000000CA',
+ "Egrave": '\U000000C8',
+ "Euml": '\U000000CB',
+ "GT": '\U0000003E',
+ "Iacute": '\U000000CD',
+ "Icirc": '\U000000CE',
+ "Igrave": '\U000000CC',
+ "Iuml": '\U000000CF',
+ "LT": '\U0000003C',
+ "Ntilde": '\U000000D1',
+ "Oacute": '\U000000D3',
+ "Ocirc": '\U000000D4',
+ "Ograve": '\U000000D2',
+ "Oslash": '\U000000D8',
+ "Otilde": '\U000000D5',
+ "Ouml": '\U000000D6',
+ "QUOT": '\U00000022',
+ "REG": '\U000000AE',
+ "THORN": '\U000000DE',
+ "Uacute": '\U000000DA',
+ "Ucirc": '\U000000DB',
+ "Ugrave": '\U000000D9',
+ "Uuml": '\U000000DC',
+ "Yacute": '\U000000DD',
+ "aacute": '\U000000E1',
+ "acirc": '\U000000E2',
+ "acute": '\U000000B4',
+ "aelig": '\U000000E6',
+ "agrave": '\U000000E0',
+ "amp": '\U00000026',
+ "aring": '\U000000E5',
+ "atilde": '\U000000E3',
+ "auml": '\U000000E4',
+ "brvbar": '\U000000A6',
+ "ccedil": '\U000000E7',
+ "cedil": '\U000000B8',
+ "cent": '\U000000A2',
+ "copy": '\U000000A9',
+ "curren": '\U000000A4',
+ "deg": '\U000000B0',
+ "divide": '\U000000F7',
+ "eacute": '\U000000E9',
+ "ecirc": '\U000000EA',
+ "egrave": '\U000000E8',
+ "eth": '\U000000F0',
+ "euml": '\U000000EB',
+ "frac12": '\U000000BD',
+ "frac14": '\U000000BC',
+ "frac34": '\U000000BE',
+ "gt": '\U0000003E',
+ "iacute": '\U000000ED',
+ "icirc": '\U000000EE',
+ "iexcl": '\U000000A1',
+ "igrave": '\U000000EC',
+ "iquest": '\U000000BF',
+ "iuml": '\U000000EF',
+ "laquo": '\U000000AB',
+ "lt": '\U0000003C',
+ "macr": '\U000000AF',
+ "micro": '\U000000B5',
+ "middot": '\U000000B7',
+ "nbsp": '\U000000A0',
+ "not": '\U000000AC',
+ "ntilde": '\U000000F1',
+ "oacute": '\U000000F3',
+ "ocirc": '\U000000F4',
+ "ograve": '\U000000F2',
+ "ordf": '\U000000AA',
+ "ordm": '\U000000BA',
+ "oslash": '\U000000F8',
+ "otilde": '\U000000F5',
+ "ouml": '\U000000F6',
+ "para": '\U000000B6',
+ "plusmn": '\U000000B1',
+ "pound": '\U000000A3',
+ "quot": '\U00000022',
+ "raquo": '\U000000BB',
+ "reg": '\U000000AE',
+ "sect": '\U000000A7',
+ "shy": '\U000000AD',
+ "sup1": '\U000000B9',
+ "sup2": '\U000000B2',
+ "sup3": '\U000000B3',
+ "szlig": '\U000000DF',
+ "thorn": '\U000000FE',
+ "times": '\U000000D7',
+ "uacute": '\U000000FA',
+ "ucirc": '\U000000FB',
+ "ugrave": '\U000000F9',
+ "uml": '\U000000A8',
+ "uuml": '\U000000FC',
+ "yacute": '\U000000FD',
+ "yen": '\U000000A5',
+ "yuml": '\U000000FF',
+}
+
+// HTML entities that are two unicode codepoints.
+var entity2 = map[string][2]rune{
+ // TODO(nigeltao): Handle replacements that are wider than their names.
+ // "nLt;": {'\u226A', '\u20D2'},
+ // "nGt;": {'\u226B', '\u20D2'},
+ "NotEqualTilde;": {'\u2242', '\u0338'},
+ "NotGreaterFullEqual;": {'\u2267', '\u0338'},
+ "NotGreaterGreater;": {'\u226B', '\u0338'},
+ "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'},
+ "NotHumpDownHump;": {'\u224E', '\u0338'},
+ "NotHumpEqual;": {'\u224F', '\u0338'},
+ "NotLeftTriangleBar;": {'\u29CF', '\u0338'},
+ "NotLessLess;": {'\u226A', '\u0338'},
+ "NotLessSlantEqual;": {'\u2A7D', '\u0338'},
+ "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
+ "NotNestedLessLess;": {'\u2AA1', '\u0338'},
+ "NotPrecedesEqual;": {'\u2AAF', '\u0338'},
+ "NotRightTriangleBar;": {'\u29D0', '\u0338'},
+ "NotSquareSubset;": {'\u228F', '\u0338'},
+ "NotSquareSuperset;": {'\u2290', '\u0338'},
+ "NotSubset;": {'\u2282', '\u20D2'},
+ "NotSucceedsEqual;": {'\u2AB0', '\u0338'},
+ "NotSucceedsTilde;": {'\u227F', '\u0338'},
+ "NotSuperset;": {'\u2283', '\u20D2'},
+ "ThickSpace;": {'\u205F', '\u200A'},
+ "acE;": {'\u223E', '\u0333'},
+ "bne;": {'\u003D', '\u20E5'},
+ "bnequiv;": {'\u2261', '\u20E5'},
+ "caps;": {'\u2229', '\uFE00'},
+ "cups;": {'\u222A', '\uFE00'},
+ "fjlig;": {'\u0066', '\u006A'},
+ "gesl;": {'\u22DB', '\uFE00'},
+ "gvertneqq;": {'\u2269', '\uFE00'},
+ "gvnE;": {'\u2269', '\uFE00'},
+ "lates;": {'\u2AAD', '\uFE00'},
+ "lesg;": {'\u22DA', '\uFE00'},
+ "lvertneqq;": {'\u2268', '\uFE00'},
+ "lvnE;": {'\u2268', '\uFE00'},
+ "nGg;": {'\u22D9', '\u0338'},
+ "nGtv;": {'\u226B', '\u0338'},
+ "nLl;": {'\u22D8', '\u0338'},
+ "nLtv;": {'\u226A', '\u0338'},
+ "nang;": {'\u2220', '\u20D2'},
+ "napE;": {'\u2A70', '\u0338'},
+ "napid;": {'\u224B', '\u0338'},
+ "nbump;": {'\u224E', '\u0338'},
+ "nbumpe;": {'\u224F', '\u0338'},
+ "ncongdot;": {'\u2A6D', '\u0338'},
+ "nedot;": {'\u2250', '\u0338'},
+ "nesim;": {'\u2242', '\u0338'},
+ "ngE;": {'\u2267', '\u0338'},
+ "ngeqq;": {'\u2267', '\u0338'},
+ "ngeqslant;": {'\u2A7E', '\u0338'},
+ "nges;": {'\u2A7E', '\u0338'},
+ "nlE;": {'\u2266', '\u0338'},
+ "nleqq;": {'\u2266', '\u0338'},
+ "nleqslant;": {'\u2A7D', '\u0338'},
+ "nles;": {'\u2A7D', '\u0338'},
+ "notinE;": {'\u22F9', '\u0338'},
+ "notindot;": {'\u22F5', '\u0338'},
+ "nparsl;": {'\u2AFD', '\u20E5'},
+ "npart;": {'\u2202', '\u0338'},
+ "npre;": {'\u2AAF', '\u0338'},
+ "npreceq;": {'\u2AAF', '\u0338'},
+ "nrarrc;": {'\u2933', '\u0338'},
+ "nrarrw;": {'\u219D', '\u0338'},
+ "nsce;": {'\u2AB0', '\u0338'},
+ "nsubE;": {'\u2AC5', '\u0338'},
+ "nsubset;": {'\u2282', '\u20D2'},
+ "nsubseteqq;": {'\u2AC5', '\u0338'},
+ "nsucceq;": {'\u2AB0', '\u0338'},
+ "nsupE;": {'\u2AC6', '\u0338'},
+ "nsupset;": {'\u2283', '\u20D2'},
+ "nsupseteqq;": {'\u2AC6', '\u0338'},
+ "nvap;": {'\u224D', '\u20D2'},
+ "nvge;": {'\u2265', '\u20D2'},
+ "nvgt;": {'\u003E', '\u20D2'},
+ "nvle;": {'\u2264', '\u20D2'},
+ "nvlt;": {'\u003C', '\u20D2'},
+ "nvltrie;": {'\u22B4', '\u20D2'},
+ "nvrtrie;": {'\u22B5', '\u20D2'},
+ "nvsim;": {'\u223C', '\u20D2'},
+ "race;": {'\u223D', '\u0331'},
+ "smtes;": {'\u2AAC', '\uFE00'},
+ "sqcaps;": {'\u2293', '\uFE00'},
+ "sqcups;": {'\u2294', '\uFE00'},
+ "varsubsetneq;": {'\u228A', '\uFE00'},
+ "varsubsetneqq;": {'\u2ACB', '\uFE00'},
+ "varsupsetneq;": {'\u228B', '\uFE00'},
+ "varsupsetneqq;": {'\u2ACC', '\uFE00'},
+ "vnsub;": {'\u2282', '\u20D2'},
+ "vnsup;": {'\u2283', '\u20D2'},
+ "vsubnE;": {'\u2ACB', '\uFE00'},
+ "vsubne;": {'\u228A', '\uFE00'},
+ "vsupnE;": {'\u2ACC', '\uFE00'},
+ "vsupne;": {'\u228B', '\uFE00'},
+}
diff --git a/vendor/golang.org/x/net/html/escape.go b/vendor/golang.org/x/net/html/escape.go
new file mode 100644
index 00000000..12f22737
--- /dev/null
+++ b/vendor/golang.org/x/net/html/escape.go
@@ -0,0 +1,339 @@
+// 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 html
+
+import (
+ "bytes"
+ "strings"
+ "unicode/utf8"
+)
+
+// These replacements permit compatibility with old numeric entities that
+// assumed Windows-1252 encoding.
+// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
+var replacementTable = [...]rune{
+ '\u20AC', // First entry is what 0x80 should be replaced with.
+ '\u0081',
+ '\u201A',
+ '\u0192',
+ '\u201E',
+ '\u2026',
+ '\u2020',
+ '\u2021',
+ '\u02C6',
+ '\u2030',
+ '\u0160',
+ '\u2039',
+ '\u0152',
+ '\u008D',
+ '\u017D',
+ '\u008F',
+ '\u0090',
+ '\u2018',
+ '\u2019',
+ '\u201C',
+ '\u201D',
+ '\u2022',
+ '\u2013',
+ '\u2014',
+ '\u02DC',
+ '\u2122',
+ '\u0161',
+ '\u203A',
+ '\u0153',
+ '\u009D',
+ '\u017E',
+ '\u0178', // Last entry is 0x9F.
+ // 0x00->'\uFFFD' is handled programmatically.
+ // 0x0D->'\u000D' is a no-op.
+}
+
+// unescapeEntity reads an entity like "<" from b[src:] and writes the
+// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
+// Precondition: b[src] == '&' && dst <= src.
+// attribute should be true if parsing an attribute value.
+func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
+ // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
+
+ // i starts at 1 because we already know that s[0] == '&'.
+ i, s := 1, b[src:]
+
+ if len(s) <= 1 {
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if s[i] == '#' {
+ if len(s) <= 3 { // We need to have at least ".".
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+ i++
+ c := s[i]
+ hex := false
+ if c == 'x' || c == 'X' {
+ hex = true
+ i++
+ }
+
+ x := '\x00'
+ for i < len(s) {
+ c = s[i]
+ i++
+ if hex {
+ if '0' <= c && c <= '9' {
+ x = 16*x + rune(c) - '0'
+ continue
+ } else if 'a' <= c && c <= 'f' {
+ x = 16*x + rune(c) - 'a' + 10
+ continue
+ } else if 'A' <= c && c <= 'F' {
+ x = 16*x + rune(c) - 'A' + 10
+ continue
+ }
+ } else if '0' <= c && c <= '9' {
+ x = 10*x + rune(c) - '0'
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ if i <= 3 { // No characters matched.
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if 0x80 <= x && x <= 0x9F {
+ // Replace characters from Windows-1252 with UTF-8 equivalents.
+ x = replacementTable[x-0x80]
+ } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
+ // Replace invalid characters with the replacement character.
+ x = '\uFFFD'
+ }
+
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ }
+
+ // Consume the maximum number of characters possible, with the
+ // consumed characters matching one of the named references.
+
+ for i < len(s) {
+ c := s[i]
+ i++
+ // Lower-cased characters are more common in entities, so we check for them first.
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ entityName := string(s[1:i])
+ if entityName == "" {
+ // No-op.
+ } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
+ // No-op.
+ } else if x := entity[entityName]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ } else if x := entity2[entityName]; x[0] != 0 {
+ dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
+ return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+ } else if !attribute {
+ maxLen := len(entityName) - 1
+ if maxLen > longestEntityWithoutSemicolon {
+ maxLen = longestEntityWithoutSemicolon
+ }
+ for j := maxLen; j > 1; j-- {
+ if x := entity[entityName[:j]]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
+ }
+ }
+ }
+
+ dst1, src1 = dst+i, src+i
+ copy(b[dst:dst1], b[src:src1])
+ return dst1, src1
+}
+
+// unescape unescapes b's entities in-place, so that "a<b" becomes "a' byte that, per above, we'd like to avoid escaping unless we have to.
+//
+// Studying the summary table (and T actions in its '>' column) closely, we
+// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the
+// start of the comment data. State 52 is after a '!'. The other three states
+// are after a '-'.
+//
+// Our algorithm is thus to escape every '&' and to escape '>' if and only if:
+// - The '>' is after a '!' or '-' (in the unescaped data) or
+// - The '>' is at the start of the comment data (after the opening ""); err != nil {
+ return err
+ }
+ return nil
+ case DoctypeNode:
+ if _, err := w.WriteString("')
+ case RawNode:
+ _, err := w.WriteString(n.Data)
+ return err
+ default:
+ return errors.New("html: unknown node type")
+ }
+
+ // Render the opening tag.
+ if err := w.WriteByte('<'); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(n.Data); err != nil {
+ return err
+ }
+ for _, a := range n.Attr {
+ if err := w.WriteByte(' '); err != nil {
+ return err
+ }
+ if a.Namespace != "" {
+ if _, err := w.WriteString(a.Namespace); err != nil {
+ return err
+ }
+ if err := w.WriteByte(':'); err != nil {
+ return err
+ }
+ }
+ if _, err := w.WriteString(a.Key); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(`="`); err != nil {
+ return err
+ }
+ if err := escape(w, a.Val); err != nil {
+ return err
+ }
+ if err := w.WriteByte('"'); err != nil {
+ return err
+ }
+ }
+ if voidElements[n.Data] {
+ if n.FirstChild != nil {
+ return fmt.Errorf("html: void element <%s> has child nodes", n.Data)
+ }
+ _, err := w.WriteString("/>")
+ return err
+ }
+ if err := w.WriteByte('>'); err != nil {
+ return err
+ }
+
+ // Add initial newline where there is danger of a newline being ignored.
+ if c := n.FirstChild; c != nil && c.Type == TextNode && strings.HasPrefix(c.Data, "\n") {
+ switch n.Data {
+ case "pre", "listing", "textarea":
+ if err := w.WriteByte('\n'); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Render any child nodes
+ if childTextNodesAreLiteral(n) {
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if c.Type == TextNode {
+ if _, err := w.WriteString(c.Data); err != nil {
+ return err
+ }
+ } else {
+ if err := render1(w, c); err != nil {
+ return err
+ }
+ }
+ }
+ if n.Data == "plaintext" {
+ // Don't render anything else. must be the
+ // last element in the file, with no closing tag.
+ return plaintextAbort
+ }
+ } else {
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ if err := render1(w, c); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Render the closing tag.
+ if _, err := w.WriteString(""); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(n.Data); err != nil {
+ return err
+ }
+ return w.WriteByte('>')
+}
+
+func childTextNodesAreLiteral(n *Node) bool {
+ // Per WHATWG HTML 13.3, if the parent of the current node is a style,
+ // script, xmp, iframe, noembed, noframes, or plaintext element, and the
+ // current node is a text node, append the value of the node's data
+ // literally. The specification is not explicit about it, but we only
+ // enforce this if we are in the HTML namespace (i.e. when the namespace is
+ // "").
+ // NOTE: we also always include noscript elements, although the
+ // specification states that they should only be rendered as such if
+ // scripting is enabled for the node (which is not something we track).
+ if n.Namespace != "" {
+ return false
+ }
+
+ switch n.Data {
+ case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
+ // We need to check if n is a node that was fostered from a HTML namespace
+ // into a non-HTML namespace (in which case, different rules apply to it).
+ // We do this by walking up the tree until we find a node with a non-empty
+ // namespace. If we find such a node, we also have to check if it's
+ // an HTML integration point. If it isn't, then the node we're currently
+ // looking at is foster-parented and we should return false.
+ for p := n.Parent; p != nil; p = p.Parent {
+ if p.Namespace != "" {
+ if !htmlIntegrationPoint(p) {
+ return false
+ }
+ break
+ }
+ }
+
+ return true
+ default:
+ return false
+ }
+}
+
+// writeDoctypeQuoted writes s to w surrounded by quotes. Normally it will use double
+// quotes, but if s contains a double quote, it will use single quotes.
+// If s contains any '>' characters, they are replaced with > in order
+// to prevent triggering an abrupt-doctype-system-identifier parse error.
+// It is used for writing the identifiers in a doctype declaration.
+// In valid HTML, they can't contain both types of quotes.
+func writeDoctypeQuoted(w writer, s string) error {
+ var q byte = '"'
+ if strings.Contains(s, `"`) {
+ // parseDoctype will never produce a Node with both quote types, but a user
+ // can construct their own Node that violates this assumption.
+ if strings.Contains(s, `'`) {
+ return errors.New("doctype contains both quote types, cannot be safely rendered")
+ }
+ q = '\''
+ }
+ if err := w.WriteByte(q); err != nil {
+ return err
+ }
+ if _, err := w.WriteString(strings.ReplaceAll(s, ">", ">")); err != nil {
+ return err
+ }
+ if err := w.WriteByte(q); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Section 12.1.2, "Elements", gives this list of void elements. Void elements
+// are those that can't have any contents.
+var voidElements = map[string]bool{
+ "area": true,
+ "base": true,
+ "br": true,
+ "col": true,
+ "embed": true,
+ "hr": true,
+ "img": true,
+ "input": true,
+ "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
+ "link": true,
+ "meta": true,
+ "param": true,
+ "source": true,
+ "track": true,
+ "wbr": true,
+}
diff --git a/vendor/golang.org/x/net/html/token.go b/vendor/golang.org/x/net/html/token.go
new file mode 100644
index 00000000..058dfb21
--- /dev/null
+++ b/vendor/golang.org/x/net/html/token.go
@@ -0,0 +1,1291 @@
+// 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 html
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "strconv"
+ "strings"
+
+ "golang.org/x/net/html/atom"
+)
+
+// A TokenType is the type of a Token.
+type TokenType uint32
+
+const (
+ // ErrorToken means that an error occurred during tokenization.
+ ErrorToken TokenType = iota
+ // TextToken means a text node.
+ TextToken
+ // A StartTagToken looks like .
+ StartTagToken
+ // An EndTagToken looks like .
+ EndTagToken
+ // A SelfClosingTagToken tag looks like .
+ SelfClosingTagToken
+ // A CommentToken looks like .
+ CommentToken
+ // A DoctypeToken looks like
+ DoctypeToken
+)
+
+// ErrBufferExceeded means that the buffering limit was exceeded.
+var ErrBufferExceeded = errors.New("max buffer exceeded")
+
+// String returns a string representation of the TokenType.
+func (t TokenType) String() string {
+ switch t {
+ case ErrorToken:
+ return "Error"
+ case TextToken:
+ return "Text"
+ case StartTagToken:
+ return "StartTag"
+ case EndTagToken:
+ return "EndTag"
+ case SelfClosingTagToken:
+ return "SelfClosingTag"
+ case CommentToken:
+ return "Comment"
+ case DoctypeToken:
+ return "Doctype"
+ }
+ return "Invalid(" + strconv.Itoa(int(t)) + ")"
+}
+
+// An Attribute is an attribute namespace-key-value triple. Namespace is
+// non-empty for foreign attributes like xlink, Key is alphabetic (and hence
+// does not contain escapable characters like '&', '<' or '>'), and Val is
+// unescaped (it looks like "a"
+ case EndTagToken:
+ return "" + t.tagString() + ">"
+ case SelfClosingTagToken:
+ return "<" + t.tagString() + "/>"
+ case CommentToken:
+ return ""
+ case DoctypeToken:
+ return ""
+ }
+ return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
+}
+
+// span is a range of bytes in a Tokenizer's buffer. The start is inclusive,
+// the end is exclusive.
+type span struct {
+ start, end int
+}
+
+// A Tokenizer returns a stream of HTML Tokens.
+type Tokenizer struct {
+ // r is the source of the HTML text.
+ r io.Reader
+ // tt is the TokenType of the current token.
+ tt TokenType
+ // err is the first error encountered during tokenization. It is possible
+ // for tt != Error && err != nil to hold: this means that Next returned a
+ // valid token but the subsequent Next call will return an error token.
+ // For example, if the HTML text input was just "plain", then the first
+ // Next call would set z.err to io.EOF but return a TextToken, and all
+ // subsequent Next calls would return an ErrorToken.
+ // err is never reset. Once it becomes non-nil, it stays non-nil.
+ err error
+ // readErr is the error returned by the io.Reader r. It is separate from
+ // err because it is valid for an io.Reader to return (n int, err1 error)
+ // such that n > 0 && err1 != nil, and callers should always process the
+ // n > 0 bytes before considering the error err1.
+ readErr error
+ // buf[raw.start:raw.end] holds the raw bytes of the current token.
+ // buf[raw.end:] is buffered input that will yield future tokens.
+ raw span
+ buf []byte
+ // maxBuf limits the data buffered in buf. A value of 0 means unlimited.
+ maxBuf int
+ // buf[data.start:data.end] holds the raw bytes of the current token's data:
+ // a text token's text, a tag token's tag name, etc.
+ data span
+ // pendingAttr is the attribute key and value currently being tokenized.
+ // When complete, pendingAttr is pushed onto attr. nAttrReturned is
+ // incremented on each call to TagAttr.
+ pendingAttr [2]span
+ attr [][2]span
+ attrNames map[string]bool
+ nAttrReturned int
+ // rawTag is the "script" in "" that closes the next token. If
+ // non-empty, the subsequent call to Next will return a raw or RCDATA text
+ // token: one that treats " " as text instead of an element.
+ // rawTag's contents are lower-cased.
+ rawTag string
+ // textIsRaw is whether the current text token's data is not escaped.
+ textIsRaw bool
+ // convertNUL is whether NUL bytes in the current token's data should
+ // be converted into \ufffd replacement characters.
+ convertNUL bool
+ // allowCDATA is whether CDATA sections are allowed in the current context.
+ allowCDATA bool
+}
+
+// AllowCDATA sets whether or not the tokenizer recognizes as
+// the text "foo". The default value is false, which means to recognize it as
+// a bogus comment "" instead.
+//
+// Strictly speaking, an HTML5 compliant tokenizer should allow CDATA if and
+// only if tokenizing foreign content, such as MathML and SVG. However,
+// tracking foreign-contentness is difficult to do purely in the tokenizer,
+// as opposed to the parser, due to HTML integration points: an element
+// can contain a that is foreign-to-SVG but not foreign-to-
+// HTML. For strict compliance with the HTML5 tokenization algorithm, it is the
+// responsibility of the user of a tokenizer to call AllowCDATA as appropriate.
+// In practice, if using the tokenizer without caring whether MathML or SVG
+// CDATA is text or comments, such as tokenizing HTML to find all the anchor
+// text, it is acceptable to ignore this responsibility.
+func (z *Tokenizer) AllowCDATA(allowCDATA bool) {
+ z.allowCDATA = allowCDATA
+}
+
+// NextIsNotRawText instructs the tokenizer that the next token should not be
+// considered as 'raw text'. Some elements, such as script and title elements,
+// normally require the next token after the opening tag to be 'raw text' that
+// has no child elements. For example, tokenizing "ac d "
+// yields a start tag token for "", a text token for "ac d", and
+// an end tag token for " ". There are no distinct start tag or end tag
+// tokens for the "" and " ".
+//
+// This tokenizer implementation will generally look for raw text at the right
+// times. Strictly speaking, an HTML5 compliant tokenizer should not look for
+// raw text if in foreign content: generally needs raw text, but a
+// inside an does not. Another example is that a