diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fb8c796..769f130 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
go-version-file: go.mod
- uses: golangci/golangci-lint-action@v9
with:
- version: v2.12.2
+ version: v2.14.0
dockerfile:
runs-on: ubuntu-latest
diff --git a/.golangci.yml b/.golangci.yml
index 6d52ed9..0dc5b24 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -23,6 +23,7 @@ linters:
# Allow partial initialization of structs
- exhaustruct
+ - exhaustruct_v5
# Allow "globals"; this linter is not currently configurable and fails even unexported package-level declarations
- gochecknoglobals
diff --git a/build/containers/deployment/release.Dockerfile b/build/containers/deployment/release.Dockerfile
index bc5f17f..8c9c43c 100644
--- a/build/containers/deployment/release.Dockerfile
+++ b/build/containers/deployment/release.Dockerfile
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.7
-ARG GO_VERSION=1.26.4
+ARG GO_VERSION=1.27.1
FROM golang:${GO_VERSION} AS builder
WORKDIR /src
diff --git a/go.mod b/go.mod
index 06905d5..40d3897 100644
--- a/go.mod
+++ b/go.mod
@@ -1,31 +1,33 @@
module github.com/olcf/s3m-cli
-go 1.26.4
+go 1.27.1
require (
- github.com/jedib0t/go-pretty/v6 v6.8.0
- github.com/modelcontextprotocol/go-sdk v1.6.1
- github.com/olcf/s3m-apis v0.0.0-00010101000000-000000000000
- github.com/urfave/cli/v3 v3.9.0
- golang.org/x/term v0.44.0
- google.golang.org/grpc v1.81.1
- google.golang.org/protobuf v1.36.11
+ github.com/jedib0t/go-pretty/v6 v6.8.3
+ github.com/modelcontextprotocol/go-sdk v1.8.0
+ github.com/olcf/s3m-apis v0.4.0
+ github.com/urfave/cli/v3 v3.13.0
+ golang.org/x/term v0.46.0
+ google.golang.org/grpc v1.84.0
+ google.golang.org/protobuf v1.36.12
)
require (
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/google/jsonschema-go v0.4.3 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
- github.com/mattn/go-runewidth v0.0.24 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 // indirect
+ github.com/mattn/go-runewidth v0.0.30 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/segmentio/encoding v0.5.4 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
- golang.org/x/net v0.55.0 // indirect
- golang.org/x/oauth2 v0.36.0 // indirect
- golang.org/x/sys v0.46.0 // indirect
- golang.org/x/text v0.38.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20260608224507-4308a22a1bab // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab // indirect
+ golang.org/x/net v0.59.0 // indirect
+ golang.org/x/oauth2 v0.37.0 // indirect
+ golang.org/x/sync v0.23.0 // indirect
+ golang.org/x/sys v0.48.0 // indirect
+ golang.org/x/text v0.42.0 // indirect
+ golang.org/x/time v0.16.0 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20260921155816-b14227669459 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20260921155816-b14227669459 // indirect
)
replace github.com/olcf/s3m-apis => ./internal/pkg/s3m-apis
diff --git a/go.sum b/go.sum
index 327ed01..34b2629 100644
--- a/go.sum
+++ b/go.sum
@@ -1,13 +1,5 @@
-github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
-github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
-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.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
-github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-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/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -16,61 +8,49 @@ 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/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
-github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
-github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
-github.com/jedib0t/go-pretty/v6 v6.8.0 h1:fQOTjATVQl5RhssBro6ZuHANFybCkmJ7FjYPo4b7sEY=
-github.com/jedib0t/go-pretty/v6 v6.8.0/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
-github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
-github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
-github.com/modelcontextprotocol/go-sdk v1.6.1 h1:0zOSupjKUxPKSocPT1Wtago+mUHU2/uZ4xSOY0FGReU=
-github.com/modelcontextprotocol/go-sdk v1.6.1/go.mod h1:kzm3kzFL1/+AziGOE0nUs3gvPoNxMCvkxokMkuFapXQ=
-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/grpc-ecosystem/grpc-gateway/v2 v2.31.0 h1:Bd7KaOxzULLxtZ/K5s1aLbWhR0+5RToO65TXHsf3bqQ=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0/go.mod h1:nN7ts3dFXKtCZWc//yfkpcQNKJABg16/uDVAZpLDalo=
+github.com/jedib0t/go-pretty/v6 v6.8.3 h1:yVSk5aemoYHCvcrtqyXklwqcgHQIQzmy/oUzFlmffSQ=
+github.com/jedib0t/go-pretty/v6 v6.8.3/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
+github.com/mattn/go-runewidth v0.0.30 h1:+KUuiDA4fF0R1p5FeueHefjDm+GIM+kWfFnDjybOPgk=
+github.com/mattn/go-runewidth v0.0.30/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8=
+github.com/modelcontextprotocol/go-sdk v1.8.0 h1:KIvahhYqwtbeniWVPs3TcXEA7b8jEtwfBpOTAI+Urx4=
+github.com/modelcontextprotocol/go-sdk v1.8.0/go.mod h1:dL7u98E/zjJTGzEq+j30jQ8K2k1mb6LeAH4inEcSGts=
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0=
github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
-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/urfave/cli/v3 v3.9.0 h1:AV9lIiPv3ukYnxunaCUsHnEozptYmDN2F0+yWqLMn/c=
-github.com/urfave/cli/v3 v3.9.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
+github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
+github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
+github.com/urfave/cli/v3 v3.13.0 h1:Dr6jqMfIyyFsRVn7Nz5mqLsMY+ZMpfh3a0aMs+umPVY=
+github.com/urfave/cli/v3 v3.13.0/go.mod h1:vXn6HxPNccJSzQr2QvwVncOKrgYGIHU0HY5h8B2nQj4=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
-go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
-go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
-go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
-go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
-go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
-go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
-go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
-go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
-go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
-go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
-go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
-golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
-golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
-golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
-golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
-golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
-golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
-golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
-golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
-golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
-golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
-golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
-golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
+go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
+go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
+golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues=
+golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
+golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98=
+golang.org/x/oauth2 v0.37.0/go.mod h1:IxwZNxUULJmpBFf9K/9NTMSIfZZuvuTy1gGxhigP/58=
+golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
+golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
+golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
+golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
+golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
+golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
+golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
+golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
+golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE=
+golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s=
+golang.org/x/tools v0.50.0 h1:c2ifzfcuY7L90lZ2aKd8S4K2NpASF08SZx9ZuJkHmSU=
+golang.org/x/tools v0.50.0/go.mod h1:7ulVMw3831Mwi5EZD6RomGyffr4VFjuNYXf2BbCEAV0=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
-google.golang.org/genproto/googleapis/api v0.0.0-20260608224507-4308a22a1bab h1:Foefixyu0l973HSYkX8Etw/fPxAmKRhyMGwuqXFiVI0=
-google.golang.org/genproto/googleapis/api v0.0.0-20260608224507-4308a22a1bab/go.mod h1:KdNqO+rCIWgFumrNBSEDlDNrkrQnpkax7Tv1WxNY8V4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab h1:cY0oV1VnAqvaim8VsR8ZyEKAudzbRJMRGwD3W/L7yOw=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
-google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
-google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
-google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
-google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+google.golang.org/genproto/googleapis/api v0.0.0-20260921155816-b14227669459 h1:GS9OIt/j7c8bvBjYNgnKQysVfmV7e4jM0H8ZK95G4t8=
+google.golang.org/genproto/googleapis/api v0.0.0-20260921155816-b14227669459/go.mod h1:PX5/4vemwVoXtwEcRDWwcR1/r0qrosfx3qoVADMwnVE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260921155816-b14227669459 h1:b0xCahf3FK2m2Cv0p4vTozGPWncCvLfwV86UNg8xWU8=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20260921155816-b14227669459/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc=
+google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0=
+google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0=
+google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
+google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
diff --git a/internal/auth/introspect.go b/internal/auth/introspect.go
index dabf0b0..fab6488 100644
--- a/internal/auth/introspect.go
+++ b/internal/auth/introspect.go
@@ -8,6 +8,7 @@ import (
"time"
tmspb "github.com/olcf/s3m-apis/tms/v1"
+ "google.golang.org/grpc"
grpcclient "github.com/olcf/s3m-cli/internal/grpc"
"github.com/olcf/s3m-cli/internal/util"
@@ -21,29 +22,41 @@ type IntrospectionResult struct {
func IntrospectToken(
ctx context.Context, target, token string, connectTimeout, callTimeout time.Duration, debug bool,
) IntrospectionResult {
- res := IntrospectionResult{
- Record: TokenRecord{
- Token: token,
- },
- }
-
conn, err := grpcclient.DialAndWait(ctx, target, token, connectTimeout, debug)
if err != nil {
- res.Err = fmt.Errorf("dial token control: %w", err)
- return res
+ return IntrospectionResult{
+ Record: TokenRecord{Token: token},
+ Err: fmt.Errorf("dial token control: %w", err),
+ }
}
+ res := IntrospectTokenWithConn(ctx, conn, token, callTimeout)
+
defer func() {
if closeErr := conn.Close(); closeErr != nil && res.Err == nil {
res.Err = fmt.Errorf("close connection: %w", closeErr)
}
}()
+ return res
+}
+
+func IntrospectTokenWithConn(
+ ctx context.Context, conn grpc.ClientConnInterface, token string, callTimeout time.Duration,
+) IntrospectionResult {
+ res := IntrospectionResult{
+ Record: TokenRecord{
+ Token: token,
+ },
+ }
+
client := tmspb.NewTokenControlClient(conn)
callCtx, cancel := context.WithTimeout(ctx, callTimeout)
defer cancel()
+ callCtx = grpcclient.ContextWithAuthToken(callCtx, token)
+
resp, err := client.IntrospectAuthToken(callCtx, &tmspb.IntrospectAuthTokenRequest{
GrpcPermissions: true,
})
diff --git a/internal/cmd/servercmd/helpers.go b/internal/cmd/servercmd/helpers.go
index 4d08ccc..b52b641 100644
--- a/internal/cmd/servercmd/helpers.go
+++ b/internal/cmd/servercmd/helpers.go
@@ -175,7 +175,14 @@ func wrapWithAuthTokenExtraction(handler http.Handler) http.Handler {
return
}
- token := grpcclient.TokenFromAuthorizationHeader(r.Header.Get("Authorization"))
+ authorization := r.Header.Get("Authorization")
+ if len(authorization) > maxAuthorizationHeaderBytes {
+ http.Error(w, "Authorization header too large", http.StatusRequestHeaderFieldsTooLarge)
+
+ return
+ }
+
+ token := grpcclient.TokenFromAuthorizationHeader(authorization)
logAuthTokenExtraction(r, token)
@@ -191,6 +198,8 @@ func wrapWithAuthTokenExtraction(handler http.Handler) http.Handler {
})
}
+const maxAuthorizationHeaderBytes = 16 << 10
+
func registerStatelessOpenAPIHandlers(
mux *http.ServeMux,
routes []toolset.HTTPRouteSpec,
diff --git a/internal/cmd/servercmd/helpers_test.go b/internal/cmd/servercmd/helpers_test.go
index 01cb38f..ff62e42 100644
--- a/internal/cmd/servercmd/helpers_test.go
+++ b/internal/cmd/servercmd/helpers_test.go
@@ -146,6 +146,23 @@ func TestWrapWithAuthTokenExtractionMissingHeader(t *testing.T) {
}
}
+func TestWrapWithAuthTokenExtractionRejectsOversizedHeader(t *testing.T) {
+ inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ t.Fatal("inner handler should not be called")
+ })
+
+ handler := wrapWithAuthTokenExtraction(inner)
+ req := httptest.NewRequest(http.MethodPost, "/", nil)
+ req.Header.Set("Authorization", strings.Repeat("x", maxAuthorizationHeaderBytes+1))
+
+ rr := httptest.NewRecorder()
+ handler.ServeHTTP(rr, req)
+
+ if rr.Code != http.StatusRequestHeaderFieldsTooLarge {
+ t.Fatalf("expected status 431, got %d", rr.Code)
+ }
+}
+
func TestWrapWithAuthTokenExtractionOptionsPassthrough(t *testing.T) {
called := false
diff --git a/internal/cmd/servercmd/server.go b/internal/cmd/servercmd/server.go
index 8b26f22..efe96e2 100644
--- a/internal/cmd/servercmd/server.go
+++ b/internal/cmd/servercmd/server.go
@@ -4,8 +4,11 @@ import (
"context"
"encoding/json"
"log/slog"
+ "mime"
"net/http"
"os"
+ "strings"
+ "sync"
"time"
"github.com/modelcontextprotocol/go-sdk/mcp"
@@ -74,7 +77,7 @@ func BuildMCPCommand(rt *runtime.Runtime) *cli.Command {
defer closeConn(conn)
- cache := newTokenCache(rt)
+ cache := newTokenCache(rt, conn)
handler := newStatelessMCPHTTPHandler(rt, conn, cache)
addr := c.String("http-addr")
@@ -101,7 +104,7 @@ func BuildMCPCommand(rt *runtime.Runtime) *cli.Command {
defer closeConn(conn)
- cache := newTokenCache(rt)
+ cache := newTokenCache(rt, conn)
server := mcp.NewServer(&mcp.Implementation{
Name: "s3m",
@@ -163,44 +166,117 @@ func newStatelessMCPHTTPHandler(
conn *grpc.ClientConn,
cache *tokenCache,
) http.Handler {
- var handler http.Handler = mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server {
- token := grpcclient.TokenFromAuthorizationHeader(r.Header.Get("Authorization"))
+ type requestServer struct {
+ once sync.Once
+ server *mcp.Server
+ }
+
+ type requestServerKey struct{}
+
+ streamableHandler := mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server {
+ state, ok := r.Context().Value(requestServerKey{}).(*requestServer)
+ if !ok {
+ return buildStatelessMCPServer(rt, conn, cache, r)
+ }
+
+ state.once.Do(func() {
+ state.server = buildStatelessMCPServer(rt, conn, cache, r)
+ })
+
+ return state.server
+ }, &mcp.StreamableHTTPOptions{
+ Stateless: true,
+ SessionTimeout: cmd.MCPSessionTimeout,
+ })
+
+ requestHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if !validStatelessMCPRequest(w, r) {
+ return
+ }
+
+ state := &requestServer{}
+ ctx := context.WithValue(r.Context(), requestServerKey{}, state)
+ streamableHandler.ServeHTTP(w, r.WithContext(ctx))
+ })
+
+ return wrapWithAuthTokenExtraction(requestHandler)
+}
+
+func buildStatelessMCPServer(
+ rt *runtime.Runtime,
+ conn *grpc.ClientConn,
+ cache *tokenCache,
+ r *http.Request,
+) *mcp.Server {
+ token := grpcclient.TokenFromAuthorizationHeader(r.Header.Get("Authorization"))
+
+ logMCPServerFactory(r, token)
+
+ perms := cache.GetPermissions(r.Context(), token)
+ allowed := filterAllowed(perms, rt.Methods)
+
+ ts := buildToolSet(rt, allowed, conn, cache.Vars)
+
+ srv := mcp.NewServer(&mcp.Implementation{
+ Name: "s3m",
+ Version: buildinfo.Version,
+ }, nil)
- logMCPServerFactory(r, token)
+ for _, spec := range ts.MCP {
+ originalHandler := spec.Handler
+ capturedToken := token
+ wrappedHandler := func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
+ logMCPToolHandler(ctx, req, capturedToken)
- perms := cache.GetPermissions(r.Context(), token)
- allowed := filterAllowed(perms, rt.Methods)
+ ctx = grpcclient.ContextWithAuthToken(ctx, capturedToken)
- ts := buildToolSet(rt, allowed, conn, cache.Vars)
+ return originalHandler(ctx, req)
+ }
+ srv.AddTool(spec.Tool, wrappedHandler)
+ }
- srv := mcp.NewServer(&mcp.Implementation{
- Name: "s3m",
- Version: buildinfo.Version,
- }, nil)
+ return srv
+}
- for _, spec := range ts.MCP {
- // Wrap handler to inject auth token into context.
- // The MCP framework doesn't propagate HTTP request context values to tool handlers,
- // so we need to explicitly inject the token for gRPC calls to be authenticated.
- originalHandler := spec.Handler
- capturedToken := token // explicit capture for closure
- wrappedHandler := func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
- logMCPToolHandler(ctx, req, capturedToken)
+func validStatelessMCPRequest(w http.ResponseWriter, r *http.Request) bool {
+ if r.Method != http.MethodPost {
+ w.Header().Set("Allow", http.MethodPost)
+ http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
+
+ return false
+ }
- ctx = grpcclient.ContextWithAuthToken(ctx, capturedToken)
+ mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
+ if err != nil || mediaType != "application/json" {
+ http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
- return originalHandler(ctx, req)
+ return false
+ }
+
+ var jsonOK, streamOK bool
+
+ for _, value := range r.Header.Values("Accept") {
+ for raw := range strings.SplitSeq(value, ",") {
+ base, _, _ := strings.Cut(strings.TrimSpace(raw), ";")
+ switch strings.ToLower(strings.TrimSpace(base)) {
+ case "application/json", "application/*":
+ jsonOK = true
+ case "text/event-stream", "text/*":
+ streamOK = true
+ case "*/*":
+ jsonOK = true
+ streamOK = true
}
- srv.AddTool(spec.Tool, wrappedHandler)
}
+ }
- return srv
- }, &mcp.StreamableHTTPOptions{
- Stateless: true,
- SessionTimeout: cmd.MCPSessionTimeout,
- })
+ if !jsonOK || !streamOK {
+ http.Error(w, "Accept must contain both 'application/json' and 'text/event-stream'", http.StatusBadRequest)
+
+ return false
+ }
- return wrapWithAuthTokenExtraction(handler)
+ return true
}
//nolint:funlen
@@ -243,7 +319,7 @@ func BuildOpenAPICommand(rt *runtime.Runtime) *cli.Command {
defer closeConn(conn)
- cache := newTokenCache(rt)
+ cache := newTokenCache(rt, conn)
ts := buildToolSet(rt, allowed, conn, cache.Vars)
mux := http.NewServeMux()
diff --git a/internal/cmd/servercmd/server_test.go b/internal/cmd/servercmd/server_test.go
index 94200f2..cedbb51 100644
--- a/internal/cmd/servercmd/server_test.go
+++ b/internal/cmd/servercmd/server_test.go
@@ -2,6 +2,7 @@ package servercmd
import (
"context"
+ "errors"
"fmt"
"net/http"
"net/http/httptest"
@@ -18,6 +19,69 @@ import (
"github.com/olcf/s3m-cli/internal/runtime"
)
+func TestStatelessMCPHTTPHandlerBuildsServerOncePerRequest(t *testing.T) {
+ rt := &runtime.Runtime{}
+ cache := newTokenCache(rt)
+
+ var introspections int
+ cache.introspect = func(context.Context, *runtime.Runtime, string) (auth.TokenRecord, error) {
+ introspections++
+
+ return auth.TokenRecord{}, errors.New("invalid token")
+ }
+
+ handler := newStatelessMCPHTTPHandler(rt, nil, cache)
+ req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{}`))
+ req.Header.Set("Authorization", "Bearer invalid-token")
+ req.Header.Set("Content-Type", "application/json")
+ req.Header.Set("Accept", "application/json, text/event-stream")
+
+ handler.ServeHTTP(httptest.NewRecorder(), req)
+
+ if introspections != 1 {
+ t.Fatalf("expected one introspection per HTTP request, got %d", introspections)
+ }
+}
+
+func TestStatelessMCPHTTPHandlerRejectsInvalidTransportBeforeIntrospection(t *testing.T) {
+ rt := &runtime.Runtime{}
+ cache := newTokenCache(rt)
+
+ var introspections int
+ cache.introspect = func(context.Context, *runtime.Runtime, string) (auth.TokenRecord, error) {
+ introspections++
+
+ return auth.TokenRecord{}, errors.New("invalid token")
+ }
+
+ handler := newStatelessMCPHTTPHandler(rt, nil, cache)
+ tests := []struct {
+ name string
+ method string
+ contentType string
+ accept string
+ }{
+ {name: "method", method: http.MethodGet, contentType: "application/json", accept: "*/*"},
+ {name: "content type", method: http.MethodPost, contentType: "text/plain", accept: "*/*"},
+ {name: "accept", method: http.MethodPost, contentType: "application/json", accept: "application/json"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ req := httptest.NewRequest(tt.method, "/", strings.NewReader(`{}`))
+ req.Header.Set("Authorization", "Bearer invalid-token")
+ req.Header.Set("Content-Type", tt.contentType)
+ req.Header.Set("Accept", tt.accept)
+
+ handler.ServeHTTP(httptest.NewRecorder(), req)
+ })
+ }
+
+ if introspections != 0 {
+ t.Fatalf("expected invalid transport requests to skip introspection, got %d calls", introspections)
+ }
+}
+
func TestStatelessMCPHTTPHandlerUsesBearerForVisibleDocs(t *testing.T) {
file := slurmv0042pb.File_proto_slurm_v0042_slurm_proto
service := file.Services().ByName("SlurmIndirect")
diff --git a/internal/cmd/servercmd/tokencache.go b/internal/cmd/servercmd/tokencache.go
index 1752d72..fda7e8e 100644
--- a/internal/cmd/servercmd/tokencache.go
+++ b/internal/cmd/servercmd/tokencache.go
@@ -13,6 +13,7 @@ import (
grpcclient "github.com/olcf/s3m-cli/internal/grpc"
"github.com/olcf/s3m-cli/internal/permissions"
"github.com/olcf/s3m-cli/internal/runtime"
+ "google.golang.org/grpc"
)
// tokenCache caches introspected token records with TTL-based expiration.
@@ -24,6 +25,7 @@ type tokenCache struct {
mu sync.RWMutex
cache map[string]*tokenCacheEntry
order *list.List
+ inflight map[string]*tokenLookup
}
type tokenCacheEntry struct {
@@ -32,16 +34,39 @@ type tokenCacheEntry struct {
element *list.Element
}
+type tokenLookup struct {
+ done chan struct{}
+ record auth.TokenRecord
+ ok bool
+}
+
const tokenCacheTTL = 2 * time.Hour
const tokenCacheMaxEntries = 2048
-func newTokenCache(rt *runtime.Runtime) *tokenCache {
- return &tokenCache{
+func newTokenCache(rt *runtime.Runtime, connections ...grpc.ClientConnInterface) *tokenCache {
+ cache := &tokenCache{
rt: rt,
introspect: introspectTokenRecord,
cache: make(map[string]*tokenCacheEntry),
order: list.New(),
+ inflight: make(map[string]*tokenLookup),
+ }
+
+ if len(connections) > 0 && connections[0] != nil {
+ conn := connections[0]
+ cache.introspect = func(
+ ctx context.Context, _ *runtime.Runtime, token string,
+ ) (auth.TokenRecord, error) {
+ res := auth.IntrospectTokenWithConn(ctx, conn, token, cmd.GRPCCallTimeout)
+ if res.Err != nil {
+ return auth.TokenRecord{}, res.Err
+ }
+
+ return res.Record, nil
+ }
}
+
+ return cache
}
func introspectTokenRecord(
@@ -126,6 +151,40 @@ func (c *tokenCache) recordForToken(ctx context.Context, token string) (auth.Tok
return cached, true
}
+ c.mu.Lock()
+ if pending, ok := c.inflight[token]; ok {
+ c.mu.Unlock()
+
+ select {
+ case <-pending.done:
+ return pending.record, pending.ok
+ case <-ctx.Done():
+ return auth.TokenRecord{}, false
+ }
+ }
+
+ pending := &tokenLookup{done: make(chan struct{})}
+ c.inflight[token] = pending
+ c.mu.Unlock()
+
+ rec, ok := c.lookupToken(ctx, token)
+
+ c.mu.Lock()
+ pending.record = rec
+ pending.ok = ok
+
+ delete(c.inflight, token)
+ close(pending.done)
+ c.mu.Unlock()
+
+ return rec, ok
+}
+
+func (c *tokenCache) lookupToken(ctx context.Context, token string) (auth.TokenRecord, bool) {
+ if cached, ok := c.loadCachedRecord(token); ok {
+ return cached, true
+ }
+
if rec, ok := c.lookupStoredRecord(token); ok {
c.storeRecord(token, rec)
return rec, true
diff --git a/internal/cmd/servercmd/tokencache_test.go b/internal/cmd/servercmd/tokencache_test.go
index 624415c..b162d25 100644
--- a/internal/cmd/servercmd/tokencache_test.go
+++ b/internal/cmd/servercmd/tokencache_test.go
@@ -10,6 +10,7 @@ import (
"github.com/olcf/s3m-cli/internal/auth"
grpcclient "github.com/olcf/s3m-cli/internal/grpc"
+ "github.com/olcf/s3m-cli/internal/permissions"
"github.com/olcf/s3m-cli/internal/runtime"
)
@@ -219,6 +220,53 @@ func TestGetPermissionsReturnsUnknownWhenIntrospectionFails(t *testing.T) {
}
}
+func TestTokenCacheCoalescesConcurrentIntrospection(t *testing.T) {
+ rt := &runtime.Runtime{Target: "unused-target"}
+ cache := newTokenCache(rt)
+
+ started := make(chan struct{})
+ release := make(chan struct{})
+
+ var mu sync.Mutex
+ var calls int
+ cache.introspect = func(context.Context, *runtime.Runtime, string) (auth.TokenRecord, error) {
+ mu.Lock()
+ calls++
+ if calls == 1 {
+ close(started)
+ }
+ mu.Unlock()
+
+ <-release
+
+ return auth.TokenRecord{Token: "shared-token", Scopes: []string{"/test/*"}}, nil
+ }
+
+ const goroutines = 8
+ results := make(chan permissions.Snapshot, goroutines)
+ for range goroutines {
+ go func() {
+ results <- cache.GetPermissions(context.Background(), "shared-token")
+ }()
+ }
+
+ <-started
+ close(release)
+
+ for range goroutines {
+ if result := <-results; !result.Known {
+ t.Fatal("expected coalesced introspection result to be known")
+ }
+ }
+
+ mu.Lock()
+ defer mu.Unlock()
+
+ if calls != 1 {
+ t.Fatalf("expected one concurrent introspection, got %d", calls)
+ }
+}
+
func TestVarsFromToken(t *testing.T) {
cache := newTokenCache(nil)
diff --git a/internal/docs/store_lookup_search.go b/internal/docs/store_lookup_search.go
index 27d6db6..3ed9ef4 100644
--- a/internal/docs/store_lookup_search.go
+++ b/internal/docs/store_lookup_search.go
@@ -5,6 +5,8 @@ import (
"strings"
)
+const maxSearchQueryTokens = 32
+
//
// Lookup
@@ -173,6 +175,9 @@ func tokenizeQuery(query string) []string {
uniq[f] = struct{}{}
tokens = append(tokens, f)
+ if len(tokens) == maxSearchQueryTokens {
+ break
+ }
}
return tokens
diff --git a/internal/docs/store_test.go b/internal/docs/store_test.go
index 0f4f7c6..6b53097 100644
--- a/internal/docs/store_test.go
+++ b/internal/docs/store_test.go
@@ -102,6 +102,24 @@ func TestSearchDocsScoresAndFilters(t *testing.T) {
}
}
+func TestSearchDocsCapsQueryTokens(t *testing.T) {
+ tokens := make([]string, maxSearchQueryTokens+1)
+ for i := range maxSearchQueryTokens {
+ tokens[i] = "missing" + strings.Repeat("x", i)
+ }
+ tokens[maxSearchQueryTokens] = "kittens"
+
+ store := newTestStore(nil)
+ doc := &Doc{ID: "a", Title: "Alpha", Body: "Kittens everywhere"}
+ doc.Sections = splitDocSections(doc)
+ store.registerDoc(doc, nil)
+
+ results, _ := store.SearchDocs(strings.Join(tokens, " "), nil, 3, 0)
+ if len(results) != 0 {
+ t.Fatalf("expected tokens after the cap to be ignored, got %+v", results)
+ }
+}
+
func TestProcessDocContentFailsForUnknownTool(t *testing.T) {
store := newTestStore([]methodTarget{{
ToolName: "alpha",
diff --git a/internal/toolset/docs.go b/internal/toolset/docs.go
index dd555f3..3631146 100644
--- a/internal/toolset/docs.go
+++ b/internal/toolset/docs.go
@@ -11,6 +11,7 @@ import (
"net/http"
"regexp"
"strings"
+ "unicode/utf8"
"github.com/modelcontextprotocol/go-sdk/mcp"
@@ -22,6 +23,12 @@ import (
type DocStoreGetter func() *docs.Store
+const (
+ maxDocSearchQueryLength = 1024
+ maxDocSearchTags = 32
+ maxDocSearchTagLength = 128
+)
+
type docHandlers struct {
getStore DocStoreGetter
vars DocVariableProvider
@@ -453,6 +460,20 @@ func (h *docHandlers) handleSearch(ctx context.Context, input docSearchRequest)
return nil, errors.New("provide query or tags")
}
+ if utf8.RuneCountInString(input.Query) > maxDocSearchQueryLength {
+ return nil, fmt.Errorf("query must be at most %d characters", maxDocSearchQueryLength)
+ }
+
+ if len(input.Tags) > maxDocSearchTags {
+ return nil, fmt.Errorf("provide at most %d tags", maxDocSearchTags)
+ }
+
+ for _, tag := range input.Tags {
+ if utf8.RuneCountInString(tag) > maxDocSearchTagLength {
+ return nil, fmt.Errorf("tags must be at most %d characters", maxDocSearchTagLength)
+ }
+ }
+
store := h.getStore()
if store == nil {
return nil, errors.New("docs not available")
@@ -468,10 +489,16 @@ func (h *docHandlers) handleSearch(ctx context.Context, input docSearchRequest)
input.Offset = 0
}
- matches, more := store.SearchDocs(input.Query, input.Tags, input.Limit, input.Offset)
+ var (
+ matches []docs.DocMatch
+ more bool
+ )
+
if h.visibleTools != nil {
allMatches, _ := store.SearchDocs(input.Query, input.Tags, len(store.Docs), 0)
matches, more = paginateVisibleDocMatches(h.filterDocMatches(allMatches), input.Limit, input.Offset)
+ } else {
+ matches, more = store.SearchDocs(input.Query, input.Tags, input.Limit, input.Offset)
}
vars := h.currentVars(ctx)
@@ -738,6 +765,7 @@ var (
"query": map[string]any{
"type": "string",
"minLength": 1,
+ "maxLength": maxDocSearchQueryLength,
"pattern": `.*\S.*`,
"description": "Keywords to search for.",
},
@@ -755,8 +783,10 @@ var (
"tags": map[string]any{
"type": "array",
"minItems": 1,
+ "maxItems": maxDocSearchTags,
"items": map[string]any{
"type": "string",
+ "maxLength": maxDocSearchTagLength,
"description": "Filter results to docs containing these tags.",
},
},
diff --git a/internal/toolset/docs_test.go b/internal/toolset/docs_test.go
index e751c54..b0c631b 100644
--- a/internal/toolset/docs_test.go
+++ b/internal/toolset/docs_test.go
@@ -75,6 +75,58 @@ func TestDocSearchToolAcceptsQueryOrTags(t *testing.T) {
}
}
+func TestDocSearchToolRejectsOversizedInputs(t *testing.T) {
+ store := loadDocStore(t, "alpha")
+ ts := BuildDocToolSet(func() *docs.Store { return store }, nil, nil)
+ spec := findMCPToolSpec(t, ts, "doc_search")
+
+ tests := []struct {
+ name string
+ request docSearchRequest
+ want string
+ }{
+ {
+ name: "query",
+ request: docSearchRequest{Query: strings.Repeat("x", maxDocSearchQueryLength+1)},
+ want: "query must be at most",
+ },
+ {
+ name: "tag count",
+ request: docSearchRequest{Tags: make([]string, maxDocSearchTags+1)},
+ want: "provide at most",
+ },
+ {
+ name: "tag length",
+ request: docSearchRequest{Tags: []string{strings.Repeat("x", maxDocSearchTagLength+1)}},
+ want: "tags must be at most",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ arguments, err := json.Marshal(tt.request)
+ if err != nil {
+ t.Fatalf("marshal request: %v", err)
+ }
+
+ result, err := spec.Handler(context.Background(), &mcp.CallToolRequest{
+ Params: &mcp.CallToolParamsRaw{Arguments: arguments},
+ })
+ if err != nil {
+ t.Fatalf("doc_search handler error: %v", err)
+ }
+ if !result.IsError {
+ t.Fatalf("expected oversized input to fail, got %+v", result)
+ }
+
+ text := result.Content[0].(*mcp.TextContent).Text
+ if !strings.Contains(text, tt.want) {
+ t.Fatalf("expected error containing %q, got %q", tt.want, text)
+ }
+ })
+ }
+}
+
func TestDocLookupHidesDocsThatOnlyApplyToHiddenTools(t *testing.T) {
store := loadDocStoreWithDocs(t,
map[string]docFixture{
diff --git a/internal/toolset/storage_helpers.go b/internal/toolset/storage_helpers.go
index 488a466..dd325af 100644
--- a/internal/toolset/storage_helpers.go
+++ b/internal/toolset/storage_helpers.go
@@ -159,8 +159,8 @@ func responseTotalSize(resp *http.Response) int64 {
if cr := resp.Header.Get("Content-Range"); cr != "" {
var totalSize int64
- if idx := strings.LastIndex(cr, "/"); idx != -1 {
- _, _ = fmt.Sscanf(cr[idx+1:], "%d", &totalSize)
+ if _, size, ok := strings.CutLast(cr, "/"); ok {
+ _, _ = fmt.Sscanf(size, "%d", &totalSize)
}
if totalSize != 0 {
diff --git a/spack.yaml b/spack.yaml
index 909841f..e4d3fe6 100644
--- a/spack.yaml
+++ b/spack.yaml
@@ -6,5 +6,5 @@ spack:
unify: true
specs:
- - go@1.26.4
+ - go@1.27.1
- protobuf@3.29.3
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel
index 04b4beb..3964ec0 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel
@@ -38,6 +38,7 @@ go_library(
"@org_golang_google_protobuf//reflect/protoreflect",
"@org_golang_google_protobuf//reflect/protoregistry",
"@org_golang_google_protobuf//types/known/durationpb",
+ "@org_golang_google_protobuf//types/known/emptypb",
"@org_golang_google_protobuf//types/known/fieldmaskpb",
"@org_golang_google_protobuf//types/known/structpb",
"@org_golang_google_protobuf//types/known/timestamppb",
@@ -49,6 +50,7 @@ go_test(
name = "runtime_test",
size = "small",
srcs = [
+ "context_internal_test.go",
"context_test.go",
"convert_test.go",
"errors_test.go",
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go
index 00b2228..5d0c91d 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"fmt"
+ "math"
"net"
"net/http"
"net/textproto"
@@ -157,7 +158,7 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM
for _, val := range vals {
// For backwards-compatibility, pass through 'authorization' header with no prefix.
- if key == "Authorization" {
+ if key == "Authorization" && isValidGRPCMetadataTextValue(val) {
pairs = append(pairs, "authorization", val)
}
if h, ok := mux.incomingHeaderMatcher(key); ok {
@@ -182,9 +183,9 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM
}
}
}
- if host := req.Header.Get(xForwardedHost); host != "" {
+ if host := req.Header.Get(xForwardedHost); host != "" && isValidGRPCMetadataTextValue(host) {
pairs = append(pairs, strings.ToLower(xForwardedHost), host)
- } else if req.Host != "" {
+ } else if req.Host != "" && isValidGRPCMetadataTextValue(req.Host) {
pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host)
}
@@ -195,7 +196,9 @@ func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcM
}
}
if len(xff) > 0 {
- pairs = append(pairs, strings.ToLower(xForwardedFor), strings.Join(xff, ", "))
+ if value := strings.Join(xff, ", "); isValidGRPCMetadataTextValue(value) {
+ pairs = append(pairs, strings.ToLower(xForwardedFor), value)
+ }
}
if timeout != 0 {
@@ -302,10 +305,16 @@ func timeoutDecode(s string) (time.Duration, error) {
if !ok {
return 0, fmt.Errorf("timeout unit is not recognized: %q", s)
}
- t, err := strconv.ParseInt(s[:size-1], 10, 64)
+ t, err := strconv.ParseUint(s[:size-1], 10, 64)
if err != nil {
return 0, err
}
+ // Guard against overflowing time.Duration, which is an int64 nanosecond
+ // count: without this a large value wraps to a bogus (often negative)
+ // deadline instead of the long timeout the client asked for.
+ if t > uint64(math.MaxInt64)/uint64(d) {
+ return time.Duration(math.MaxInt64), nil
+ }
return d * time.Duration(t), nil
}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go
index 2e50082..2bb7c8f 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go
@@ -90,7 +90,7 @@ func Float32Slice(val, sep string) ([]float32, error) {
// Int64 converts the given string representation of an integer into int64.
func Int64(val string) (int64, error) {
- return strconv.ParseInt(val, 0, 64)
+ return strconv.ParseInt(val, 10, 64)
}
// Int64Slice converts 'val' where individual integers are separated by
@@ -110,7 +110,7 @@ func Int64Slice(val, sep string) ([]int64, error) {
// Int32 converts the given string representation of an integer into int32.
func Int32(val string) (int32, error) {
- i, err := strconv.ParseInt(val, 0, 32)
+ i, err := strconv.ParseInt(val, 10, 32)
if err != nil {
return 0, err
}
@@ -134,7 +134,7 @@ func Int32Slice(val, sep string) ([]int32, error) {
// Uint64 converts the given string representation of an integer into uint64.
func Uint64(val string) (uint64, error) {
- return strconv.ParseUint(val, 0, 64)
+ return strconv.ParseUint(val, 10, 64)
}
// Uint64Slice converts 'val' where individual integers are separated by
@@ -154,7 +154,7 @@ func Uint64Slice(val, sep string) ([]uint64, error) {
// Uint32 converts the given string representation of an integer into uint32.
func Uint32(val string) (uint32, error) {
- i, err := strconv.ParseUint(val, 0, 32)
+ i, err := strconv.ParseUint(val, 10, 32)
if err != nil {
return 0, err
}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go
index 3d07063..43b30f5 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "math"
"reflect"
"strconv"
@@ -311,6 +312,12 @@ func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions
// TODO(yugui) Should use proto.StructProperties?
return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
case float64:
+ // Enum values are int32 on the wire. A fractional or out-of-range
+ // number would otherwise be silently truncated/wrapped into a bogus
+ // enum here, unlike protojson which rejects it, so reject it too.
+ if v != math.Trunc(v) || v < math.MinInt32 || v > math.MaxInt32 {
+ return fmt.Errorf("%v is not a valid value for enum %T", repr, rv.Interface())
+ }
rv.Set(reflect.ValueOf(int32(v)).Convert(rv.Type()))
return nil
default:
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
index 69edf5e..3b4586b 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
@@ -158,7 +158,15 @@ func DefaultHeaderMatcher(key string) (string, bool) {
case isPermanentHTTPHeader(key):
return MetadataPrefix + key, true
case strings.HasPrefix(key, MetadataHeaderPrefix):
- return key[len(MetadataHeaderPrefix):], true
+ mdKey := key[len(MetadataHeaderPrefix):]
+ // The grpcgateway- namespace is reserved for permanent HTTP headers the
+ // gateway maps itself, so refuse to forward a Grpc-Metadata- header that
+ // strips into it. Otherwise Grpc-Metadata-grpcgateway-host lets a client
+ // inject a value indistinguishable from the gateway-set grpcgateway-host.
+ if strings.HasPrefix(strings.ToLower(mdKey), MetadataPrefix) {
+ return "", false
+ }
+ return mdKey, true
}
return "", false
}
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go
index e545071..48cab90 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go
@@ -196,6 +196,16 @@ func (p Pattern) MatchAndEscape(components []string, verb string, unescapingMode
return nil, ErrNotMatch
}
end -= p.tailLen
+ if pos > 0 && pos == end {
+ // A deep wildcard ("**") is allowed to match zero path segments when it is
+ // the first thing being matched in the pattern (pos == 0). But once a literal
+ // or variable segment has already consumed a component, "**" needs the request
+ // path to continue past that segment — it cannot succeed with nothing left to
+ // consume at all (though an empty trailing segment, e.g. from a trailing slash,
+ // still counts as a real component and is fine).
+ // See https://github.com/grpc-ecosystem/grpc-gateway/issues/5771.
+ return nil, ErrNotMatch
+ }
c := strings.Join(components[pos:end], "/")
if c, err = unescape(c, unescapingMode, true); err != nil {
return nil, err
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go
index 8549dfb..4f9221a 100644
--- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go
+++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go
@@ -16,6 +16,7 @@ import (
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/known/durationpb"
+ "google.golang.org/protobuf/types/known/emptypb"
field_mask "google.golang.org/protobuf/types/known/fieldmaskpb"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
@@ -224,7 +225,7 @@ func parseField(fieldDescriptor protoreflect.FieldDescriptor, value string) (pro
// Look for enum by name
v := enum.Descriptor().Values().ByName(protoreflect.Name(value))
if v == nil {
- i, err := strconv.Atoi(value)
+ i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value)
}
@@ -370,6 +371,14 @@ func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (p
return protoreflect.Value{}, err
}
msg = &v
+ case "google.protobuf.Empty":
+ // An Empty carries nothing, so the only thing the value can say is that the
+ // field is present. Accept the two spellings of "no content" and reject
+ // anything else, rather than silently ignoring it.
+ if value != "" && value != "{}" {
+ return protoreflect.Value{}, fmt.Errorf("expected an empty value or %q, got %q", "{}", value)
+ }
+ msg = &emptypb.Empty{}
default:
return protoreflect.Value{}, fmt.Errorf("unsupported message type: %q", string(msgDescriptor.FullName()))
}
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/filter.go b/vendor/github.com/jedib0t/go-pretty/v6/table/filter.go
index 7462cfc..b4b6f19 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/table/filter.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/filter.go
@@ -42,6 +42,11 @@ type FilterBy struct {
//
// Use this when the default filtering logic is not sufficient.
CustomFilter func(cellValue string) bool
+
+ // compiledRegex caches the compiled pattern for RegexMatch and
+ // RegexNotMatch; populated once by parseFilterBy instead of compiling
+ // the pattern again for every row
+ compiledRegex *regexp.Regexp
}
// FilterOperator defines how to filter.
@@ -91,12 +96,13 @@ func (t *Table) parseFilterBy(filterBy []FilterBy) []FilterBy {
}
if colNum > 0 {
resFilterBy = append(resFilterBy, FilterBy{
- Name: filter.Name,
- Number: colNum,
- Operator: filter.Operator,
- Value: filter.Value,
- IgnoreCase: filter.IgnoreCase,
- CustomFilter: filter.CustomFilter,
+ Name: filter.Name,
+ Number: colNum,
+ Operator: filter.Operator,
+ Value: filter.Value,
+ IgnoreCase: filter.IgnoreCase,
+ CustomFilter: filter.CustomFilter,
+ compiledRegex: compileFilterRegex(filter),
})
}
}
@@ -154,9 +160,9 @@ func (t *Table) matchesOperator(cellValue string, filter FilterBy) bool {
case EndsWith:
return t.compareEndsWith(cellValue, filter.Value, filter.IgnoreCase)
case RegexMatch:
- return t.compareRegexMatch(cellValue, filter.Value, filter.IgnoreCase)
+ return t.compareRegexMatch(cellValue, filter)
case RegexNotMatch:
- return !t.compareRegexMatch(cellValue, filter.Value, filter.IgnoreCase)
+ return !t.compareRegexMatch(cellValue, filter)
default:
return false
}
@@ -229,22 +235,33 @@ func (t *Table) compareEndsWith(cellValue string, filterValue interface{}, ignor
return strings.HasSuffix(cellValue, filterStr)
}
-func (t *Table) compareRegexMatch(cellValue string, filterValue interface{}, ignoreCase bool) bool {
- filterStr := fmt.Sprint(filterValue)
-
- // Compile the regex pattern
- var pattern *regexp.Regexp
- var err error
- if ignoreCase {
- pattern, err = regexp.Compile("(?i)" + filterStr)
- } else {
- pattern, err = regexp.Compile(filterStr)
+func (t *Table) compareRegexMatch(cellValue string, filter FilterBy) bool {
+ pattern := filter.compiledRegex
+ if pattern == nil {
+ pattern = compileFilterRegex(filter)
}
-
- if err != nil {
+ if pattern == nil {
// If regex compilation fails, fall back to simple string matching
- return t.compareEqual(cellValue, filterValue, ignoreCase)
+ return t.compareEqual(cellValue, filter.Value, filter.IgnoreCase)
}
return pattern.MatchString(cellValue)
}
+
+// compileFilterRegex compiles the pattern for a RegexMatch/RegexNotMatch
+// filter; returns nil for other operators or when the pattern is invalid.
+func compileFilterRegex(filter FilterBy) *regexp.Regexp {
+ if filter.Operator != RegexMatch && filter.Operator != RegexNotMatch {
+ return nil
+ }
+
+ filterStr := fmt.Sprint(filter.Value)
+ if filter.IgnoreCase {
+ filterStr = "(?i)" + filterStr
+ }
+ pattern, err := regexp.Compile(filterStr)
+ if err != nil {
+ return nil
+ }
+ return pattern
+}
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/render.go b/vendor/github.com/jedib0t/go-pretty/v6/table/render.go
index a1b6cfe..0e59bbf 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/table/render.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/render.go
@@ -107,7 +107,9 @@ func (t *Table) renderColumn(out *strings.Builder, row rowStr, colIdx int, maxCo
func (t *Table) renderColumnAutoIndex(out *strings.Builder, hint renderHint) {
var outAutoIndex strings.Builder
- outAutoIndex.Grow(t.maxColumnLengths[0])
+ if len(t.maxColumnLengths) > 0 {
+ outAutoIndex.Grow(t.maxColumnLengths[0])
+ }
if hint.isSeparatorRow {
numChars := t.autoIndexVIndexMaxLength + utf8.RuneCountInString(t.style.Box.PaddingLeft) +
@@ -268,7 +270,7 @@ func (t *Table) renderRow(out *strings.Builder, row rowStr, hint renderHint) {
// fit every column into the allowedColumnLength/maxColumnLength limit
// and in the process find the max. number of lines in any column in
// this row
- colMaxLines, rowWrapped := t.wrapRow(row)
+ colMaxLines, rowWrapped := t.wrapRow(row, hint)
// if there is just 1 line in all columns, add the row as such; else
// split each column into individual lines and render them one-by-one
@@ -311,9 +313,22 @@ func (t *Table) renderRowSeparator(out *strings.Builder, hint renderHint) {
}
func (t *Table) renderRows(out *strings.Builder, rows []rowStr, hint renderHint) {
- for rowIdx, row := range rows {
+ interleaveVerticalMerge := t.shouldInterleaveVerticalMerge(hint)
+ for rowIdx := 0; rowIdx < len(rows); rowIdx++ {
+ row := rows[rowIdx]
+
+ // stack rows that are being vertically merged into one shared block so
+ // the differing columns fill the merged cell's wrapped height instead
+ // of leaving blank lines below it (issue #261)
+ groupEnd := rowIdx + 1
+ if interleaveVerticalMerge {
+ if groupEnd = t.verticalMergeGroupEnd(rows, rowIdx); groupEnd > rowIdx+1 {
+ row = t.combineVerticalMergeGroup(rows, rowIdx, groupEnd)
+ }
+ }
+
hint.isFirstRow = rowIdx == 0
- hint.isLastRow = rowIdx == len(rows)-1
+ hint.isLastRow = groupEnd == len(rows)
hint.rowNumber = rowIdx + 1
t.renderRow(out, row, hint)
@@ -330,6 +345,9 @@ func (t *Table) renderRows(out *strings.Builder, rows []rowStr, hint renderHint)
}
t.renderRowSeparator(out, hintSep)
}
+
+ // skip the rows that were stacked into the block rendered above
+ rowIdx = groupEnd - 1
}
}
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/render_csv.go b/vendor/github.com/jedib0t/go-pretty/v6/table/render_csv.go
index 8974565..eac5824 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/table/render_csv.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/render_csv.go
@@ -10,7 +10,7 @@ import (
//
// #,First Name,Last Name,Salary,
// 1,Arya,Stark,3000,
-// 20,Jon,Snow,2000,"You know nothing\, Jon Snow!"
+// 20,Jon,Snow,2000,"You know nothing, Jon Snow!"
// 300,Tyrion,Lannister,5000,
// ,,Total,10000,
func (t *Table) RenderCSV() string {
@@ -18,6 +18,7 @@ func (t *Table) RenderCSV() string {
var out strings.Builder
if t.numColumns > 0 {
+ out.Grow(t.estimatedRenderLength())
if t.title != "" {
out.WriteString(t.title)
}
@@ -35,12 +36,21 @@ func (t *Table) RenderCSV() string {
return t.render(&out)
}
-func (t *Table) csvFixCommas(str string) string {
- return strings.ReplaceAll(str, ",", "\\,")
+// csvEscapeDoubleQuotes escapes double-quotes inside a quoted field by
+// doubling them, as mandated by RFC 4180.
+func (t *Table) csvEscapeDoubleQuotes(str string) string {
+ return strings.ReplaceAll(str, "\"", "\"\"")
}
-func (t *Table) csvFixDoubleQuotes(str string) string {
- return strings.ReplaceAll(str, "\"", "\\\"")
+// csvProtectField neutralizes fields that spreadsheet applications would
+// interpret as formulas (=, +, -, @, tab or CR prefix) by prefixing them with
+// a single-quote.
+func (t *Table) csvProtectField(str string) string {
+ switch str[0] {
+ case '=', '+', '-', '@', '\t', '\r':
+ return "'" + str
+ }
+ return str
}
func (t *Table) csvRenderRow(out *strings.Builder, row rowStr, hint renderHint) {
@@ -61,9 +71,12 @@ func (t *Table) csvRenderRow(out *strings.Builder, row rowStr, hint renderHint)
if colIdx > 0 {
out.WriteRune(',')
}
+ if t.style.CSV.FieldProtection && colStr != "" {
+ colStr = t.csvProtectField(colStr)
+ }
if strings.ContainsAny(colStr, "\",\n") {
out.WriteRune('"')
- out.WriteString(t.csvFixCommas(t.csvFixDoubleQuotes(colStr)))
+ out.WriteString(t.csvEscapeDoubleQuotes(colStr))
out.WriteRune('"')
} else if utf8.RuneCountInString(colStr) > 0 {
out.WriteString(colStr)
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/render_html.go b/vendor/github.com/jedib0t/go-pretty/v6/table/render_html.go
index 07b1850..e138faf 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/table/render_html.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/render_html.go
@@ -64,11 +64,12 @@ func (t *Table) RenderHTML() string {
var out strings.Builder
if t.numColumns > 0 {
+ out.Grow(t.estimatedRenderLength())
out.WriteString("
\n")
t.htmlRenderTitle(&out)
@@ -99,8 +100,12 @@ func (t *Table) htmlGetColStrAndTag(row rowStr, colIdx int, hint renderHint) (st
func (t *Table) htmlRenderCaption(out *strings.Builder) {
if t.caption != "" {
+ caption := t.caption
+ if t.style.HTML.EscapeText {
+ caption = html.EscapeString(caption)
+ }
out.WriteString(" ")
- out.WriteString(t.caption)
+ out.WriteString(caption)
out.WriteString("\n")
}
}
@@ -263,6 +268,9 @@ func (t *Table) htmlRenderTitle(out *strings.Builder) {
align := t.style.Title.Align.HTMLProperty()
colors := t.style.Title.Colors.HTMLProperty()
title := t.style.Title.Format.Apply(t.title)
+ if t.style.HTML.EscapeText {
+ title = html.EscapeString(title)
+ }
out.WriteString(" 0 {
+ out.Grow(t.estimatedRenderLength())
t.markdownRenderTitle(&out)
t.markdownRenderRowsHeader(&out)
t.markdownRenderRows(&out, t.rows, renderHint{})
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/render_tsv.go b/vendor/github.com/jedib0t/go-pretty/v6/table/render_tsv.go
index 9e0c4dd..81022d9 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/table/render_tsv.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/render_tsv.go
@@ -11,6 +11,7 @@ func (t *Table) RenderTSV() string {
var out strings.Builder
if t.numColumns > 0 {
+ out.Grow(t.estimatedRenderLength())
if t.title != "" {
out.WriteString(t.title)
}
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/style.go b/vendor/github.com/jedib0t/go-pretty/v6/table/style.go
index 0b2473d..0e2058a 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/table/style.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/style.go
@@ -6,6 +6,7 @@ type Style struct {
Name string // name of the Style
Box BoxStyle // characters to use for the boxes
Color ColorOptions // colors to use for the rows and columns
+ CSV CSVOptions // rendering options for CSV mode
Format FormatOptions // formatting options for the rows and columns
HTML HTMLOptions // rendering options for HTML mode
Markdown MarkdownOptions // rendering options for Markdown mode
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/style_csv.go b/vendor/github.com/jedib0t/go-pretty/v6/table/style_csv.go
new file mode 100644
index 0000000..dc24865
--- /dev/null
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/style_csv.go
@@ -0,0 +1,19 @@
+package table
+
+// CSVOptions defines options to control CSV rendering.
+type CSVOptions struct {
+ // FieldProtection neutralizes fields that spreadsheet applications could
+ // interpret as formulas (fields beginning with =, +, -, @, tab or CR) by
+ // prefixing them with a single-quote, preventing CSV formula injection
+ // when the rendered output is opened in such an application.
+ //
+ // Note that the single-quote becomes part of the field content for
+ // standards-compliant CSV readers; enable this only when the output is
+ // destined for a spreadsheet application.
+ FieldProtection bool
+}
+
+var (
+ // DefaultCSVOptions defines sensible CSV rendering defaults.
+ DefaultCSVOptions = CSVOptions{}
+)
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/table/table.go b/vendor/github.com/jedib0t/go-pretty/v6/table/table.go
index 02d4092..bf1af4d 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/table/table.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/table/table.go
@@ -812,6 +812,13 @@ func (t *Table) isIndexColumn(colIdx int, hint renderHint) bool {
return t.indexColumn == colIdx+1 || hint.isAutoIndexColumn
}
+// estimatedRenderLength approximates the rendered output size, to pre-size
+// the output builder and avoid repeated re-allocations while rendering.
+func (t *Table) estimatedRenderLength() int {
+ numRows := len(t.rows) + len(t.rowsHeader) + len(t.rowsFooter) + 1
+ return numRows * (t.maxRowLength + 1)
+}
+
func (t *Table) render(out *strings.Builder) string {
outStr := out.String()
if t.suppressTrailingSpaces {
@@ -940,20 +947,187 @@ func (t *Table) shouldSeparateRows(rowIdx int, numRows int) bool {
return true
}
-func (t *Table) wrapRow(row rowStr) (int, rowStr) {
+// wrapCell fits a single column's value into its width limit (WidthMax, or the
+// column's longest line when no limit is set) using the column's enforcer.
+func (t *Table) wrapCell(colIdx int, colStr string) string {
+ widthEnforcer := t.columnConfigMap[colIdx].getWidthMaxEnforcer()
+ maxWidth := t.getColumnWidthMax(colIdx)
+ if maxWidth == 0 {
+ maxWidth = t.maxColumnLengths[colIdx]
+ }
+ return widthEnforcer(colStr, maxWidth)
+}
+
+func (t *Table) wrapRow(row rowStr, hint renderHint) (int, rowStr) {
colMaxLines := 0
rowWrapped := make(rowStr, len(row))
for colIdx, colStr := range row {
- widthEnforcer := t.columnConfigMap[colIdx].getWidthMaxEnforcer()
- maxWidth := t.getColumnWidthMax(colIdx)
- if maxWidth == 0 {
- maxWidth = t.maxColumnLengths[colIdx]
+ rowWrapped[colIdx] = t.wrapCell(colIdx, colStr)
+ // a cell that is being merged into the one above renders empty in this
+ // row, so its (possibly wrapped) height must not stretch the row and
+ // leave blank lines trailing the merged content; see issue #261
+ if t.shouldMergeCellsVerticallyAbove(colIdx, hint) {
+ continue
}
- rowWrapped[colIdx] = widthEnforcer(colStr, maxWidth)
colNumLines := strings.Count(rowWrapped[colIdx], "\n") + 1
if colNumLines > colMaxLines {
colMaxLines = colNumLines
}
}
+ if colMaxLines == 0 {
+ // every column merged into the row above; keep one (blank) line so the
+ // row still occupies its place
+ colMaxLines = 1
+ }
return colMaxLines, rowWrapped
}
+
+// shouldInterleaveVerticalMerge reports whether consecutive body rows that are
+// being vertically merged (ColumnConfig.AutoMerge) may be rendered as a single
+// shared block. Doing so lets the differing columns stack into the merged
+// cell's wrapped height instead of leaving blank lines below it (issue #261).
+//
+// It is intentionally restricted to the plain, unambiguous case - no row
+// separators, auto-index, or per-row coloring - so it never alters any other
+// layout and falls back to the regular row-by-row rendering everywhere else.
+func (t *Table) shouldInterleaveVerticalMerge(hint renderHint) bool {
+ if hint.isHeaderRow || hint.isFooterRow {
+ return false
+ }
+ if t.style.Options.SeparateRows || len(t.separators) > 0 {
+ return false
+ }
+ if t.autoIndex || t.pager.size > 0 {
+ return false
+ }
+ if t.rowPainter != nil || t.rowPainterWithAttributes != nil || t.style.Color.RowAlternate != nil {
+ return false
+ }
+ for colIdx := 0; colIdx < t.numColumns; colIdx++ {
+ if t.columnConfigMap[colIdx].AutoMerge {
+ return true
+ }
+ }
+ return false
+}
+
+// verticalMergeGroupEnd returns the exclusive end index of the maximal run of
+// rows starting at "start" that can be stacked into a single block: rows that
+// carry the same config and each add just one line, so they slot into the
+// wrapped height of the merged cell(s) spanning them.
+func (t *Table) verticalMergeGroupEnd(rows []rowStr, start int) int {
+ if !t.rowVerticallyStackable(rows[start]) {
+ return start + 1
+ }
+ end := start + 1
+ for end < len(rows) {
+ if t.rowsConfigMap[start] != t.rowsConfigMap[end] {
+ break
+ }
+ if !t.rowStacksBelow(rows[end-1], rows[end]) {
+ break
+ }
+ end++
+ }
+ return end
+}
+
+// rowVerticallyStackable reports whether a row's non-merged cells each render on
+// a single line, so it occupies a single line when stacked (a merged cell may
+// still wrap - it provides the vertical space the stacked rows slot into).
+func (t *Table) rowVerticallyStackable(row rowStr) bool {
+ for colIdx := 0; colIdx < t.numColumns && colIdx < len(row); colIdx++ {
+ if t.columnConfigMap[colIdx].AutoMerge {
+ continue
+ }
+ if t.cellWraps(colIdx, row[colIdx]) {
+ return false
+ }
+ }
+ return true
+}
+
+// rowStacksBelow reports whether "cur" can be stacked right below "prev" within
+// a shared merge block, i.e. it adds exactly one line. A merged column that
+// keeps its value simply continues the cell above; any column that changes must
+// fit on a single line (and a merged column that changes must also have left
+// its previous value on a single line, else its wrapped height would not line
+// up with the stacked rows).
+func (t *Table) rowStacksBelow(prev, cur rowStr) bool {
+ for colIdx := 0; colIdx < t.numColumns; colIdx++ {
+ prevVal, curVal := "", ""
+ if colIdx < len(prev) {
+ prevVal = prev[colIdx]
+ }
+ if colIdx < len(cur) {
+ curVal = cur[colIdx]
+ }
+ merged := t.columnConfigMap[colIdx].AutoMerge
+ if merged && curVal == prevVal {
+ continue
+ }
+ if t.cellWraps(colIdx, curVal) {
+ return false
+ }
+ if merged && t.cellWraps(colIdx, prevVal) {
+ return false
+ }
+ }
+ return true
+}
+
+// cellWraps reports whether a column's value renders on more than one line.
+func (t *Table) cellWraps(colIdx int, colStr string) bool {
+ return strings.Contains(t.wrapCell(colIdx, colStr), "\n")
+}
+
+// combineVerticalMergeGroup collapses rows[start:end] into a single row. A
+// merged column that never changes keeps its single (spanning) value; every
+// other column stacks the rows' values one below the other, blanking a merged
+// value that repeats so it still reads as one vertically merged cell.
+func (t *Table) combineVerticalMergeGroup(rows []rowStr, start, end int) rowStr {
+ combined := make(rowStr, t.numColumns)
+ for colIdx := 0; colIdx < t.numColumns; colIdx++ {
+ if t.columnConfigMap[colIdx].AutoMerge && t.mergedColumnIsConstant(rows, start, end, colIdx) {
+ if colIdx < len(rows[start]) {
+ combined[colIdx] = rows[start][colIdx]
+ }
+ continue
+ }
+ lines := make([]string, 0, end-start)
+ prevCell := ""
+ for rowIdx := start; rowIdx < end; rowIdx++ {
+ cell := ""
+ if colIdx < len(rows[rowIdx]) {
+ cell = rows[rowIdx][colIdx]
+ }
+ line := cell
+ if t.columnConfigMap[colIdx].AutoMerge && rowIdx > start && cell == prevCell {
+ line = ""
+ }
+ prevCell = cell
+ lines = append(lines, line)
+ }
+ combined[colIdx] = strings.Join(lines, "\n")
+ }
+ return combined
+}
+
+// mergedColumnIsConstant reports whether a merged column holds the same value
+// across every row in rows[start:end].
+func (t *Table) mergedColumnIsConstant(rows []rowStr, start, end, colIdx int) bool {
+ first := ""
+ if colIdx < len(rows[start]) {
+ first = rows[start][colIdx]
+ }
+ for rowIdx := start + 1; rowIdx < end; rowIdx++ {
+ val := ""
+ if colIdx < len(rows[rowIdx]) {
+ val = rows[rowIdx][colIdx]
+ }
+ if val != first {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/align.go b/vendor/github.com/jedib0t/go-pretty/v6/text/align.go
index 18cc59e..0169b91 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/text/align.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/text/align.go
@@ -1,10 +1,8 @@
package text
import (
- "fmt"
"strconv"
"strings"
- "unicode/utf8"
)
// Align denotes how text is to be aligned horizontally.
@@ -39,24 +37,39 @@ func (a Align) Apply(text string, maxLength int) string {
}
text = aComputed.trimString(text)
- sLen := utf8.RuneCountInString(text)
sLenWoE := StringWidthWithoutEscSequences(text)
- numEscChars := sLen - sLenWoE
+ padding := maxLength - sLenWoE
- // now, align the text
+ // now, align the text by padding the missing display-width with spaces
switch aComputed {
case AlignDefault, AlignLeft:
- return fmt.Sprintf("%-"+strconv.Itoa(maxLength+numEscChars)+"s", text)
+ return padText(text, 0, padding)
case AlignCenter:
- if sLenWoE < maxLength {
- // left pad with half the number of spaces needed before using %text
- return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s",
- text+strings.Repeat(" ", (maxLength-sLenWoE)/2))
- }
+ // extra space on the left when the padding is odd
+ return padText(text, padding-padding/2, padding/2)
case AlignJustify:
return justifyText(text, sLenWoE, maxLength)
}
- return fmt.Sprintf("%"+strconv.Itoa(maxLength+numEscChars)+"s", text)
+ return padText(text, padding, 0)
+}
+
+// padText returns the text with the given number of spaces on either side;
+// non-positive counts add nothing.
+func padText(text string, left int, right int) string {
+ if left <= 0 && right <= 0 {
+ return text
+ }
+
+ var out strings.Builder
+ out.Grow(len(text) + left + right)
+ for idx := 0; idx < left; idx++ {
+ out.WriteByte(' ')
+ }
+ out.WriteString(text)
+ for idx := 0; idx < right; idx++ {
+ out.WriteByte(' ')
+ }
+ return out.String()
}
// HTMLProperty returns the equivalent HTML horizontal-align tag property.
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go b/vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go
index 66edae6..2444498 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/text/escape_seq_parser.go
@@ -1,10 +1,12 @@
package text
import (
+ "bytes"
"fmt"
"sort"
"strconv"
"strings"
+ "unicode/utf8"
)
// Constants
@@ -64,6 +66,18 @@ const (
// conceal OSI sequences
escapeStartConcealOSI = "\x1b]8;"
escapeStopConcealOSI = "\x1b\\"
+
+ // escSeqMaxLength bounds the accumulated escape sequence; real terminals
+ // cap sequences in the low KBs, and anything longer here is most likely
+ // malformed input that would otherwise grow the buffer without limit
+ escSeqMaxLength = 2048
+)
+
+// []byte forms of the conceal OSI markers for prefix/suffix checks on the
+// escape sequence buffer without allocating per call
+var (
+ escapeStartConcealOSIBytes = []byte(escapeStartConcealOSI)
+ escapeStopConcealOSIBytes = []byte(escapeStopConcealOSI)
)
// 256-color codes
@@ -117,8 +131,9 @@ type EscSeqParser struct {
inEscSeq bool
// escSeqKind identifies the type of escape sequence being parsed (CSI or OSI).
escSeqKind escSeqKind
- // escapeSeq accumulates the current escape sequence being parsed.
- escapeSeq string
+ // escapeSeq accumulates the current escape sequence being parsed; it is
+ // bounded by escSeqMaxLength and reused across sequences.
+ escapeSeq []byte
}
func (s *EscSeqParser) Codes() []int {
@@ -136,7 +151,7 @@ func (s *EscSeqParser) Consume(char rune) {
if !s.inEscSeq && char == EscapeStartRune {
s.inEscSeq = true
s.escSeqKind = escSeqKindUnknown
- s.escapeSeq = ""
+ s.escapeSeq = s.escapeSeq[:0]
} else if s.inEscSeq && s.escSeqKind == escSeqKindUnknown {
switch char {
case EscapeStartRuneCSI:
@@ -147,20 +162,27 @@ func (s *EscSeqParser) Consume(char rune) {
}
if s.inEscSeq {
- s.escapeSeq += string(char)
+ s.escapeSeq = utf8.AppendRune(s.escapeSeq, char)
+
+ // abort on absurdly long (most likely malformed/unterminated)
+ // sequences instead of accumulating them without limit
+ if len(s.escapeSeq) > escSeqMaxLength {
+ s.Reset()
+ return
+ }
// --- FIX for OSC 8 hyperlinks (e.g. \x1b]8;;url\x07label\x1b]8;;\x07)
if s.escSeqKind == escSeqKindOSI &&
- strings.HasPrefix(s.escapeSeq, escapeStartConcealOSI) &&
+ bytes.HasPrefix(s.escapeSeq, escapeStartConcealOSIBytes) &&
char == escRuneBEL { // BEL
- s.ParseSeq(s.escapeSeq, s.escSeqKind)
+ s.ParseSeq(string(s.escapeSeq), s.escSeqKind)
s.Reset()
return
}
if s.isEscapeStopRune(char) {
- s.ParseSeq(s.escapeSeq, s.escSeqKind)
+ s.ParseSeq(string(s.escapeSeq), s.escSeqKind)
s.Reset()
}
}
@@ -186,7 +208,7 @@ func (s *EscSeqParser) ParseSeq(seq string, seqKind escSeqKind) {
}
func (s *EscSeqParser) ParseString(str string) string {
- s.escapeSeq, s.inEscSeq, s.escSeqKind = "", false, escSeqKindUnknown
+ s.escapeSeq, s.inEscSeq, s.escSeqKind = s.escapeSeq[:0], false, escSeqKindUnknown
for _, char := range str {
s.Consume(char)
}
@@ -196,7 +218,7 @@ func (s *EscSeqParser) ParseString(str string) string {
func (s *EscSeqParser) Reset() {
s.inEscSeq = false
s.escSeqKind = escSeqKindUnknown
- s.escapeSeq = ""
+ s.escapeSeq = s.escapeSeq[:0]
}
func (s *EscSeqParser) Sequence() string {
@@ -275,8 +297,8 @@ func (s *EscSeqParser) clearColorRange(isForeground bool) {
}
func (s *EscSeqParser) isEscapeStopRune(char rune) bool {
- if strings.HasPrefix(s.escapeSeq, escapeStartConcealOSI) {
- if strings.HasSuffix(s.escapeSeq, escapeStopConcealOSI) {
+ if bytes.HasPrefix(s.escapeSeq, escapeStartConcealOSIBytes) {
+ if bytes.HasSuffix(s.escapeSeq, escapeStopConcealOSIBytes) {
return true
}
} else if (s.escSeqKind == escSeqKindCSI && char == EscapeStopRuneCSI) ||
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/hyperlink.go b/vendor/github.com/jedib0t/go-pretty/v6/text/hyperlink.go
index 00a551a..48952c2 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/text/hyperlink.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/text/hyperlink.go
@@ -1,8 +1,12 @@
package text
-import "fmt"
+import (
+ "fmt"
+ "strings"
+)
func Hyperlink(url, text string) string {
+ url = sanitizeHyperlinkURL(url)
if url == "" {
return text
}
@@ -12,3 +16,15 @@ func Hyperlink(url, text string) string {
// source https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
return fmt.Sprintf("\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\", url, text)
}
+
+// sanitizeHyperlinkURL strips ASCII control characters (including ESC and BEL)
+// from the URL; left in place, they could terminate the OSC 8 sequence early
+// and inject arbitrary escape sequences into the terminal output.
+func sanitizeHyperlinkURL(url string) string {
+ return strings.Map(func(r rune) rune {
+ if r < 0x20 || r == 0x7f {
+ return -1
+ }
+ return r
+ }, url)
+}
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/string.go b/vendor/github.com/jedib0t/go-pretty/v6/text/string.go
index fa3e4f1..7902b0e 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/text/string.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/text/string.go
@@ -263,6 +263,15 @@ func StringWidth(str string) int {
// StringWidthWithoutEscSequences("Ghost 生命"): 10
// StringWidthWithoutEscSequences("\x1b[33mGhost 生命\x1b[0m"): 10
func StringWidthWithoutEscSequences(str string) int {
+ // fast-path the common case of a string without escape sequences
+ if !strings.ContainsRune(str, EscapeStartRune) {
+ count := 0
+ for _, c := range str {
+ count += RuneWidth(c)
+ }
+ return count
+ }
+
count, esp := 0, EscSeqParser{}
for _, c := range str {
if esp.InSequence() {
@@ -277,13 +286,16 @@ func StringWidthWithoutEscSequences(str string) int {
return count
}
-// Trim trims a string to the given length while ignoring escape sequences. For
-// ex.:
+// Trim trims a string to the given display width (maxLen columns) while
+// ignoring escape sequences. Wide East Asian characters count as two columns,
+// so the result never exceeds maxLen columns. For ex.:
//
// Trim("Ghost", 3) == "Gho"
// Trim("Ghost", 6) == "Ghost"
// Trim("\x1b[33mGhost\x1b[0m", 3) == "\x1b[33mGho\x1b[0m"
// Trim("\x1b[33mGhost\x1b[0m", 6) == "\x1b[33mGhost\x1b[0m"
+// Trim("生命生命", 3) == "生"
+// Trim("生命生命", 4) == "生命"
func Trim(str string, maxLen int) string {
if maxLen <= 0 {
return ""
@@ -292,7 +304,7 @@ func Trim(str string, maxLen int) string {
var out strings.Builder
out.Grow(maxLen)
- outLen, esp := 0, EscSeqParser{}
+ outLen, full, esp := 0, false, EscSeqParser{}
for _, sChr := range str {
if esp.InSequence() {
esp.Consume(sChr)
@@ -304,10 +316,17 @@ func Trim(str string, maxLen int) string {
out.WriteRune(sChr)
continue
}
- if outLen < maxLen {
- outLen++
- out.WriteRune(sChr)
- continue
+ // Count the display width of the rune (wide East Asian characters
+ // occupy two columns) instead of counting runes, so the result never
+ // exceeds maxLen columns. Once a rune no longer fits, stop emitting
+ // visible runes but keep copying any trailing escape sequences.
+ if !full {
+ if w := RuneWidth(sChr); outLen+w <= maxLen {
+ outLen += w
+ out.WriteRune(sChr)
+ continue
+ }
+ full = true
}
}
return out.String()
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/valign.go b/vendor/github.com/jedib0t/go-pretty/v6/text/valign.go
index 8e086d9..9862590 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/text/valign.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/text/valign.go
@@ -27,6 +27,10 @@ func (va VAlign) Apply(lines []string, maxLines int) []string {
maxLines = len(lines)
}
+ if maxLines < 1 { // no lines and a negative maxLines
+ return lines
+ }
+
var insertIdx int
switch va {
case VAlignMiddle:
diff --git a/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go b/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go
index b9ff842..962085c 100644
--- a/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go
+++ b/vendor/github.com/jedib0t/go-pretty/v6/text/wrap.go
@@ -122,7 +122,7 @@ func appendWord(word string, lineIdx *int, lastSeenEscSeq string, wrapLen int, o
inEscSeq = true
lastSeenEscSeq = ""
}
- if inEscSeq {
+ if inEscSeq && len(lastSeenEscSeq) < escSeqMaxLength {
lastSeenEscSeq += string(char)
}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go
index 6b958fd..c2e0946 100644
--- a/vendor/github.com/mattn/go-runewidth/runewidth.go
+++ b/vendor/github.com/mattn/go-runewidth/runewidth.go
@@ -4,6 +4,8 @@ import (
"os"
"sort"
"strings"
+ "sync"
+ "sync/atomic"
"unicode/utf8"
"github.com/clipperhouse/uax29/v2/graphemes"
@@ -18,6 +20,14 @@ var (
// StrictEmojiNeutral should be set false if handle broken fonts
StrictEmojiNeutral bool = true
+ // ZeroWidthJoiner is flag to set to use UTR#51 ZWJ.
+ //
+ // Deprecated: ZWJ sequences are always handled through Unicode
+ // grapheme cluster segmentation now, so this flag has no effect.
+ // It is kept only for compatibility with code written against
+ // v0.0.9 and earlier.
+ ZeroWidthJoiner bool
+
// DefaultCondition is a condition in current locale
DefaultCondition = &Condition{
EastAsianWidth: false,
@@ -26,20 +36,87 @@ var (
)
var (
- zerowidth table // combining + nonprint merged for faster zero-width lookup
- widewidth table // ambiguous + doublewidth merged for EA path
- eastAsianWidth widthTable
- eastAsianWidth0 [0x300]byte
+ zerowidth table // combining + nonprint merged for faster zero-width lookup
+ widewidth table // ambiguous + doublewidth merged for EA path
+ eastAsianWidth widthTable
+ tablesOnce sync.Once
+
+ // strictWidthLUT is mostly built lazily on the first width lookup so
+ // that importing the package costs neither the build time nor the 2 MB
+ // of resident memory; see issue #104. Only the entries below
+ // strictWidthLUTLimit are valid: init fills the first 0x300 entries of
+ // both planes, and the lazy build fills the rest — never rewriting the
+ // low region, so readers of it cannot race with the build. The limit
+ // is loaded with acquire semantics, which makes the non-atomic reads
+ // of the high region safe once it reports 0x110000. Keeping the whole
+ // check down to one compare-and-branch matters: RuneWidth is only a
+ // dozen instructions long.
+ strictWidthLUT [2][0x110000]byte
+ strictWidthLUTLimit atomic.Int32
+ strictWidthLUTOnce sync.Once
+
+ // joinerBits is the joiner table as a bitmap over
+ // [joinerBase, 0x10000), the range where the per-rune test has to be
+ // cheap for the fast paths in StringWidth and Wrap to pay off. It is
+ // 7.6 KB and init fills it in a few microseconds. Runes above it stay
+ // on the interval search: they are rare in the text these fast paths
+ // are for, and the emoji that are common there leave the fast path at
+ // their first joiner anyway.
+ joinerBits [(0x10000 - joinerBase) / 8]byte
)
+// joinerBase is the lowest rune in the joiner table. CR is the only rune
+// below it that can form a multi-rune cluster, by pairing with LF.
+const joinerBase = 0x300
+
func init() {
+ initStrictWidthLUTLow()
+ fillJoinerBits()
+ strictWidthLUTLimit.Store(0x300)
+ handleEnv()
+}
+
+// initStrictWidthLUTLow paints the first 0x300 entries of strictWidthLUT
+// from the static interval tables. The result must stay identical to
+// runeWidthNoLUT for runes below 0x300, which TestStrictWidthLUT verifies.
+func initStrictWidthLUTLow() {
+ for i := 0; i < 0x300; i++ {
+ r := rune(i)
+ w := byte(1)
+ if r < 0x20 || (r >= 0x7F && r <= 0x9F) || r == 0xAD { // nonprint
+ w = 0
+ }
+ strictWidthLUT[0][i] = w
+ }
+
+ ea := strictWidthLUT[1][:0x300]
+ fillBytes(ea, 1)
+ paint := func(t table, w byte) {
+ for _, iv := range t {
+ if iv.first >= 0x300 {
+ break
+ }
+ last := iv.last
+ if last > 0x2FF {
+ last = 0x2FF
+ }
+ fillBytes(ea[iv.first:last+1], w)
+ }
+ }
+ paint(ambiguous, 2)
+ paint(doublewidth, 2)
+ // zero-width wins over wide on overlap, so paint it last.
+ paint(combining, 0)
+ paint(nonprint, 0)
+}
+
+// initTables builds the merged lookup tables. It runs lazily through
+// tablesOnce so that merely importing the package stays cheap; see issue
+// #104.
+func initTables() {
zerowidth = mergeIntervals(combining, nonprint)
widewidth = mergeIntervals(ambiguous, doublewidth)
eastAsianWidth = makeWidthTable(zerowidth, widewidth)
- for r := range eastAsianWidth0 {
- eastAsianWidth0[r] = byte(runeWidthEastAsian(rune(r)))
- }
- handleEnv()
}
func mergeIntervals(t1, t2 table) table {
@@ -84,7 +161,6 @@ func handleEnv() {
if DefaultCondition.EastAsianWidth != EastAsianWidth {
DefaultCondition.EastAsianWidth = EastAsianWidth
if len(DefaultCondition.combinedLut) > 0 {
- DefaultCondition.combinedLut = DefaultCondition.combinedLut[:0]
CreateLUT()
}
}
@@ -189,13 +265,96 @@ func inWidthTable(r rune, t widthTable) (int, bool) {
return 0, false
}
-func runeWidthEastAsian(r rune) int {
+func runeWidthNoLUT(r rune, eastAsian, strictEmojiNeutral bool) int {
+ tablesOnce.Do(initTables)
+ if !eastAsian {
+ if r < 0x20 {
+ return 0
+ }
+ if (r >= 0x7F && r <= 0x9F) || r == 0xAD { // nonprint
+ return 0
+ }
+ if r < 0x300 {
+ return 1
+ }
+ switch {
+ case inTable(r, zerowidth):
+ return 0
+ case inTable(r, doublewidth):
+ return 2
+ default:
+ return 1
+ }
+ }
+
+ if r < 0x300 {
+ return int(strictWidthLUT[1][r])
+ }
if w, ok := inWidthTable(r, eastAsianWidth); ok {
return w
}
+ if !strictEmojiNeutral && inTable(r, emoji) {
+ return 2
+ }
return 1
}
+// fillBytes sets every byte of b to v. It doubles the copied region on each
+// iteration so large slices are filled at memcpy speed instead of one byte
+// per loop iteration.
+func fillBytes(b []byte, v byte) {
+ if len(b) == 0 {
+ return
+ }
+ b[0] = v
+ for i := 1; i < len(b); i *= 2 {
+ copy(b[i:], b[:i])
+ }
+}
+
+// buildStrictWidthLUT builds the strict-width lookup table above 0x300
+// exactly once. It paints whole intervals instead of computing every rune
+// through the binary searches in runeWidthNoLUT. It must not write below
+// 0x300: that region was filled by init and may be read concurrently. The
+// result must stay identical to runeWidthNoLUT(r, eastAsian, true), which
+// TestStrictWidthLUT verifies.
+func buildStrictWidthLUT() {
+ strictWidthLUTOnce.Do(func() {
+ tablesOnce.Do(initTables)
+
+ // paintHigh fills lut with w over each interval, clipped to 0x300+.
+ paintHigh := func(lut []byte, first, last rune, w byte) {
+ if first < 0x300 {
+ if last < 0x300 {
+ return
+ }
+ first = 0x300
+ }
+ fillBytes(lut[first:last+1], w)
+ }
+
+ // EastAsianWidth=false, StrictEmojiNeutral=true
+ lut := strictWidthLUT[0][:]
+ fillBytes(lut[0x300:], 1)
+ for _, iv := range doublewidth {
+ paintHigh(lut, iv.first, iv.last, 2)
+ }
+ // zerowidth is checked before doublewidth, so it wins on overlap.
+ for _, iv := range zerowidth {
+ paintHigh(lut, iv.first, iv.last, 0)
+ }
+
+ // EastAsianWidth=true, StrictEmojiNeutral=true
+ lut = strictWidthLUT[1][:]
+ fillBytes(lut[0x300:], 1)
+ for _, iv := range eastAsianWidth {
+ paintHigh(lut, iv.first, iv.last, iv.width)
+ }
+
+ strictWidthLUTLimit.Store(0x110000)
+ })
+}
+
var private = table{
{0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
}
@@ -209,9 +368,20 @@ var nonprint = table{
// Condition have flag EastAsianWidth whether the current locale is CJK or not.
type Condition struct {
- combinedLut []byte
+ combinedLut []byte
+ // The flags combinedLut was built from, so that CreateLUT can tell a
+ // table that is still current from one that has to be rebuilt.
+ lutEastAsianWidth bool
+ lutStrictEmojiNeutral bool
+
EastAsianWidth bool
StrictEmojiNeutral bool
+
+ // Deprecated: ZWJ sequences are always handled through Unicode
+ // grapheme cluster segmentation now, so this flag has no effect.
+ // It is kept only for compatibility with code written against
+ // v0.0.9 and earlier.
+ ZeroWidthJoiner bool
}
// NewCondition return new instance of Condition which is current locale.
@@ -219,49 +389,47 @@ func NewCondition() *Condition {
return &Condition{
EastAsianWidth: EastAsianWidth,
StrictEmojiNeutral: StrictEmojiNeutral,
+ ZeroWidthJoiner: ZeroWidthJoiner,
}
}
// RuneWidth returns the number of cells in r.
// See http://www.unicode.org/reports/tr11/
func (c *Condition) RuneWidth(r rune) int {
- if r < 0 || r > 0x10FFFF {
- return 0
+ // This one compare doubles as the range check and the lazy-LUT check:
+ // out-of-range runes and runes above the built portion of
+ // strictWidthLUT both take the slow path. Once the LUT is fully built
+ // the limit is 0x110000 and only invalid runes go slow.
+ if uint32(r) >= uint32(strictWidthLUTLimit.Load()) {
+ return c.runeWidthSlow(r)
}
if len(c.combinedLut) > 0 {
return int(c.combinedLut[r>>1]>>(uint(r&1)*4)) & 3
}
- // optimized version, verified by TestRuneWidthChecksums()
- if !c.EastAsianWidth {
- if r < 0x20 {
- return 0
- }
- if (r >= 0x7F && r <= 0x9F) || r == 0xAD { // nonprint
- return 0
- }
- if r < 0x300 {
- return 1
- }
- switch {
- case inTable(r, zerowidth):
- return 0
- case inTable(r, doublewidth):
- return 2
- default:
- return 1
+ if c.StrictEmojiNeutral {
+ if c.EastAsianWidth {
+ return int(strictWidthLUT[1][r])
}
+ return int(strictWidthLUT[0][r])
}
+ return runeWidthNoLUT(r, c.EastAsianWidth, c.StrictEmojiNeutral)
+}
- if r < 0x300 {
- return int(eastAsianWidth0[r])
+func (c *Condition) runeWidthSlow(r rune) int {
+ if r < 0 || r > 0x10FFFF {
+ return 0
}
- if w, ok := inWidthTable(r, eastAsianWidth); ok {
- return w
+ buildStrictWidthLUT()
+ if len(c.combinedLut) > 0 {
+ return int(c.combinedLut[r>>1]>>(uint(r&1)*4)) & 3
}
- if !c.StrictEmojiNeutral && inTable(r, emoji) {
- return 2
+ if c.StrictEmojiNeutral {
+ if c.EastAsianWidth {
+ return int(strictWidthLUT[1][r])
+ }
+ return int(strictWidthLUT[0][r])
}
- return 1
+ return runeWidthNoLUT(r, c.EastAsianWidth, c.StrictEmojiNeutral)
}
// CreateLUT will create an in-memory lookup table of 557056 bytes for faster operation.
@@ -271,6 +439,11 @@ func (c *Condition) CreateLUT() {
const max = 0x110000
lut := c.combinedLut
if len(c.combinedLut) != 0 {
+ if c.lutEastAsianWidth == c.EastAsianWidth && c.lutStrictEmojiNeutral == c.StrictEmojiNeutral {
+ // The table still matches the flags, so rebuilding it
+ // would produce the same bytes.
+ return
+ }
// Remove so we don't use it.
c.combinedLut = nil
} else {
@@ -283,6 +456,77 @@ func (c *Condition) CreateLUT() {
lut[i] = uint8(x0) | uint8(x1)<<4
}
c.combinedLut = lut
+ c.lutEastAsianWidth = c.EastAsianWidth
+ c.lutStrictEmojiNeutral = c.StrictEmojiNeutral
+}
+
+// isASCII reports whether s has no byte above 0x7F, in which case every
+// grapheme cluster in s is a single byte apart from CRLF.
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= 0x80 {
+ return false
+ }
+ }
+ return true
+}
+
+// fillJoinerBits paints joinerBits from the joiner table.
+func fillJoinerBits() {
+ for _, iv := range joiner {
+ if iv.first >= 0x10000 {
+ break // the table is sorted, the rest is astral
+ }
+ lo, hi := int(iv.first)-joinerBase, int(iv.last)-joinerBase
+ if hi >= len(joinerBits)*8 {
+ hi = len(joinerBits)*8 - 1
+ }
+ for lo <= hi {
+ if lo&7 == 0 && lo+7 <= hi {
+ joinerBits[lo>>3] = 0xFF
+ lo += 8
+ continue
+ }
+ joinerBits[lo>>3] |= 1 << uint(lo&7)
+ lo++
+ }
+ }
+ // A byte that is not valid UTF-8 decodes to U+FFFD, and the segmenter
+ // can gather a run of such bytes into one cluster, which a rune loop
+ // has no way to see. Marking U+FFFD keeps those strings on the
+ // segmenter, and the only string it holds back needlessly is one that
+ // really contains U+FFFD.
+ i := int(utf8.RuneError) - joinerBase
+ joinerBits[i>>3] |= 1 << uint(i&7)
+}
+
+// isJoiner reports whether r can join with a neighbour into a multi-rune
+// grapheme cluster. A string of runes for which it reports false has one
+// rune per cluster, so measuring it needs no grapheme segmentation.
+func isJoiner(r rune) bool {
+ if r < joinerBase {
+ return r == '\r'
+ }
+ if r < 0x10000 {
+ i := r - joinerBase
+ return joinerBits[i>>3]&(1<<(uint(i)&7)) != 0
+ }
+ return inTable(r, joiner)
+}
+
+// graphemeWidth returns the width of a single grapheme cluster: the sum of
+// the widths of its runes, capped at 2 cells. The cap keeps multi-rune
+// sequences that render as a single glyph (ZWJ emoji, flags, Hangul jamo)
+// from being counted wider than the two cells terminals give them.
+func (c *Condition) graphemeWidth(cluster string) int {
+ width := 0
+ for _, r := range cluster {
+ width += c.RuneWidth(r)
+ }
+ if width > 2 {
+ width = 2
+ }
+ return width
}
// StringWidth return width as you can see
@@ -313,38 +557,49 @@ func (c *Condition) StringWidth(s string) (width int) {
return
graphemes:
+ // Runes first: until one of them can join a cluster, each cluster is a
+ // single rune and segmenting the string would only find that out the
+ // expensive way.
+ if w, ok := c.runeWidthSum(s); ok {
+ width = w
+ return
+ }
width = 0
g := graphemes.FromString(s)
for g.Next() {
- var chWidth int
- for _, r := range g.Value() {
- chWidth = c.RuneWidth(r)
- if chWidth > 0 {
- break // Our best guess at this point is to use the width of the first non-zero-width rune.
- }
- }
- width += chWidth
+ width += c.graphemeWidth(g.Value())
}
return
}
+// runeWidthSum adds up the widths of the runes in s, and reports false
+// without a total once it meets a rune that can join a cluster, which is
+// where per-rune widths stop being the whole story.
+func (c *Condition) runeWidthSum(s string) (int, bool) {
+ width := 0
+ for _, r := range s {
+ if isJoiner(r) {
+ return 0, false
+ }
+ width += c.RuneWidth(r)
+ }
+ return width, true
+}
+
// Truncate return string truncated with w cells
func (c *Condition) Truncate(s string, w int, tail string) string {
if c.StringWidth(s) <= w {
return s
}
w -= c.StringWidth(tail)
+ if pos, ok := c.truncateRunes(s, w); ok {
+ return s[:pos] + tail
+ }
var width int
pos := len(s)
g := graphemes.FromString(s)
for g.Next() {
- var chWidth int
- for _, r := range g.Value() {
- chWidth = c.RuneWidth(r)
- if chWidth > 0 {
- break // See StringWidth() for details.
- }
- }
+ chWidth := c.graphemeWidth(g.Value())
if width+chWidth > w {
pos = g.Start()
break
@@ -354,24 +609,51 @@ func (c *Condition) Truncate(s string, w int, tail string) string {
return s[:pos] + tail
}
+// truncateRunes is the loop in Truncate with every rune taken for a whole
+// cluster, which holds until a rune can join one. It reports false there
+// and leaves the string to the segmenter.
+func (c *Condition) truncateRunes(s string, w int) (int, bool) {
+ width := 0
+ for i, r := range s {
+ if isJoiner(r) {
+ return 0, false
+ }
+ cw := c.RuneWidth(r)
+ if width+cw > w {
+ return i, true
+ }
+ width += cw
+ }
+ return len(s), true
+}
+
+// endsCluster reports whether the byte at i, which follows a rune that
+// cannot join a cluster, also starts one. Cutting there is only safe when
+// the rune that follows does not reach back.
+func endsCluster(s string, i int) bool {
+ if i >= len(s) {
+ return true
+ }
+ r, _ := utf8.DecodeRuneInString(s[i:])
+ return !isJoiner(r)
+}
+
// TruncateLeft cuts w cells from the beginning of the `s`.
func (c *Condition) TruncateLeft(s string, w int, prefix string) string {
if c.StringWidth(s) <= w {
return prefix
}
+ if pos, pad, ok := c.truncateLeftRunes(s, w); ok {
+ return prefix + strings.Repeat(" ", pad) + s[pos:]
+ }
+
var width int
pos := len(s)
g := graphemes.FromString(s)
for g.Next() {
- var chWidth int
- for _, r := range g.Value() {
- chWidth = c.RuneWidth(r)
- if chWidth > 0 {
- break // See StringWidth() for details.
- }
- }
+ chWidth := c.graphemeWidth(g.Value())
if width+chWidth > w {
if width < w {
@@ -390,25 +672,164 @@ func (c *Condition) TruncateLeft(s string, w int, prefix string) string {
return prefix + s[pos:]
}
-// Wrap return string wrapped with w cells
-func (c *Condition) Wrap(s string, w int) string {
+// truncateLeftRunes is the loop in TruncateLeft with every rune taken for a
+// whole cluster, returning the cut and the padding that replaces the cell
+// the cut lands inside. It reports false at the first rune that can join a
+// cluster.
+func (c *Condition) truncateLeftRunes(s string, w int) (pos, pad int, ok bool) {
+ width := 0
+ for i, r := range s {
+ if isJoiner(r) {
+ return 0, 0, false
+ }
+ cw := c.RuneWidth(r)
+ if width+cw > w {
+ if width >= w {
+ return i, 0, true
+ }
+ end := i + utf8.RuneLen(r)
+ if !endsCluster(s, end) {
+ return 0, 0, false
+ }
+ return end, width + cw - w, true
+ }
+ width += cw
+ }
+ return len(s), 0, true
+}
+
+// TruncatePrefix cuts the beginning of `s` so the result fits in w cells, with prefix prepended
+func (c *Condition) TruncatePrefix(s string, w int, prefix string) string {
+ if c.StringWidth(prefix) >= w {
+ return prefix
+ }
+
+ sw := c.StringWidth(s)
+ if sw <= w {
+ return s
+ }
+ w -= c.StringWidth(prefix)
+ if pos, ok := c.truncatePrefixRunes(s, sw, w); ok {
+ return prefix + s[pos:]
+ }
+ var width int
+ var pos int
+ g := graphemes.FromString(s)
+ for g.Next() {
+ chWidth := c.graphemeWidth(g.Value())
+ if sw-(width+chWidth) <= w {
+ pos = g.End()
+ break
+ }
+ width += chWidth
+ }
+
+ return prefix + s[pos:]
+}
+
+// truncatePrefixRunes is the loop in TruncatePrefix with every rune taken
+// for a whole cluster, reporting false at the first rune that can join one.
+func (c *Condition) truncatePrefixRunes(s string, sw, w int) (int, bool) {
+ width := 0
+ for i, r := range s {
+ if isJoiner(r) {
+ return 0, false
+ }
+ cw := c.RuneWidth(r)
+ if sw-(width+cw) <= w {
+ end := i + utf8.RuneLen(r)
+ if !endsCluster(s, end) {
+ return 0, false
+ }
+ return end, true
+ }
+ width += cw
+ }
+ return 0, true
+}
+
+// wrapRunes wraps s treating every rune as its own grapheme cluster, and
+// reports false without a result once it meets a rune that can join one.
+func (c *Condition) wrapRunes(s string, w int) (string, bool) {
width := 0
var out strings.Builder
- out.Grow(len(s) + len(s)/w + 1)
+ out.Grow(len(s) + len(s)/max(w, 1) + 1)
for _, r := range s {
+ if isJoiner(r) {
+ return "", false
+ }
cw := c.RuneWidth(r)
if r == '\n' {
out.WriteRune(r)
width = 0
continue
- } else if width+cw > w {
+ }
+ if width+cw > w {
out.WriteByte('\n')
width = 0
- out.WriteRune(r)
+ }
+ out.WriteRune(r)
+ width += cw
+ }
+ return out.String(), true
+}
+
+// Wrap return string wrapped with w cells
+func (c *Condition) Wrap(s string, w int) string {
+ // ASCII fast path: no grapheme clustering needed for pure ASCII
+ if isASCII(s) {
+ width := 0
+ var out strings.Builder
+ // max keeps the capacity hint from dividing by zero when w is 0;
+ // a non-positive width breaks before every cluster, as it always
+ // has.
+ out.Grow(len(s) + len(s)/max(w, 1) + 1)
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if b == '\n' {
+ out.WriteByte(b)
+ width = 0
+ continue
+ }
+ // Same rule as the StringWidth fast path: no ASCII byte is
+ // wide or ambiguous, so the flags in c cannot change this.
+ cw := 0
+ if b >= 0x20 && b != 0x7F {
+ cw = 1
+ }
+ if width+cw > w {
+ out.WriteByte('\n')
+ width = 0
+ }
+ out.WriteByte(b)
width += cw
+ }
+ return out.String()
+ }
+ // Runes first, as in StringWidth. Reaching a rune that can join a
+ // cluster throws the wrapped text away and starts over on the
+ // segmenter, which is the uncommon case.
+ if out, ok := c.wrapRunes(s, w); ok {
+ return out
+ }
+ width := 0
+ var out strings.Builder
+ out.Grow(len(s) + len(s)/max(w, 1) + 1)
+ g := graphemes.FromString(s)
+ for g.Next() {
+ cluster := g.Value()
+ // LF and CRLF are each a single cluster
+ if strings.HasSuffix(cluster, "\n") {
+ out.WriteString(cluster)
+ width = 0
continue
}
- out.WriteRune(r)
+ cw := c.graphemeWidth(cluster)
+ if width+cw > w {
+ out.WriteByte('\n')
+ width = 0
+ }
+ out.WriteString(cluster)
width += cw
}
return out.String()
@@ -419,11 +840,7 @@ func (c *Condition) FillLeft(s string, w int) string {
width := c.StringWidth(s)
count := w - width
if count > 0 {
- b := make([]byte, count)
- for i := range b {
- b[i] = ' '
- }
- return string(b) + s
+ return strings.Repeat(" ", count) + s
}
return s
}
@@ -433,11 +850,7 @@ func (c *Condition) FillRight(s string, w int) string {
width := c.StringWidth(s)
count := w - width
if count > 0 {
- b := make([]byte, count)
- for i := range b {
- b[i] = ' '
- }
- return s + string(b)
+ return s + strings.Repeat(" ", count)
}
return s
}
@@ -478,6 +891,11 @@ func TruncateLeft(s string, w int, prefix string) string {
return DefaultCondition.TruncateLeft(s, w, prefix)
}
+// TruncatePrefix cuts the beginning of `s` so the result fits in w cells, with prefix prepended
+func TruncatePrefix(s string, w int, prefix string) string {
+ return DefaultCondition.TruncatePrefix(s, w, prefix)
+}
+
// Wrap return string wrapped with w cells
func Wrap(s string, w int) string {
return DefaultCondition.Wrap(s, w)
@@ -495,9 +913,8 @@ func FillRight(s string, w int) string {
// CreateLUT will create an in-memory lookup table of 557055 bytes for faster operation.
// This should not be called concurrently with other operations.
+// If flags in DefaultCondition are changed, CreateLUT should be called again;
+// a call that finds the table already current is a no-op.
func CreateLUT() {
- if len(DefaultCondition.combinedLut) > 0 {
- return
- }
DefaultCondition.CreateLUT()
}
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_posix.go b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
index 5a31d73..16673af 100644
--- a/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
@@ -5,35 +5,50 @@ package runewidth
import (
"os"
- "regexp"
"strings"
)
-var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
+func mblen(charset string) int {
+ switch charset {
+ case "utf-8", "utf8":
+ return 6
+ case "jis":
+ return 8
+ case "eucjp":
+ return 3
+ case "euckr", "euccn", "sjis", "cp932", "cp51932", "cp936", "cp949", "cp950", "big5", "gbk", "gb2312":
+ return 2
+ }
+ return 1
+}
-var mblenTable = map[string]int{
- "utf-8": 6,
- "utf8": 6,
- "jis": 8,
- "eucjp": 3,
- "euckr": 2,
- "euccn": 2,
- "sjis": 2,
- "cp932": 2,
- "cp51932": 2,
- "cp936": 2,
- "cp949": 2,
- "cp950": 2,
- "big5": 2,
- "gbk": 2,
- "gb2312": 2,
+// localeCharset extracts the charset part of a locale name of the form
+// "ll.CHARSET" or "ll_CC.CHARSET" (two- or three-letter language code,
+// optional uppercase country code). It returns "" if locale does not have
+// that shape.
+func localeCharset(locale string) string {
+ n := 0
+ for n < len(locale) && locale[n] >= 'a' && locale[n] <= 'z' {
+ n++
+ }
+ if n < 2 || n > 3 {
+ return ""
+ }
+ rest := locale[n:]
+ if len(rest) >= 3 && rest[0] == '_' &&
+ rest[1] >= 'A' && rest[1] <= 'Z' && rest[2] >= 'A' && rest[2] <= 'Z' {
+ rest = rest[3:]
+ }
+ if len(rest) >= 2 && rest[0] == '.' {
+ return rest[1:]
+ }
+ return ""
}
func isEastAsian(locale string) bool {
charset := strings.ToLower(locale)
- r := reLoc.FindStringSubmatch(locale)
- if len(r) == 2 {
- charset = strings.ToLower(r[1])
+ if cs := localeCharset(locale); cs != "" {
+ charset = strings.ToLower(cs)
}
if strings.HasSuffix(charset, "@cjk_narrow") {
@@ -46,10 +61,7 @@ func isEastAsian(locale string) bool {
break
}
}
- max := 1
- if m, ok := mblenTable[charset]; ok {
- max = m
- }
+ max := mblen(charset)
if max > 1 && (charset[0] != 'u' ||
strings.HasPrefix(locale, "ja") ||
strings.HasPrefix(locale, "ko") ||
diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_table.go b/vendor/github.com/mattn/go-runewidth/runewidth_table.go
index cdd003e..be9618d 100644
--- a/vendor/github.com/mattn/go-runewidth/runewidth_table.go
+++ b/vendor/github.com/mattn/go-runewidth/runewidth_table.go
@@ -3,23 +3,127 @@
package runewidth
var combining = table{
- {0x0300, 0x036F}, {0x0483, 0x0489}, {0x07EB, 0x07F3},
- {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0CF3, 0x0CF3},
- {0x0D00, 0x0D01}, {0x135D, 0x135F}, {0x180B, 0x180D},
- {0x180F, 0x180F}, {0x1A7F, 0x1A7F}, {0x1AB0, 0x1ADD},
- {0x1AE0, 0x1AEB}, {0x1B6B, 0x1B73}, {0x1DC0, 0x1DFF},
- {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2DE0, 0x2DFF},
- {0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D},
- {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA8E0, 0xA8F1},
- {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD},
- {0x10376, 0x1037A}, {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50},
- {0x10F82, 0x10F85}, {0x11300, 0x11301}, {0x1133B, 0x1133C},
- {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x16AF0, 0x16AF4},
- {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169},
- {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B},
- {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1E000, 0x1E006},
- {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
- {0x1E026, 0x1E02A}, {0x1E08F, 0x1E08F}, {0x1E8D0, 0x1E8D6},
+ {0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD},
+ {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5},
+ {0x05C7, 0x05C7}, {0x0610, 0x061A}, {0x064B, 0x065F},
+ {0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DF, 0x06E4},
+ {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x0711, 0x0711},
+ {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3},
+ {0x07FD, 0x07FD}, {0x0816, 0x0819}, {0x081B, 0x0823},
+ {0x0825, 0x0827}, {0x0829, 0x082D}, {0x0859, 0x085B},
+ {0x0897, 0x089F}, {0x08CA, 0x08E1}, {0x08E3, 0x0902},
+ {0x093A, 0x093A}, {0x093C, 0x093C}, {0x0941, 0x0948},
+ {0x094D, 0x094D}, {0x0951, 0x0957}, {0x0962, 0x0963},
+ {0x0981, 0x0981}, {0x09BC, 0x09BC}, {0x09C1, 0x09C4},
+ {0x09CD, 0x09CD}, {0x09E2, 0x09E3}, {0x09FE, 0x09FE},
+ {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42},
+ {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
+ {0x0A70, 0x0A71}, {0x0A75, 0x0A75}, {0x0A81, 0x0A82},
+ {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8},
+ {0x0ACD, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0AFA, 0x0AFF},
+ {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F},
+ {0x0B41, 0x0B44}, {0x0B4D, 0x0B4D}, {0x0B55, 0x0B56},
+ {0x0B62, 0x0B63}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0},
+ {0x0BCD, 0x0BCD}, {0x0C00, 0x0C00}, {0x0C04, 0x0C04},
+ {0x0C3C, 0x0C3C}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48},
+ {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0C62, 0x0C63},
+ {0x0C81, 0x0C81}, {0x0CBC, 0x0CBC}, {0x0CBF, 0x0CBF},
+ {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, {0x0CE2, 0x0CE3},
+ {0x0CF3, 0x0CF3}, {0x0D00, 0x0D01}, {0x0D3B, 0x0D3C},
+ {0x0D41, 0x0D44}, {0x0D4D, 0x0D4D}, {0x0D62, 0x0D63},
+ {0x0D81, 0x0D81}, {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4},
+ {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31}, {0x0E34, 0x0E3A},
+ {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EBC},
+ {0x0EC8, 0x0ECE}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
+ {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E},
+ {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97},
+ {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030},
+ {0x1032, 0x1037}, {0x1039, 0x103A}, {0x103D, 0x103E},
+ {0x1058, 0x1059}, {0x105E, 0x1060}, {0x1071, 0x1074},
+ {0x1082, 0x1082}, {0x1085, 0x1086}, {0x108D, 0x108D},
+ {0x109D, 0x109D}, {0x135D, 0x135F}, {0x1712, 0x1714},
+ {0x1732, 0x1733}, {0x1752, 0x1753}, {0x1772, 0x1773},
+ {0x17B4, 0x17B5}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6},
+ {0x17C9, 0x17D3}, {0x17DD, 0x17DD}, {0x180B, 0x180D},
+ {0x180F, 0x180F}, {0x1885, 0x1886}, {0x18A9, 0x18A9},
+ {0x1920, 0x1922}, {0x1927, 0x1928}, {0x1932, 0x1932},
+ {0x1939, 0x193B}, {0x1A17, 0x1A18}, {0x1A1B, 0x1A1B},
+ {0x1A56, 0x1A56}, {0x1A58, 0x1A5E}, {0x1A60, 0x1A60},
+ {0x1A62, 0x1A62}, {0x1A65, 0x1A6C}, {0x1A73, 0x1A7C},
+ {0x1A7F, 0x1A7F}, {0x1AB0, 0x1ADD}, {0x1AE0, 0x1AEB},
+ {0x1B00, 0x1B03}, {0x1B34, 0x1B34}, {0x1B36, 0x1B3A},
+ {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42}, {0x1B6B, 0x1B73},
+ {0x1B80, 0x1B81}, {0x1BA2, 0x1BA5}, {0x1BA8, 0x1BA9},
+ {0x1BAB, 0x1BAD}, {0x1BE6, 0x1BE6}, {0x1BE8, 0x1BE9},
+ {0x1BED, 0x1BED}, {0x1BEF, 0x1BF1}, {0x1C2C, 0x1C33},
+ {0x1C36, 0x1C37}, {0x1CD0, 0x1CD2}, {0x1CD4, 0x1CE0},
+ {0x1CE2, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF4, 0x1CF4},
+ {0x1CF8, 0x1CF9}, {0x1DC0, 0x1DFF}, {0x20D0, 0x20F0},
+ {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F}, {0x2DE0, 0x2DFF},
+ {0x302A, 0x302D}, {0x3099, 0x309A}, {0xA66F, 0xA672},
+ {0xA674, 0xA67D}, {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1},
+ {0xA802, 0xA802}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
+ {0xA825, 0xA826}, {0xA82C, 0xA82C}, {0xA8C4, 0xA8C5},
+ {0xA8E0, 0xA8F1}, {0xA8FF, 0xA8FF}, {0xA926, 0xA92D},
+ {0xA947, 0xA951}, {0xA980, 0xA982}, {0xA9B3, 0xA9B3},
+ {0xA9B6, 0xA9B9}, {0xA9BC, 0xA9BD}, {0xA9E5, 0xA9E5},
+ {0xAA29, 0xAA2E}, {0xAA31, 0xAA32}, {0xAA35, 0xAA36},
+ {0xAA43, 0xAA43}, {0xAA4C, 0xAA4C}, {0xAA7C, 0xAA7C},
+ {0xAAB0, 0xAAB0}, {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8},
+ {0xAABE, 0xAABF}, {0xAAC1, 0xAAC1}, {0xAAEC, 0xAAED},
+ {0xAAF6, 0xAAF6}, {0xABE5, 0xABE5}, {0xABE8, 0xABE8},
+ {0xABED, 0xABED}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
+ {0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, {0x102E0, 0x102E0},
+ {0x10376, 0x1037A}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06},
+ {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F},
+ {0x10AE5, 0x10AE6}, {0x10D24, 0x10D27}, {0x10D69, 0x10D6D},
+ {0x10EAB, 0x10EAC}, {0x10EFA, 0x10EFF}, {0x10F46, 0x10F50},
+ {0x10F82, 0x10F85}, {0x11001, 0x11001}, {0x11038, 0x11046},
+ {0x11070, 0x11070}, {0x11073, 0x11074}, {0x1107F, 0x11081},
+ {0x110B3, 0x110B6}, {0x110B9, 0x110BA}, {0x110C2, 0x110C2},
+ {0x11100, 0x11102}, {0x11127, 0x1112B}, {0x1112D, 0x11134},
+ {0x11173, 0x11173}, {0x11180, 0x11181}, {0x111B6, 0x111BE},
+ {0x111C9, 0x111CC}, {0x111CF, 0x111CF}, {0x1122F, 0x11231},
+ {0x11234, 0x11234}, {0x11236, 0x11237}, {0x1123E, 0x1123E},
+ {0x11241, 0x11241}, {0x112DF, 0x112DF}, {0x112E3, 0x112EA},
+ {0x11300, 0x11301}, {0x1133B, 0x1133C}, {0x11340, 0x11340},
+ {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x113BB, 0x113C0},
+ {0x113CE, 0x113CE}, {0x113D0, 0x113D0}, {0x113D2, 0x113D2},
+ {0x113E1, 0x113E2}, {0x11438, 0x1143F}, {0x11442, 0x11444},
+ {0x11446, 0x11446}, {0x1145E, 0x1145E}, {0x114B3, 0x114B8},
+ {0x114BA, 0x114BA}, {0x114BF, 0x114C0}, {0x114C2, 0x114C3},
+ {0x115B2, 0x115B5}, {0x115BC, 0x115BD}, {0x115BF, 0x115C0},
+ {0x115DC, 0x115DD}, {0x11633, 0x1163A}, {0x1163D, 0x1163D},
+ {0x1163F, 0x11640}, {0x116AB, 0x116AB}, {0x116AD, 0x116AD},
+ {0x116B0, 0x116B5}, {0x116B7, 0x116B7}, {0x1171D, 0x1171D},
+ {0x1171F, 0x1171F}, {0x11722, 0x11725}, {0x11727, 0x1172B},
+ {0x1182F, 0x11837}, {0x11839, 0x1183A}, {0x1193B, 0x1193C},
+ {0x1193E, 0x1193E}, {0x11943, 0x11943}, {0x119D4, 0x119D7},
+ {0x119DA, 0x119DB}, {0x119E0, 0x119E0}, {0x11A01, 0x11A0A},
+ {0x11A33, 0x11A38}, {0x11A3B, 0x11A3E}, {0x11A47, 0x11A47},
+ {0x11A51, 0x11A56}, {0x11A59, 0x11A5B}, {0x11A8A, 0x11A96},
+ {0x11A98, 0x11A99}, {0x11B60, 0x11B60}, {0x11B62, 0x11B64},
+ {0x11B66, 0x11B66}, {0x11C30, 0x11C36}, {0x11C38, 0x11C3D},
+ {0x11C3F, 0x11C3F}, {0x11C92, 0x11CA7}, {0x11CAA, 0x11CB0},
+ {0x11CB2, 0x11CB3}, {0x11CB5, 0x11CB6}, {0x11D31, 0x11D36},
+ {0x11D3A, 0x11D3A}, {0x11D3C, 0x11D3D}, {0x11D3F, 0x11D45},
+ {0x11D47, 0x11D47}, {0x11D90, 0x11D91}, {0x11D95, 0x11D95},
+ {0x11D97, 0x11D97}, {0x11EF3, 0x11EF4}, {0x11F00, 0x11F01},
+ {0x11F36, 0x11F3A}, {0x11F40, 0x11F40}, {0x11F42, 0x11F42},
+ {0x11F5A, 0x11F5A}, {0x13440, 0x13440}, {0x13447, 0x13455},
+ {0x1611E, 0x16129}, {0x1612D, 0x1612F}, {0x16AF0, 0x16AF4},
+ {0x16B30, 0x16B36}, {0x16F4F, 0x16F4F}, {0x16F8F, 0x16F92},
+ {0x16FE4, 0x16FE4}, {0x1BC9D, 0x1BC9E}, {0x1CF00, 0x1CF2D},
+ {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172},
+ {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
+ {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36}, {0x1DA3B, 0x1DA6C},
+ {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84}, {0x1DA9B, 0x1DA9F},
+ {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018},
+ {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A},
+ {0x1E08F, 0x1E08F}, {0x1E130, 0x1E136}, {0x1E2AE, 0x1E2AE},
+ {0x1E2EC, 0x1E2EF}, {0x1E4EC, 0x1E4EF}, {0x1E5EE, 0x1E5EF},
+ {0x1E6E3, 0x1E6E3}, {0x1E6E6, 0x1E6E6}, {0x1E6EE, 0x1E6EF},
+ {0x1E6F5, 0x1E6F5}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A},
{0xE0100, 0xE01EF},
}
@@ -486,3 +590,120 @@ var emoji = table{
{0x1F947, 0x1F9FF}, {0x1FA58, 0x1FA5F}, {0x1FA6E, 0x1FAFF},
{0x1FC00, 0x1FFFD},
}
+
+var joiner = table{
+ {0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD},
+ {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5},
+ {0x05C7, 0x05C7}, {0x0600, 0x0605}, {0x0610, 0x061A},
+ {0x064B, 0x065F}, {0x0670, 0x0670}, {0x06D6, 0x06DD},
+ {0x06DF, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
+ {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
+ {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x07FD, 0x07FD},
+ {0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827},
+ {0x0829, 0x082D}, {0x0859, 0x085B}, {0x0890, 0x0891},
+ {0x0897, 0x089F}, {0x08CA, 0x0903}, {0x093A, 0x093C},
+ {0x093E, 0x094F}, {0x0951, 0x0957}, {0x0962, 0x0963},
+ {0x0981, 0x0983}, {0x09BC, 0x09BC}, {0x09BE, 0x09C4},
+ {0x09C7, 0x09C8}, {0x09CB, 0x09CD}, {0x09D7, 0x09D7},
+ {0x09E2, 0x09E3}, {0x09FE, 0x09FE}, {0x0A01, 0x0A03},
+ {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, {0x0A47, 0x0A48},
+ {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, {0x0A70, 0x0A71},
+ {0x0A75, 0x0A75}, {0x0A81, 0x0A83}, {0x0ABC, 0x0ABC},
+ {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD},
+ {0x0AE2, 0x0AE3}, {0x0AFA, 0x0AFF}, {0x0B01, 0x0B03},
+ {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48},
+ {0x0B4B, 0x0B4D}, {0x0B55, 0x0B57}, {0x0B62, 0x0B63},
+ {0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8},
+ {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C04},
+ {0x0C3C, 0x0C3C}, {0x0C3E, 0x0C44}, {0x0C46, 0x0C48},
+ {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0C62, 0x0C63},
+ {0x0C81, 0x0C83}, {0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4},
+ {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6},
+ {0x0CE2, 0x0CE3}, {0x0CF3, 0x0CF3}, {0x0D00, 0x0D03},
+ {0x0D3B, 0x0D3C}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48},
+ {0x0D4A, 0x0D4E}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63},
+ {0x0D81, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4},
+ {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3},
+ {0x0E31, 0x0E31}, {0x0E33, 0x0E3A}, {0x0E47, 0x0E4E},
+ {0x0EB1, 0x0EB1}, {0x0EB3, 0x0EBC}, {0x0EC8, 0x0ECE},
+ {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37},
+ {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F}, {0x0F71, 0x0F84},
+ {0x0F86, 0x0F87}, {0x0F8D, 0x0F97}, {0x0F99, 0x0FBC},
+ {0x0FC6, 0x0FC6}, {0x102D, 0x1037}, {0x1039, 0x103E},
+ {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1071, 0x1074},
+ {0x1082, 0x1082}, {0x1084, 0x1086}, {0x108D, 0x108D},
+ {0x109D, 0x109D}, {0x1100, 0x11FF}, {0x135D, 0x135F},
+ {0x1712, 0x1715}, {0x1732, 0x1734}, {0x1752, 0x1753},
+ {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD},
+ {0x180B, 0x180D}, {0x180F, 0x180F}, {0x1885, 0x1886},
+ {0x18A9, 0x18A9}, {0x1920, 0x192B}, {0x1930, 0x193B},
+ {0x1A17, 0x1A1B}, {0x1A55, 0x1A5E}, {0x1A60, 0x1A60},
+ {0x1A62, 0x1A62}, {0x1A65, 0x1A7C}, {0x1A7F, 0x1A7F},
+ {0x1AB0, 0x1ADD}, {0x1AE0, 0x1AEB}, {0x1B00, 0x1B04},
+ {0x1B34, 0x1B44}, {0x1B6B, 0x1B73}, {0x1B80, 0x1B82},
+ {0x1BA1, 0x1BAD}, {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37},
+ {0x1CD0, 0x1CD2}, {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED},
+ {0x1CF4, 0x1CF4}, {0x1CF7, 0x1CF9}, {0x1DC0, 0x1DFF},
+ {0x200C, 0x200D}, {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1},
+ {0x2D7F, 0x2D7F}, {0x2DE0, 0x2DFF}, {0x302A, 0x302F},
+ {0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D},
+ {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA802, 0xA802},
+ {0xA806, 0xA806}, {0xA80B, 0xA80B}, {0xA823, 0xA827},
+ {0xA82C, 0xA82C}, {0xA880, 0xA881}, {0xA8B4, 0xA8C5},
+ {0xA8E0, 0xA8F1}, {0xA8FF, 0xA8FF}, {0xA926, 0xA92D},
+ {0xA947, 0xA953}, {0xA960, 0xA97C}, {0xA980, 0xA983},
+ {0xA9B3, 0xA9C0}, {0xA9E5, 0xA9E5}, {0xAA29, 0xAA36},
+ {0xAA43, 0xAA43}, {0xAA4C, 0xAA4D}, {0xAA7C, 0xAA7C},
+ {0xAAB0, 0xAAB0}, {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8},
+ {0xAABE, 0xAABF}, {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF},
+ {0xAAF5, 0xAAF6}, {0xABE3, 0xABEA}, {0xABEC, 0xABED},
+ {0xAC00, 0xD7A3}, {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB},
+ {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F},
+ {0xFF9E, 0xFF9F}, {0x101FD, 0x101FD}, {0x102E0, 0x102E0},
+ {0x10376, 0x1037A}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06},
+ {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F},
+ {0x10AE5, 0x10AE6}, {0x10D24, 0x10D27}, {0x10D69, 0x10D6D},
+ {0x10EAB, 0x10EAC}, {0x10EFA, 0x10EFF}, {0x10F46, 0x10F50},
+ {0x10F82, 0x10F85}, {0x11000, 0x11002}, {0x11038, 0x11046},
+ {0x11070, 0x11070}, {0x11073, 0x11074}, {0x1107F, 0x11082},
+ {0x110B0, 0x110BA}, {0x110BD, 0x110BD}, {0x110C2, 0x110C2},
+ {0x110CD, 0x110CD}, {0x11100, 0x11102}, {0x11127, 0x11134},
+ {0x11145, 0x11146}, {0x11173, 0x11173}, {0x11180, 0x11182},
+ {0x111B3, 0x111C0}, {0x111C2, 0x111C3}, {0x111C9, 0x111CC},
+ {0x111CE, 0x111CF}, {0x1122C, 0x11237}, {0x1123E, 0x1123E},
+ {0x11241, 0x11241}, {0x112DF, 0x112EA}, {0x11300, 0x11303},
+ {0x1133B, 0x1133C}, {0x1133E, 0x11344}, {0x11347, 0x11348},
+ {0x1134B, 0x1134D}, {0x11357, 0x11357}, {0x11362, 0x11363},
+ {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x113B8, 0x113C0},
+ {0x113C2, 0x113C2}, {0x113C5, 0x113C5}, {0x113C7, 0x113CA},
+ {0x113CC, 0x113D2}, {0x113E1, 0x113E2}, {0x11435, 0x11446},
+ {0x1145E, 0x1145E}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5},
+ {0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640},
+ {0x116AB, 0x116B7}, {0x1171D, 0x1171F}, {0x11722, 0x1172B},
+ {0x1182C, 0x1183A}, {0x11930, 0x11935}, {0x11937, 0x11938},
+ {0x1193B, 0x11943}, {0x119D1, 0x119D7}, {0x119DA, 0x119E0},
+ {0x119E4, 0x119E4}, {0x11A01, 0x11A0A}, {0x11A33, 0x11A3E},
+ {0x11A47, 0x11A47}, {0x11A51, 0x11A5B}, {0x11A84, 0x11A99},
+ {0x11B60, 0x11B67}, {0x11C2F, 0x11C36}, {0x11C38, 0x11C3F},
+ {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, {0x11D31, 0x11D36},
+ {0x11D3A, 0x11D3A}, {0x11D3C, 0x11D3D}, {0x11D3F, 0x11D47},
+ {0x11D8A, 0x11D8E}, {0x11D90, 0x11D91}, {0x11D93, 0x11D97},
+ {0x11EF3, 0x11EF6}, {0x11F00, 0x11F03}, {0x11F34, 0x11F3A},
+ {0x11F3E, 0x11F42}, {0x11F5A, 0x11F5A}, {0x13440, 0x13440},
+ {0x13447, 0x13455}, {0x1611E, 0x1612F}, {0x16AF0, 0x16AF4},
+ {0x16B30, 0x16B36}, {0x16D63, 0x16D63}, {0x16D67, 0x16D6A},
+ {0x16F4F, 0x16F4F}, {0x16F51, 0x16F87}, {0x16F8F, 0x16F92},
+ {0x16FE4, 0x16FE4}, {0x16FF0, 0x16FF1}, {0x1BC9D, 0x1BC9E},
+ {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169},
+ {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B},
+ {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36},
+ {0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84},
+ {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
+ {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
+ {0x1E026, 0x1E02A}, {0x1E08F, 0x1E08F}, {0x1E130, 0x1E136},
+ {0x1E2AE, 0x1E2AE}, {0x1E2EC, 0x1E2EF}, {0x1E4EC, 0x1E4EF},
+ {0x1E5EE, 0x1E5EF}, {0x1E6E3, 0x1E6E3}, {0x1E6E6, 0x1E6E6},
+ {0x1E6EE, 0x1E6EF}, {0x1E6F5, 0x1E6F5}, {0x1E8D0, 0x1E8D6},
+ {0x1E944, 0x1E94A}, {0x1F1E6, 0x1F1FF}, {0x1F3FB, 0x1F3FF},
+ {0xE0020, 0xE007F}, {0xE0100, 0xE01EF},
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/auth/auth.go b/vendor/github.com/modelcontextprotocol/go-sdk/auth/auth.go
index 40fa259..dc02d7d 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/auth/auth.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/auth/auth.go
@@ -47,6 +47,34 @@ type RequireBearerTokenOptions struct {
ResourceMetadataURL string
// The required scopes.
Scopes []string
+ // AllowMissingExpiration opts the middleware out of the
+ // `tokenInfo.Expiration.IsZero()` reject. Default false preserves the
+ // existing strict behaviour (every TokenInfo must carry an Expiration).
+ //
+ // Some IdPs emit session-bound bearer tokens that do not carry a standalone
+ // `exp` claim — the token's lifetime is bounded by an external session and
+ // is not advertised in-band. Resource servers integrating with such IdPs
+ // need to opt in to validating the rest of the token (scopes, signature
+ // via the verifier callback, etc.) without requiring the expiration field
+ // to be present.
+ //
+ // When enabled, the verifier is still responsible for any session-level
+ // validity check it can perform; this option only relaxes the middleware's
+ // own expiration enforcement.
+ AllowMissingExpiration bool
+ // ClockSkew bounds the tolerance applied to a token's Expiration when
+ // deciding whether it has elapsed. A token is rejected only if
+ // Expiration + ClockSkew is before the current time. Zero (the default)
+ // preserves strict comparison: any expired token is rejected immediately.
+ //
+ // Resource servers running behind a CDN, in distributed deployments, or
+ // communicating with an authorization server whose clock drifts a few
+ // seconds (common with cloud-managed IdPs) need a small positive value
+ // here to avoid rejecting tokens that are valid by the issuer's clock
+ // but momentarily appear expired by the verifier's. The same tolerance
+ // guards against an issuer's clock running slightly fast at /token
+ // issuance time.
+ ClockSkew time.Duration
}
type tokenInfoKey struct{}
@@ -129,11 +157,17 @@ func verify(req *http.Request, verifier TokenVerifier, opts *RequireBearerTokenO
}
}
- // Check expiration.
- if tokenInfo.Expiration.IsZero() {
- return nil, "token missing expiration", http.StatusUnauthorized
+ if opts == nil {
+ opts = &RequireBearerTokenOptions{}
}
- if tokenInfo.Expiration.Before(time.Now()) {
+ // Check expiration, with optional clock-skew tolerance. Skew only applies
+ // when an expiration is present; a missing expiration is governed solely by
+ // AllowMissingExpiration.
+ if tokenInfo.Expiration.IsZero() {
+ if !opts.AllowMissingExpiration {
+ return nil, "token missing expiration", http.StatusUnauthorized
+ }
+ } else if tokenInfo.Expiration.Add(opts.ClockSkew).Before(time.Now()) {
return nil, "token expired", http.StatusUnauthorized
}
return tokenInfo, "", 0
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/auth/authorization_code.go b/vendor/github.com/modelcontextprotocol/go-sdk/auth/authorization_code.go
index 758b88e..f349842 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/auth/authorization_code.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/auth/authorization_code.go
@@ -14,7 +14,9 @@ import (
"net/url"
"slices"
"strings"
+ "sync"
+ "github.com/modelcontextprotocol/go-sdk/internal/authutil"
"github.com/modelcontextprotocol/go-sdk/internal/util"
"github.com/modelcontextprotocol/go-sdk/oauthex"
"golang.org/x/oauth2"
@@ -49,6 +51,12 @@ type AuthorizationResult struct {
Code string
// State string returned by the authorization server.
State string
+ // Iss is the issuer identifier returned by the authorization server in the
+ // authorization response per [RFC 9207]. The AuthorizationCodeFetcher should
+ // populate this from the "iss" query parameter in the redirect URI if present.
+ //
+ // [RFC 9207]: https://www.rfc-editor.org/rfc/rfc9207
+ Iss string
}
// AuthorizationArgs is the input to [AuthorizationCodeFetcher].
@@ -90,6 +98,37 @@ type AuthorizationCodeHandlerConfig struct {
// See [AuthorizationCodeFetcher] for details.
AuthorizationCodeFetcher AuthorizationCodeFetcher
+ // ScopeFilter, if non-nil, is called with the scopes discovered from the
+ // protected resource metadata (or WWW-Authenticate challenge) and returns
+ // the scopes to request during authorization. It gives the client full
+ // control to narrow, extend, or reorder that set — e.g. dropping Gmail's
+ // gmail.metadata, which the Gmail API refuses to combine with the search "q"
+ // parameter even alongside gmail.readonly. It runs before offline_access
+ // (see RequestRefreshToken) and the step-up union, so neither is affected.
+ ScopeFilter func(discovered []string) []string
+
+ // RequestRefreshToken indicates that the client intends to use refresh
+ // tokens and is capable of storing them securely.
+ //
+ // When true and the Authorization Server metadata contains "offline_access"
+ // in its scopes_supported, the client adds "offline_access" to the
+ // requested scopes.
+ //
+ // When using Dynamic Client Registration, callers should include
+ // "refresh_token" in [DynamicClientRegistrationConfig].Metadata.GrantTypes
+ // directly to advertise refresh token support to the Authorization Server.
+ //
+ // When using Client ID Metadata Document, the document hosted at the
+ // Client ID URL should include "refresh_token" in its grant_types.
+ //
+ // See https://modelcontextprotocol.io/seps/2207-oidc-refresh-token-guidance.
+ RequestRefreshToken bool
+
+ // AcceptUnadvertisedIss accepts a matching RFC 9207 iss even when the
+ // authorization server metadata omits authorization_response_iss_parameter_supported.
+ // The zero value (false) keeps the historical reject-unadvertised-iss behavior.
+ AcceptUnadvertisedIss bool
+
// Client is an optional HTTP client to use for HTTP requests.
// It is used for the following requests:
// - Fetching Protected Resource Metadata
@@ -102,6 +141,24 @@ type AuthorizationCodeHandlerConfig struct {
// https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices#server-side-request-forgery-ssrf
// If not provided, http.DefaultClient will be used.
Client *http.Client
+
+ // NewTokenSource is an optional function that can be set to construct the
+ // token source that will be used by the [AuthorizationCodeHandler]. If
+ // non-nil, it is called after the authorization code is successfully
+ // exchanged for a token in [AuthorizationCodeHandler.Authorize]
+ // to obtain the [oauth2.TokenSource] returned by
+ // [AuthorizationCodeHandler.TokenSource]. Implementations must use the
+ // provided context, which is properly configured for constructing a
+ // TokenSource. The default is to call [oauth2.Config.TokenSource].
+ NewTokenSource func(context.Context, *oauth2.Config, *oauth2.Token) (oauth2.TokenSource, error)
+
+ // InitialTokenSource is an optional field that can be set to inject the
+ // token source that will be used by the [AuthorizationCodeHandler]. If
+ // non-nil, it is set as the token source that will be returned by
+ // [AuthorizationCodeHandler.TokenSource] during handler initialization.
+ // The default is nil, which means no token source has been set initially,
+ // and will trigger a call to [AuthorizationCodeHandler.Authorize].
+ InitialTokenSource oauth2.TokenSource
}
// AuthorizationCodeHandler is an implementation of [OAuthHandler] that uses
@@ -109,13 +166,21 @@ type AuthorizationCodeHandlerConfig struct {
type AuthorizationCodeHandler struct {
config *AuthorizationCodeHandlerConfig
+ // mu protects concurrent access to tokenSource and grantedScopes.
+ mu sync.RWMutex
+
// tokenSource is the token source to use for authorization.
tokenSource oauth2.TokenSource
+
+ // grantedScopes maps authorization server issuer to the list of scopes granted by that issuer.
+ grantedScopes map[string][]string
}
var _ OAuthHandler = (*AuthorizationCodeHandler)(nil)
func (h *AuthorizationCodeHandler) TokenSource(ctx context.Context) (oauth2.TokenSource, error) {
+ h.mu.RLock()
+ defer h.mu.RUnlock()
return h.tokenSource, nil
}
@@ -170,7 +235,11 @@ func NewAuthorizationCodeHandler(config *AuthorizationCodeHandlerConfig) (*Autho
if config.Client == nil {
config.Client = http.DefaultClient
}
- return &AuthorizationCodeHandler{config: config}, nil
+ return &AuthorizationCodeHandler{
+ config: config,
+ tokenSource: config.InitialTokenSource,
+ grantedScopes: make(map[string][]string),
+ }, nil
}
func isNonRootHTTPSURL(u string) bool {
@@ -258,11 +327,33 @@ func (h *AuthorizationCodeHandler) Authorize(ctx context.Context, req *http.Requ
return err
}
- scps := scopesFromChallenges(wwwChallenges)
- if len(scps) == 0 && len(prm.ScopesSupported) > 0 {
- scps = prm.ScopesSupported
+ requestedScopes := scopesFromChallenges(wwwChallenges)
+ if len(requestedScopes) == 0 && len(prm.ScopesSupported) > 0 {
+ requestedScopes = prm.ScopesSupported
+ }
+
+ // Let the client adjust the discovered scopes before offline_access and the
+ // step-up union below so neither is affected.
+ if h.config.ScopeFilter != nil {
+ requestedScopes = h.config.ScopeFilter(requestedScopes)
+ }
+
+ // SEP-2207: when the client desires refresh tokens and the Authorization
+ // Server advertises offline_access support, add it to the requested scopes.
+ if h.config.RequestRefreshToken &&
+ slices.Contains(asm.ScopesSupported, "offline_access") &&
+ !slices.Contains(requestedScopes, "offline_access") {
+ requestedScopes = append(requestedScopes, "offline_access")
}
+ // Accumulate scopes: union previously granted scopes with the newly
+ // challenged scopes so that step-up authorization does not lose
+ // permissions granted in earlier rounds (SEP-2350).
+ h.mu.RLock()
+ granted := h.grantedScopes[asm.Issuer]
+ h.mu.RUnlock()
+ requestedScopes = authutil.UnionScopes(granted, requestedScopes)
+
cfg := &oauth2.Config{
ClientID: resolvedClientConfig.clientID,
ClientSecret: resolvedClientConfig.clientSecret,
@@ -273,7 +364,7 @@ func (h *AuthorizationCodeHandler) Authorize(ctx context.Context, req *http.Requ
AuthStyle: resolvedClientConfig.authStyle,
},
RedirectURL: h.config.RedirectURL,
- Scopes: scps,
+ Scopes: requestedScopes,
}
authRes, err := h.getAuthorizationCode(ctx, cfg, prm.Resource)
@@ -281,8 +372,16 @@ func (h *AuthorizationCodeHandler) Authorize(ctx context.Context, req *http.Requ
// Purposefully leaving the error unwrappable so it can be handled by the caller.
return err
}
+ if err := validateIssuerResponse(authRes.Iss, asm.Issuer, asm.AuthorizationResponseIssParameterSupported, h.config.AcceptUnadvertisedIss); err != nil {
+ return err
+ }
- return h.exchangeAuthorizationCode(ctx, cfg, authRes, prm.Resource)
+ err = h.exchangeAuthorizationCode(ctx, cfg, authRes, prm.Resource)
+ if err != nil {
+ return err
+ }
+
+ return h.updateGrantedScopes(asm.Issuer, requestedScopes)
}
// resourceMetadataURLFromChallenges returns a resource metadata URL from the given "WWW-Authenticate" header challenges,
@@ -456,6 +555,9 @@ func (h *AuthorizationCodeHandler) handleRegistration(ctx context.Context, asm *
// 2. Attempt to use pre-registered client configuration.
preCfg := h.config.PreregisteredClient
if preCfg != nil {
+ if preCfg.Issuer != "" && !authutil.IssuersEqual(preCfg.Issuer, asm.Issuer) {
+ return nil, fmt.Errorf("authorization server issuer %q does not match pre-registered credentials issuer %q", asm.Issuer, preCfg.Issuer)
+ }
authStyle := selectTokenAuthMethod(asm.TokenEndpointAuthMethodsSupported)
clientSecret := ""
if preCfg.ClientSecretAuth != nil {
@@ -518,6 +620,36 @@ func (h *AuthorizationCodeHandler) getAuthorizationCode(ctx context.Context, cfg
}, nil
}
+// validateIssuerResponse validates the "iss" parameter in an authorization response
+// per [RFC 9207]. When the server advertises authorization_response_iss_parameter_supported,
+// iss is required and must match expectedIssuer. When it does not advertise support,
+// an empty iss is accepted; a present iss is compared to expectedIssuer (RFC 9207 §2.4)
+// and a mismatch is always rejected. A matching unadvertised iss is accepted only when
+// acceptUnadvertisedIss is true (local policy); the default is the historical reject.
+//
+// [RFC 9207]: https://www.rfc-editor.org/rfc/rfc9207
+func validateIssuerResponse(iss, expectedIssuer string, issParameterSupported, acceptUnadvertisedIss bool) error {
+ if issParameterSupported {
+ if iss == "" {
+ return fmt.Errorf("authorization server advertises RFC 9207 iss parameter support but none was received in the authorization response")
+ }
+ if iss != expectedIssuer {
+ return fmt.Errorf("authorization response issuer %q does not match expected issuer %q", iss, expectedIssuer)
+ }
+ return nil
+ }
+ if iss == "" {
+ return nil
+ }
+ if iss != expectedIssuer {
+ return fmt.Errorf("authorization response issuer %q does not match expected issuer %q", iss, expectedIssuer)
+ }
+ if !acceptUnadvertisedIss {
+ return fmt.Errorf("authorization server does not advertise RFC 9207 iss parameter support but iss was received in the authorization response")
+ }
+ return nil
+}
+
// exchangeAuthorizationCode exchanges the authorization code for a token
// and stores it in a token source.
func (h *AuthorizationCodeHandler) exchangeAuthorizationCode(ctx context.Context, cfg *oauth2.Config, authResult *authResult, resourceURL string) error {
@@ -530,6 +662,52 @@ func (h *AuthorizationCodeHandler) exchangeAuthorizationCode(ctx context.Context
if err != nil {
return fmt.Errorf("token exchange failed: %w", err)
}
- h.tokenSource = cfg.TokenSource(clientCtx, token)
+ // The token source outlives this authorization request: it is stored on the
+ // handler and used by the transport for the lifetime of the connection. The
+ // oauth2 library captures the context passed to TokenSource and reuses it for
+ // every subsequent token refresh (see golang.org/x/oauth2: tokenRefresher
+ // retains the context and passes it to each refresh round-trip). Binding it to
+ // the per-request ctx makes all later refreshes fail with "context canceled"
+ // once that request (or the connect operation that triggered authorization)
+ // completes. Use a background context that still carries the configured HTTP
+ // client so refreshes keep working for the life of the token source.
+ refreshCtx := context.WithValue(context.Background(), oauth2.HTTPClient, h.config.Client)
+ var ts oauth2.TokenSource
+ if h.config.NewTokenSource == nil {
+ ts = cfg.TokenSource(refreshCtx, token)
+ } else {
+ var err error
+ ts, err = h.config.NewTokenSource(refreshCtx, cfg, token)
+ if err != nil {
+ return fmt.Errorf("constructing token source failed: %w", err)
+ }
+ }
+ h.mu.Lock()
+ h.tokenSource = ts
+ h.mu.Unlock()
+ return nil
+}
+
+// updateGrantedScopes updates the granted scopes based on the token source and requested scopes.
+func (h *AuthorizationCodeHandler) updateGrantedScopes(issuer string, requestedScopes []string) error {
+ h.mu.RLock()
+ ts := h.tokenSource
+ h.mu.RUnlock()
+
+ if ts == nil {
+ return nil
+ }
+ tok, err := ts.Token()
+ if err != nil {
+ return err
+ }
+
+ h.mu.Lock()
+ if tokenScopes := authutil.ScopesFromToken(tok); tokenScopes == nil {
+ h.grantedScopes[issuer] = requestedScopes
+ } else {
+ h.grantedScopes[issuer] = tokenScopes
+ }
+ h.mu.Unlock()
return nil
}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/internal/authutil/scopes.go b/vendor/github.com/modelcontextprotocol/go-sdk/internal/authutil/scopes.go
new file mode 100644
index 0000000..4b5de73
--- /dev/null
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/internal/authutil/scopes.go
@@ -0,0 +1,36 @@
+// Copyright 2026 The Go MCP SDK Authors. All rights reserved.
+// Use of this source code is governed by the license
+// that can be found in the LICENSE file.
+package authutil
+
+import (
+ "maps"
+ "slices"
+ "strings"
+
+ "golang.org/x/oauth2"
+)
+
+// UnionScopes returns the union of the existing and challenged scope sets.
+// It is used during step-up authorization to accumulate scopes across
+// authorization rounds (SEP-2350).
+func UnionScopes(existing, challenged []string) []string {
+ combined := make(map[string]struct{})
+ for _, s := range existing {
+ combined[s] = struct{}{}
+ }
+ for _, s := range challenged {
+ combined[s] = struct{}{}
+ }
+ return slices.Collect(maps.Keys(combined))
+}
+
+// ScopesFromToken extracts the granted scopes from an OAuth2 token response.
+// Per RFC 6749 §5.1, the scope parameter is optional; returns nil if absent.
+func ScopesFromToken(token *oauth2.Token) []string {
+ scope, ok := token.Extra("scope").(string)
+ if !ok {
+ return nil
+ }
+ return strings.Fields(scope)
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/internal/authutil/util.go b/vendor/github.com/modelcontextprotocol/go-sdk/internal/authutil/util.go
new file mode 100644
index 0000000..880d1bf
--- /dev/null
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/internal/authutil/util.go
@@ -0,0 +1,13 @@
+// Copyright 2026 The Go MCP SDK Authors. All rights reserved.
+// Use of this source code is governed by the license
+// that can be found in the LICENSE file.
+
+package authutil
+
+import "strings"
+
+// IssuersEqual reports whether two OAuth 2.0 authorization server issuer
+// identifiers refer to the same server comparing them without the final trailing slash.
+func IssuersEqual(a, b string) bool {
+ return strings.TrimSuffix(a, "/") == strings.TrimSuffix(b, "/")
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/internal/json/json.go b/vendor/github.com/modelcontextprotocol/go-sdk/internal/json/json.go
index b4c897f..b3fa039 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/internal/json/json.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/internal/json/json.go
@@ -8,11 +8,21 @@ package json
import (
"bytes"
+ "fmt"
"io"
"github.com/segmentio/encoding/json"
)
+// defaultMaxDepth is the maximum JSON nesting depth accepted by [Unmarshal].
+// Realistic MCP payloads nest only a handful of levels, so 1000 is far more
+// than any legitimate message requires while keeping worst-case parse cost
+// bounded.
+const defaultMaxDepth = 1000
+
+// errMaxDepthExceeded is returned by [Unmarshal] when the input nests deeper than [defaultMaxDepth].
+var errMaxDepthExceeded = fmt.Errorf("json: exceeded maximum nesting depth of %d", defaultMaxDepth)
+
type Decoder struct {
dec *json.Decoder
}
@@ -28,5 +38,47 @@ func (d *Decoder) Decode(v any) error {
}
func Unmarshal(data []byte, v any) error {
+ if err := checkMaxDepth(data, defaultMaxDepth); err != nil {
+ return err
+ }
return NewDecoder(bytes.NewReader(data)).Decode(v)
}
+
+// checkMaxDepth scans data once and reports [errMaxDepthExceeded] if the
+// nesting of JSON objects and arrays exceeds maxDepth. It is a lightweight pass which
+// tracks '{' and '[' against '}' and ']' while skipping over the contents of strings.
+func checkMaxDepth(data []byte, maxDepth int) error {
+ var (
+ depth int
+ inString bool
+ escaped bool
+ )
+ for _, b := range data {
+ if inString {
+ switch {
+ case escaped:
+ escaped = false
+ case b == '\\':
+ escaped = true
+ case b == '"':
+ inString = false
+ }
+ continue
+ }
+
+ switch b {
+ case '"':
+ inString = true
+ case '{', '[':
+ depth++
+ if depth > maxDepth {
+ return errMaxDepthExceeded
+ }
+ case '}', ']':
+ if depth > 0 {
+ depth--
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/conn.go b/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/conn.go
index 72cc740..5849a87 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/conn.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/conn.go
@@ -14,8 +14,25 @@ import (
"time"
"github.com/modelcontextprotocol/go-sdk/internal/json"
+ "github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug"
)
+// nomethodnotfoundcodeinerror is a compatibility parameter that restores the
+// pre-fix behavior of [processResult], where wrapped [ErrNotHandled] or
+// [ErrMethodNotFound] errors returned by request handlers were not
+// recognized as "method not found" signals. The original switch statement
+// compared sentinel errors with ==, which never matched errors returned via
+// fmt.Errorf("%w: ...", ErrNotHandled, ...) — including the ones produced
+// by checkRequest. As a result the wire error response carried code 0
+// instead of code -32601. The fix uses errors.Is to recognize wrapped
+// sentinels and append the method name to the message.
+//
+// To restore the previous behavior, set MCPGODEBUG=nomethodnotfoundcodeinerror=1.
+// This option will be removed in a future SDK version.
+// See the documentation for the mcpgodebug package for instructions on how
+// to use it.
+var nomethodnotfoundcodeinerror = mcpgodebug.Value("nomethodnotfoundcodeinerror")
+
// Connection manages the jsonrpc2 protocol, connecting responses back to their
// calls. Connection is bidirectional; it does not have a designated server or
// client end.
@@ -141,12 +158,12 @@ func (s *inFlightState) shuttingDown(errClosing error) error {
if s.readErr != nil {
// If the read side of the connection is broken, we cannot read new call
// requests, and cannot read responses to our outgoing calls.
- return fmt.Errorf("%w: %v", errClosing, s.readErr)
+ return fmt.Errorf("%w: %w", errClosing, s.readErr)
}
if s.writeErr != nil {
// If the write side of the connection is broken, we cannot write responses
// for incoming calls, and cannot write requests for outgoing calls.
- return fmt.Errorf("%w: %v", errClosing, s.writeErr)
+ return fmt.Errorf("%w: %w", errClosing, s.writeErr)
}
return nil
}
@@ -155,7 +172,7 @@ func (s *inFlightState) shuttingDown(errClosing error) error {
type incomingRequest struct {
*Request // the request being processed
ctx context.Context
- cancel context.CancelFunc
+ cancel context.CancelCauseFunc
}
// Reader abstracts the transport mechanics from the JSON RPC protocol.
@@ -191,12 +208,30 @@ type ConnectionConfig struct {
Bind func(*Connection) Handler // required
OnDone func() // optional
OnInternalError func(error) // optional
+
+ // PropagateCancellation controls whether cancellation of the context
+ // passed to [NewConnection] is observable by request handlers.
+ //
+ // By default (false), the connection wraps that context (see [notDone])
+ // so handlers' Done channels do not fire when the connection's root
+ // context is cancelled. Cancellation of an in-flight handler is then
+ // expected to flow only through the jsonrpc2 layer's explicit channels
+ // (the [Preempter] reacting to the peer's cancel notification, or a
+ // transport read/write failure cancelling every in-flight request).
+ //
+ // Set this true when cancellation of the connection's context is itself
+ // a meaningful signal that handlers should react to (for example, when
+ // the connection is tied to a carrier that owns it and whose end means
+ // the request is cancelled).
+ PropagateCancellation bool // optional
}
// NewConnection creates a new [Connection] object and starts processing
// incoming messages.
func NewConnection(ctx context.Context, cfg ConnectionConfig) *Connection {
- ctx = notDone{ctx}
+ if !cfg.PropagateCancellation {
+ ctx = notDone{ctx}
+ }
c := &Connection{
state: inFlightState{closer: cfg.Closer},
@@ -423,7 +458,7 @@ func (c *Connection) Cancel(id ID) {
req = s.incomingByID[id]
})
if req != nil {
- req.cancel()
+ req.cancel(nil)
}
}
@@ -513,6 +548,16 @@ func (c *Connection) readIncoming(ctx context.Context, reader Reader, preempter
ac.retire(&Response{ID: id, Error: err})
}
s.outgoingCalls = nil
+
+ // Cancel any incoming requests still in flight: with the reader gone we
+ // cannot receive cancellation notifications, and likely cannot write a
+ // response either, so parked handlers have nothing useful left to do.
+ // The read error (typically io.EOF from the peer disconnecting) is the
+ // cause, rather than a directional ErrServerClosing/ErrClientClosing
+ // sentinel: at this layer the connection has no designated end.
+ for _, r := range s.incomingByID {
+ r.cancel(err)
+ }
})
}
@@ -521,7 +566,7 @@ func (c *Connection) readIncoming(ctx context.Context, reader Reader, preempter
func (c *Connection) acceptRequest(ctx context.Context, msg *Request, preempter Preempter) {
// In theory notifications cannot be cancelled, but we build them a cancel
// context anyway.
- reqCtx, cancel := context.WithCancel(ctx)
+ reqCtx, cancel := context.WithCancelCause(ctx)
req := &incomingRequest{
Request: msg,
ctx: reqCtx,
@@ -622,15 +667,14 @@ func (c *Connection) handleAsync() {
return
}
- // Only deliver to the Handler if not already canceled.
+ // Only deliver to the Handler if not already canceled. If the request
+ // was canceled with a cause (e.g. a write failure cancels every
+ // in-flight request), report that cause rather than the bare
+ // context.Canceled.
if err := req.ctx.Err(); err != nil {
- c.updateInFlight(func(s *inFlightState) {
- if s.writeErr != nil {
- // Assume that req.ctx was canceled due to s.writeErr.
- // TODO(#51365): use a Context API to plumb this through req.ctx.
- err = fmt.Errorf("%w: %v", ErrServerClosing, s.writeErr)
- }
- })
+ if cause := context.Cause(req.ctx); cause != nil {
+ err = cause
+ }
c.processResult("handleAsync", req, nil, err)
continue
}
@@ -648,9 +692,7 @@ func (c *Connection) handleAsync() {
// processResult processes the result of a request and, if appropriate, sends a response.
func (c *Connection) processResult(from any, req *incomingRequest, result any, err error) error {
- switch err {
- case ErrNotHandled, ErrMethodNotFound:
- // Add detail describing the unhandled method.
+ if nomethodnotfoundcodeinerror != "1" && (errors.Is(err, ErrNotHandled) || errors.Is(err, ErrMethodNotFound)) {
err = fmt.Errorf("%w: %q", ErrMethodNotFound, req.Method)
}
@@ -693,7 +735,7 @@ func (c *Connection) processResult(from any, req *incomingRequest, result any, e
}
// Cancel the request to free any associated resources.
- req.cancel()
+ req.cancel(nil)
c.updateInFlight(func(s *inFlightState) {
if s.incoming == 0 {
panic("jsonrpc2: processResult called when incoming count is already zero")
@@ -709,9 +751,12 @@ func (c *Connection) write(ctx context.Context, msg Message) error {
var err error
// Fail writes immediately if the connection is shutting down.
//
- // TODO(rfindley): should we allow cancellation notifications through? It
- // could be the case that writes can still succeed.
+ // Allow outgoing "notifications" forwarded by the Notify method.
+ // This will allow to send the cancelled notification when the client is shutting down.
c.updateInFlight(func(s *inFlightState) {
+ if req, ok := msg.(*Request); ok && !req.IsCall() && s.outgoingNotifications > 0 {
+ return
+ }
err = s.shuttingDown(ErrServerClosing)
})
if err == nil {
@@ -733,7 +778,7 @@ func (c *Connection) write(ctx context.Context, msg Message) error {
if s.writeErr == nil {
s.writeErr = err
for _, r := range s.incomingByID {
- r.cancel()
+ r.cancel(fmt.Errorf("%w: %v", ErrServerClosing, err))
}
}
})
@@ -756,6 +801,15 @@ func (c *Connection) internalErrorf(format string, args ...any) error {
}
// notDone is a context.Context wrapper that returns a nil Done channel.
+//
+// Request handlers' contexts are derived from the connection's root context,
+// which by default is wrapped in notDone so a transport-level cancellation
+// does not implicitly cancel every in-flight handler. Cancellation of an
+// in-flight handler is instead expected to flow only through the jsonrpc2
+// layer's explicit channels: the [Preempter] calling [Connection.Cancel] in
+// response to the peer's cancel notification, or the transport itself
+// failing (the read loop exits on EOF or a write fails) — both of which
+// cancel every in-flight incoming request in turn.
type notDone struct{ ctx context.Context }
func (ic notDone) Value(key any) any {
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/messages.go b/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/messages.go
index 77c9531..8b96770 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/messages.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/messages.go
@@ -171,8 +171,20 @@ func EncodeIndent(msg Message, prefix, indent string) ([]byte, error) {
return bytes.TrimRight(buf.Bytes(), "\n"), nil
}
+// wireDecode is the decode form of [wireCombined]. Method is a [json.RawMessage]
+// so we can tell whether the "method" key was present on the wire, including
+// when its value is the empty string (see go-sdk#976).
+type wireDecode struct {
+ VersionTag string `json:"jsonrpc"`
+ ID any `json:"id,omitempty"`
+ Method json.RawMessage `json:"method"`
+ Params json.RawMessage `json:"params,omitempty"`
+ Result json.RawMessage `json:"result,omitempty"`
+ Error *WireError `json:"error,omitempty"`
+}
+
func DecodeMessage(data []byte) (Message, error) {
- msg := wireCombined{}
+ msg := wireDecode{}
if err := internaljson.Unmarshal(data, &msg); err != nil {
return nil, fmt.Errorf("unmarshaling jsonrpc message: %w", err)
}
@@ -183,15 +195,19 @@ func DecodeMessage(data []byte) (Message, error) {
if err != nil {
return nil, err
}
- if msg.Method != "" {
- // has a method, must be a call
+ if len(msg.Method) > 0 {
+ // The "method" key was present. Decode its value (including "").
+ var method string
+ if err := internaljson.Unmarshal(msg.Method, &method); err != nil {
+ return nil, fmt.Errorf("unmarshaling jsonrpc message: %w", err)
+ }
return &Request{
- Method: msg.Method,
+ Method: method,
ID: id,
Params: msg.Params,
}, nil
}
- // no method, should be a response
+ // no method key, should be a response
if !id.IsValid() {
return nil, ErrInvalidRequest
}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/wire.go b/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/wire.go
index 4d123f2..499b026 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/wire.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2/wire.go
@@ -87,7 +87,7 @@ func (err *WireError) Error() string {
func (err *WireError) Is(other error) bool {
w, ok := other.(*WireError)
- if !ok {
+ if !ok || w == nil {
return false
}
return err.Code == w.Code
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/internal/util/net.go b/vendor/github.com/modelcontextprotocol/go-sdk/internal/util/net.go
index 6858614..593012d 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/internal/util/net.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/internal/util/net.go
@@ -24,3 +24,26 @@ func IsLoopback(addr string) bool {
}
return ip.IsLoopback()
}
+
+// cgnat is the RFC 6598 carrier-grade NAT range (100.64.0.0/10). netip's
+// IsPrivate does not report it, but it is shared ISP space that is not publicly
+// routable and could point at another tenant behind the same NAT.
+var cgnat = netip.MustParsePrefix("100.64.0.0/10")
+
+// IsPrivateOrReserved reports whether ip belongs to a range that must not be
+// reachable through a server-controlled URL, as a defense against SSRF: private
+// (RFC 1918 / RFC 4193 ULA), link-local (including the 169.254.169.254 cloud
+// metadata endpoint), carrier-grade NAT, multicast, and the unspecified address.
+func IsPrivateOrReserved(ip netip.Addr) bool {
+ ip = ip.Unmap()
+ if !ip.IsValid() {
+ return true
+ }
+ if ip.IsPrivate() ||
+ ip.IsLinkLocalUnicast() ||
+ ip.IsMulticast() ||
+ ip.IsUnspecified() {
+ return true
+ }
+ return cgnat.Contains(ip)
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/cache.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/cache.go
new file mode 100644
index 0000000..9837337
--- /dev/null
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/cache.go
@@ -0,0 +1,87 @@
+// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
+// Use of this source code is governed by the license
+// that can be found in the LICENSE file.
+
+package mcp
+
+import (
+ "sync"
+ "time"
+)
+
+// methodCache is a per-method TTL cache for list and read results, as
+// described in SEP-2549. Each entry is keyed by cursor (for paginated list
+// methods) or URI (for resources/read).
+type methodCache[R CacheableResult] struct {
+ mu sync.Mutex
+ cachedValues map[string]*cacheEntry[R]
+}
+
+type cacheEntry[R CacheableResult] struct {
+ result R
+ receivedAt time.Time
+}
+
+func (e *cacheEntry[R]) isValid() bool {
+ return time.Since(e.receivedAt) < time.Duration(e.result.GetTTLMs())*time.Millisecond
+}
+
+func (mc *methodCache[R]) get(key string) (R, bool) {
+ mc.mu.Lock()
+ defer mc.mu.Unlock()
+ entry, ok := mc.cachedValues[key]
+ if !ok {
+ var zero R
+ return zero, false
+ }
+ if entry.result.GetTTLMs() <= 0 || !entry.isValid() {
+ delete(mc.cachedValues, key)
+ var zero R
+ return zero, false
+ }
+ return entry.result, true
+}
+
+func (mc *methodCache[R]) put(key string, result R) {
+ mc.mu.Lock()
+ defer mc.mu.Unlock()
+ if mc.cachedValues == nil {
+ mc.cachedValues = make(map[string]*cacheEntry[R])
+ }
+ mc.cachedValues[key] = &cacheEntry[R]{
+ result: result,
+ receivedAt: time.Now(),
+ }
+}
+
+func (mc *methodCache[R]) invalidate() {
+ mc.mu.Lock()
+ defer mc.mu.Unlock()
+ clear(mc.cachedValues)
+}
+
+func (mc *methodCache[R]) invalidateKey(key string) {
+ mc.mu.Lock()
+ defer mc.mu.Unlock()
+ delete(mc.cachedValues, key)
+}
+
+// cursorParams is the constraint for list-method params that carry a pagination
+// cursor and can be checked for nil. Both methods are already implemented by
+// every concrete list-params type.
+type cursorParams interface {
+ Params
+ cursorPtr() *string
+}
+
+// cachedListResult returns a cached list result keyed by the request cursor
+// (SEP-2549). It returns the zero value and false on miss or when params is nil.
+func cachedListResult[P cursorParams, R CacheableResult](cache *methodCache[R], params P) (R, bool) {
+ key := ""
+ if !params.isNil() {
+ if cp := params.cursorPtr(); cp != nil {
+ key = *cp
+ }
+ }
+ return cache.get(key)
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/client.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/client.go
index c82e189..c11f0c8 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/client.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/client.go
@@ -10,6 +10,8 @@ import (
"fmt"
"iter"
"log/slog"
+ "maps"
+ "reflect"
"slices"
"strings"
"sync"
@@ -32,6 +34,11 @@ type Client struct {
sessions []*ClientSession
sendingMethodHandler_ MethodHandler
receivingMethodHandler_ MethodHandler
+ // sendMethods is the list of methods this client may send to a
+ // server: it always contains the standard server methods (from
+ // serverMethodInfos) plus any custom methods registered via
+ // [AddSendingCustomMethod].
+ sendMethods map[string]methodInfo
}
// NewClient creates a new [Client].
@@ -58,13 +65,21 @@ func NewClient(impl *Implementation, options *ClientOptions) *Client {
opts.Logger = ensureLogger(nil)
}
- return &Client{
+ sendMethods := make(map[string]methodInfo, len(serverMethodInfos))
+ maps.Copy(sendMethods, serverMethodInfos)
+
+ c := &Client{
impl: impl,
opts: opts,
roots: newFeatureSet(func(r *Root) string { return r.URI }),
sendingMethodHandler_: defaultSendingMethodHandler,
receivingMethodHandler_: defaultReceivingMethodHandler[*ClientSession],
+ sendMethods: sendMethods,
+ }
+ if opts.MultiRoundTrip == nil || !opts.MultiRoundTrip.Disabled {
+ c.AddSendingMiddleware(clientMultiRoundTripMiddleware())
}
+ return c
}
// ClientOptions configures the behavior of the client.
@@ -78,6 +93,12 @@ type ClientOptions struct {
// &SamplingCapabilities{}. If [ClientOptions.Capabilities] is set and has a
// non nil value for [ClientCapabilities.Sampling], that value overrides the
// inferred capability.
+ //
+ // Deprecated: the sampling feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). Migrate to calling LLM provider APIs
+ // directly from your server. See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
CreateMessageHandler func(context.Context, *CreateMessageRequest) (*CreateMessageResult, error)
// CreateMessageWithToolsHandler handles incoming sampling/createMessage
// requests that may involve tool use. It returns
@@ -91,6 +112,12 @@ type ClientOptions struct {
//
// It is a panic to set both CreateMessageHandler and
// CreateMessageWithToolsHandler.
+ //
+ // Deprecated: the sampling feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). Migrate to calling LLM provider APIs
+ // directly from your server. See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
CreateMessageWithToolsHandler func(context.Context, *CreateMessageWithToolsRequest) (*CreateMessageWithToolsResult, error)
// ElicitationHandler handles incoming requests for elicitation/create.
//
@@ -148,18 +175,43 @@ type ClientOptions struct {
// ElicitationCompleteHandler handles incoming notifications for notifications/elicitation/complete.
ElicitationCompleteHandler func(context.Context, *ElicitationCompleteNotificationRequest)
// Handlers for notifications from the server.
- ToolListChangedHandler func(context.Context, *ToolListChangedRequest)
- PromptListChangedHandler func(context.Context, *PromptListChangedRequest)
- ResourceListChangedHandler func(context.Context, *ResourceListChangedRequest)
- ResourceUpdatedHandler func(context.Context, *ResourceUpdatedNotificationRequest)
+ ToolListChangedHandler func(context.Context, *ToolListChangedRequest)
+ PromptListChangedHandler func(context.Context, *PromptListChangedRequest)
+ ResourceListChangedHandler func(context.Context, *ResourceListChangedRequest)
+ ResourceUpdatedHandler func(context.Context, *ResourceUpdatedNotificationRequest)
+ // LoggingMessageHandler handles incoming notifications/message
+ // notifications from the server.
+ //
+ // Deprecated: the logging feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
LoggingMessageHandler func(context.Context, *LoggingMessageRequest)
ProgressNotificationHandler func(context.Context, *ProgressNotificationClientRequest)
+ // MultiRoundTrip configures the automatic MultiRoundTrip (Multi Round-Trip Requests) middleware.
+ // By default (nil), the middleware is enabled with default settings.
+ // Set Disabled to true to opt out of automatic MultiRoundTrip handling.
+ MultiRoundTrip *MultiRoundTripOptions
// If non-zero, defines an interval for regular "ping" requests.
// If the peer fails to respond to pings originating from the keepalive check,
// the session is automatically closed.
+ // NOTE: The keepalive feature is only available for protocol versions < 2026-07-28
KeepAlive time.Duration
+ // KeepAliveFailureThreshold is the number of consecutive keepalive ping
+ // failures tolerated before the session is closed. A value of 0 or 1
+ // closes the session on the first failure (the default). Higher values
+ // align with the spec's "multiple failed pings MAY trigger a connection
+ // reset" guidance, letting a transient miss pass without tearing down an
+ // otherwise live session. Has no effect unless KeepAlive is non-zero.
+ KeepAliveFailureThreshold int
}
+// toolContextKeyType is the context key type for passing tool definitions
+// from CallTool to the transport layer.
+type toolContextKeyType struct{}
+
+var toolContextKey = toolContextKeyType{}
+
// bind implements the binder[*ClientSession] interface, so that Clients can
// be connected using [connect].
func (c *Client) bind(mcpConn Connection, conn *jsonrpc2.Connection, state *clientSessionState, onClose func()) *ClientSession {
@@ -193,11 +245,12 @@ func (e unsupportedProtocolVersionError) Error() string {
return fmt.Sprintf("unsupported protocol version: %q", e.version)
}
-// ClientSessionOptions is reserved for future use.
+// ClientSessionOptions configures a client session created by [Client.Connect].
type ClientSessionOptions struct {
- // protocolVersion overrides the protocol version sent in the initialize
- // request, for testing. If empty, latestProtocolVersion is used.
- protocolVersion string
+ // ProtocolVersion is the protocol version sent in the initialize (or
+ // discover) request. If empty, the latest supported version is used.
+ // The server may negotiate a different mutually supported version.
+ ProtocolVersion string
}
func (c *Client) capabilities(protocolVersion string) *ClientCapabilities {
@@ -259,9 +312,75 @@ func (c *Client) Connect(ctx context.Context, t Transport, opts *ClientSessionOp
}
protocolVersion := latestProtocolVersion
- if opts != nil && opts.protocolVersion != "" {
- protocolVersion = opts.protocolVersion
+ if opts != nil && opts.ProtocolVersion != "" {
+ protocolVersion = opts.ProtocolVersion
+ }
+
+ if protocolVersion >= protocolVersion20260728 {
+ // Per SEP-2575, try the stateless server/discover RPC first. If the server
+ // signals it doesn't support it, fall back to the legacy initialize
+ // handshake.
+ discoverCtx := context.WithValue(ctx, protocolVersionContextKey{}, protocolVersion)
+ // We try to discover the server's capabilities. If the server rejects the
+ // requested version but specifies which versions it supports, we negotiate
+ // a mutually supported version and try again.
+ for range 2 {
+ discRes, err := c.discover(discoverCtx, cs)
+ if err == nil {
+ cs.state.InitializeResult = discRes
+ if hc, ok := cs.mcpConn.(clientConnection); ok {
+ hc.sessionUpdated(cs.state)
+ }
+ subscribeParams := &SubscriptionsListenParams{
+ Notifications: &NotificationSubscriptions{},
+ }
+ caps := discRes.Capabilities
+ if caps == nil {
+ caps = &ServerCapabilities{}
+ }
+ if c.opts.ToolListChangedHandler != nil && caps.Tools != nil && caps.Tools.ListChanged {
+ subscribeParams.Notifications.ToolsListChanged = true
+ }
+ if c.opts.PromptListChangedHandler != nil && caps.Prompts != nil && caps.Prompts.ListChanged {
+ subscribeParams.Notifications.PromptsListChanged = true
+ }
+ if c.opts.ResourceListChangedHandler != nil && caps.Resources != nil && caps.Resources.ListChanged {
+ subscribeParams.Notifications.ResourcesListChanged = true
+ }
+ if subscribeParams.Notifications.ToolsListChanged ||
+ subscribeParams.Notifications.PromptsListChanged ||
+ subscribeParams.Notifications.ResourcesListChanged {
+ // ClientSession.Close cancels the listenCtx context to send notifications/cancelled.
+ listenCtx, cancelListen := context.WithCancel(context.Background())
+ cs.listenCancel = cancelListen
+ if err := cs.subscriptionsListen(listenCtx, subscribeParams); err != nil {
+ cancelListen()
+ return nil, fmt.Errorf("opening subscriptions/listen: %w", err)
+ }
+ }
+ return cs, nil
+ }
+
+ // Try to negotiate a mutually supported version if the server
+ // reports an UnsupportedProtocolVersionError with a supported version.
+ var werr *jsonrpc.Error
+ if errors.As(err, &werr) && werr.Code == CodeUnsupportedProtocolVersion && len(werr.Data) > 0 {
+ var data UnsupportedProtocolVersionData
+ if err := json.Unmarshal(werr.Data, &data); err == nil {
+ if negotiatedVersion := negotiateMutuallySupportedVersion(data.Supported); negotiatedVersion != "" && negotiatedVersion >= protocolVersion20260728 {
+ discoverCtx = context.WithValue(ctx, protocolVersionContextKey{}, negotiatedVersion)
+ continue
+ }
+ }
+ }
+ // Per the spec, fall back to the legacy initialize handshake on any
+ // non-modern error from server/discover.
+ break
+ }
+ // Use the latest legacy protocol version for the fallback initialize.
+ protocolVersion = protocolVersion20251125
}
+
params := &InitializeParams{
ProtocolVersion: protocolVersion,
ClientInfo: c.impl,
@@ -274,6 +393,7 @@ func (c *Client) Connect(ctx context.Context, t Transport, opts *ClientSessionOp
return nil, err
}
if !slices.Contains(supportedProtocolVersions, res.ProtocolVersion) {
+ _ = cs.Close()
return nil, unsupportedProtocolVersionError{res.ProtocolVersion}
}
cs.state.InitializeResult = res
@@ -293,6 +413,54 @@ func (c *Client) Connect(ctx context.Context, t Transport, opts *ClientSessionOp
return cs, nil
}
+// discover sends a SEP-2575 server/discover request to probe the server for
+// stateless protocol support.
+func (c *Client) discover(ctx context.Context, cs *ClientSession) (*InitializeResult, error) {
+ protocolVersion := protocolVersionFromContext(ctx)
+ caps := c.capabilities(protocolVersion)
+ params := &DiscoverParams{
+ Meta: Meta{
+ MetaKeyProtocolVersion: protocolVersion,
+ MetaKeyClientInfo: c.impl,
+ MetaKeyClientCapabilities: caps.toV2(),
+ },
+ }
+ req := &DiscoverRequest{Session: cs, Params: params}
+ res, err := handleSend[*DiscoverResult](ctx, methodDiscover, req)
+ if err != nil {
+ return nil, err
+ }
+
+ // Pick the highest protocol version that both the server and this SDK support.
+ // Since supportedProtocolVersions is defined in descending order (newest to oldest),
+ // the first match we find is the highest supported version.
+ var negotiated string
+ if slices.Contains(res.SupportedVersions, protocolVersion) {
+ negotiated = protocolVersion
+ } else {
+ negotiated = negotiateMutuallySupportedVersion(res.SupportedVersions)
+ }
+ if negotiated == "" || negotiated < protocolVersion20260728 {
+ // If there is no overlap, fall back to initialize so version
+ // negotiation can happen via the legacy path.
+ return nil, &jsonrpc2.WireError{
+ Code: CodeUnsupportedProtocolVersion,
+ Message: "unsupported protocol version",
+ }
+ }
+
+ var serverInfo *Implementation
+ if v, ok := decodeMetaValue[*Implementation](res.GetMeta(), MetaKeyServerInfo); ok {
+ serverInfo = v
+ }
+ return &InitializeResult{
+ Capabilities: res.Capabilities,
+ Instructions: res.Instructions,
+ ProtocolVersion: negotiated,
+ ServerInfo: serverInfo,
+ }, nil
+}
+
// A ClientSession is a logical connection with an MCP server. Its
// methods can be used to send requests or notifications to the server. Create
// a session by calling [Client.Connect].
@@ -309,15 +477,32 @@ type ClientSession struct {
conn *jsonrpc2.Connection
client *Client
keepaliveCancel context.CancelFunc
+ listenCancel context.CancelFunc
mcpConn Connection
// No mutex is (currently) required to guard the session state, because it is
// only set synchronously during Client.Connect.
state clientSessionState
+ // Per-method TTL caches for list results (SEP-2549).
+ toolsCache methodCache[*ListToolsResult]
+ promptsCache methodCache[*ListPromptsResult]
+ resourcesCache methodCache[*ListResourcesResult]
+ resourceTemplatesCache methodCache[*ListResourceTemplatesResult]
+ readResourceCache methodCache[*ReadResourceResult]
+
// Pending URL elicitations waiting for completion notifications.
pendingElicitationsMu sync.Mutex
pendingElicitations map[string]chan struct{}
+
+ // resourceSubsMu guards resourceSubs.
+ resourceSubsMu sync.Mutex
+ // resourceSubs maps a subscribed resource URI to the cancel func of the
+ // goroutine running its dedicated subscriptions/listen stream. Populated
+ // only under SEP-2575; the legacy protocol routes Subscribe and
+ // Unsubscribe straight to the resources/subscribe and resources/unsubscribe
+ // RPCs and leaves this map untouched.
+ resourceSubs map[string]context.CancelFunc
}
type clientSessionState struct {
@@ -326,6 +511,45 @@ type clientSessionState struct {
func (cs *ClientSession) InitializeResult() *InitializeResult { return cs.state.InitializeResult }
+// usesNewProtocol reports whether this session has negotiated a protocol
+// version >= 2026-07-28, which requires the SEP-2575 per-request `_meta`
+// triple on every outgoing request.
+func (cs *ClientSession) usesNewProtocol() bool {
+ res := cs.state.InitializeResult
+ return res != nil && res.ProtocolVersion >= protocolVersion20260728
+}
+
+// injectRequestMeta populates the SEP-2575 per-request `_meta` fields
+// (protocolVersion, optional clientInfo, clientCapabilities) on the given
+// outgoing request params. Keys already present in params.Meta are not
+// overwritten. Per PR modelcontextprotocol/modelcontextprotocol#3002
+// clientInfo is SHOULD (not MUST), and is omitted when the client has no
+// [Implementation] configured.
+func injectRequestMeta[T any, P interface {
+ *T
+ Params
+}](cs *ClientSession, params P) P {
+ res := cs.state.InitializeResult
+ if params == nil {
+ params = new(T)
+ }
+ m := params.GetMeta()
+ if m == nil {
+ m = map[string]any{}
+ }
+ if _, ok := m[MetaKeyProtocolVersion]; !ok {
+ m[MetaKeyProtocolVersion] = res.ProtocolVersion
+ }
+ if _, ok := m[MetaKeyClientInfo]; !ok && cs.client.impl != nil {
+ m[MetaKeyClientInfo] = cs.client.impl
+ }
+ if _, ok := m[MetaKeyClientCapabilities]; !ok {
+ m[MetaKeyClientCapabilities] = cs.client.capabilities(res.ProtocolVersion).toV2()
+ }
+ params.SetMeta(m)
+ return params
+}
+
func (cs *ClientSession) ID() string {
if c, ok := cs.mcpConn.(hasSessionID); ok {
return c.SessionID()
@@ -348,6 +572,10 @@ func (cs *ClientSession) Close() error {
if cs.keepaliveCancel != nil {
cs.keepaliveCancel()
}
+ if cs.listenCancel != nil {
+ cs.listenCancel()
+ }
+ cs.cancelAllResourceSubscriptions()
err := cs.conn.Close()
if cs.onClose != nil && cs.calledOnClose.CompareAndSwap(false, true) {
@@ -363,6 +591,24 @@ func (cs *ClientSession) Wait() error {
return cs.conn.Wait()
}
+// lookupTool returns the most recently seen definition of the tool with the
+// given name across all cached ListTools results, or nil if no such tool has
+// been seen. It is used by CallTool to inject the tool definition into the
+// outgoing request context for transport-layer features (e.g. x-mcp-header
+// param annotations).
+func (cs *ClientSession) lookupTool(name string) *Tool {
+ cs.toolsCache.mu.Lock()
+ defer cs.toolsCache.mu.Unlock()
+ for _, entry := range cs.toolsCache.cachedValues {
+ for _, t := range entry.result.Tools {
+ if t.Name == name {
+ return t
+ }
+ }
+ }
+ return nil
+}
+
// registerElicitationWaiter registers a waiter for an elicitation complete
// notification with the given elicitation ID. It returns two functions: an await
// function that waits for the notification or context cancellation, and a cleanup
@@ -405,12 +651,18 @@ func (cs *ClientSession) registerElicitationWaiter(elicitationID string) (await
// startKeepalive starts the keepalive mechanism for this client session.
func (cs *ClientSession) startKeepalive(interval time.Duration) {
- startKeepalive(cs, interval, &cs.keepaliveCancel, cs.client.opts.Logger)
+ startKeepalive(cs, interval, cs.client.opts.KeepAliveFailureThreshold, &cs.keepaliveCancel, cs.client.opts.Logger)
}
// AddRoots adds the given roots to the client,
// replacing any with the same URIs,
// and notifies any connected servers.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). Migrate to passing paths via tool parameters,
+// resource URIs, or configuration. See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func (c *Client) AddRoots(roots ...*Root) {
// Only notify if something could change.
if len(roots) == 0 {
@@ -423,6 +675,12 @@ func (c *Client) AddRoots(roots ...*Root) {
// RemoveRoots removes the roots with the given URIs,
// and notifies any connected servers if the list has changed.
// It is not an error to remove a nonexistent root.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). Migrate to passing paths via tool parameters,
+// resource URIs, or configuration. See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func (c *Client) RemoveRoots(uris ...string) {
changeAndNotify(c, notificationRootsListChanged, &RootsListChangedParams{},
func() bool { return c.roots.remove(uris...) })
@@ -914,10 +1172,13 @@ var clientMethodInfos = map[string]methodInfo{
notificationLoggingMessage: newClientMethodInfo(clientMethod((*Client).callLoggingHandler), notification),
notificationProgress: newClientMethodInfo(clientSessionMethod((*ClientSession).callProgressNotificationHandler), notification),
notificationElicitationComplete: newClientMethodInfo(clientMethod((*Client).callElicitationCompleteHandler), notification|missingParamsOK),
+ notificationSubscriptionsAck: newClientMethodInfo(clientMethod((*Client).callSubscriptionsAckHandler), notification|missingParamsOK),
}
func (cs *ClientSession) sendingMethodInfos() map[string]methodInfo {
- return serverMethodInfos
+ cs.client.mu.Lock()
+ defer cs.client.mu.Unlock()
+ return cs.client.sendMethods
}
func (cs *ClientSession) receivingMethodInfos() map[string]methodInfo {
@@ -970,18 +1231,51 @@ func (cs *ClientSession) Ping(ctx context.Context, params *PingParams) error {
}
// ListPrompts lists prompts that are currently available on the server.
+//
+// Results may be served from a client-side TTL cache populated by previous
+// calls; see SEP-2549.
func (cs *ClientSession) ListPrompts(ctx context.Context, params *ListPromptsParams) (*ListPromptsResult, error) {
- return handleSend[*ListPromptsResult](ctx, methodListPrompts, newClientRequest(cs, orZero[Params](params)))
+ if cs.usesNewProtocol() {
+ if result, ok := cachedListResult(&cs.promptsCache, params); ok {
+ return result, nil
+ }
+ params = injectRequestMeta(cs, params)
+ }
+ result, err := handleSend[*ListPromptsResult](ctx, methodListPrompts, newClientRequest(cs, orZero[Params](params)))
+ if err != nil {
+ return nil, err
+ }
+ if cs.usesNewProtocol() {
+ cs.promptsCache.put(params.Cursor, result)
+ }
+ return result, nil
}
// GetPrompt gets a prompt from the server.
func (cs *ClientSession) GetPrompt(ctx context.Context, params *GetPromptParams) (*GetPromptResult, error) {
+ if cs.usesNewProtocol() {
+ params = injectRequestMeta(cs, params)
+ }
return handleSend[*GetPromptResult](ctx, methodGetPrompt, newClientRequest(cs, orZero[Params](params)))
}
// ListTools lists tools that are currently available on the server.
func (cs *ClientSession) ListTools(ctx context.Context, params *ListToolsParams) (*ListToolsResult, error) {
- return handleSend[*ListToolsResult](ctx, methodListTools, newClientRequest(cs, orZero[Params](params)))
+ if cs.usesNewProtocol() {
+ if result, ok := cachedListResult(&cs.toolsCache, params); ok {
+ return result, nil
+ }
+ params = injectRequestMeta(cs, params)
+ }
+ result, err := handleSend[*ListToolsResult](ctx, methodListTools, newClientRequest(cs, orZero[Params](params)))
+ if err != nil {
+ return nil, err
+ }
+ result.Tools = filterValidTools(cs.client.opts.Logger, result.Tools)
+ if cs.usesNewProtocol() {
+ cs.toolsCache.put(params.Cursor, result)
+ }
+ return result, nil
}
// CallTool calls the tool with the given parameters.
@@ -995,9 +1289,23 @@ func (cs *ClientSession) CallTool(ctx context.Context, params *CallToolParams) (
// Avoid sending nil over the wire.
params.Arguments = map[string]any{}
}
+ if tool := cs.lookupTool(params.Name); tool != nil {
+ ctx = context.WithValue(ctx, toolContextKey, tool)
+ }
+ if cs.usesNewProtocol() {
+ params = injectRequestMeta(cs, params)
+ }
return handleSend[*CallToolResult](ctx, methodCallTool, newClientRequest(cs, orZero[Params](params)))
}
+// SetLoggingLevel sets the minimum severity level for log messages sent by
+// the server.
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). Migrate to consuming stderr output (for STDIO
+// servers) or OpenTelemetry. See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func (cs *ClientSession) SetLoggingLevel(ctx context.Context, params *SetLoggingLevelParams) error {
_, err := handleSend[*emptyResult](ctx, methodSetLevel, newClientRequest(cs, orZero[Params](params)))
return err
@@ -1005,38 +1313,161 @@ func (cs *ClientSession) SetLoggingLevel(ctx context.Context, params *SetLogging
// ListResources lists the resources that are currently available on the server.
func (cs *ClientSession) ListResources(ctx context.Context, params *ListResourcesParams) (*ListResourcesResult, error) {
- return handleSend[*ListResourcesResult](ctx, methodListResources, newClientRequest(cs, orZero[Params](params)))
+ if cs.usesNewProtocol() {
+ if result, ok := cachedListResult(&cs.resourcesCache, params); ok {
+ return result, nil
+ }
+ params = injectRequestMeta(cs, params)
+ }
+ result, err := handleSend[*ListResourcesResult](ctx, methodListResources, newClientRequest(cs, orZero[Params](params)))
+ if err != nil {
+ return nil, err
+ }
+ if cs.usesNewProtocol() {
+ cs.resourcesCache.put(params.Cursor, result)
+ }
+ return result, nil
}
// ListResourceTemplates lists the resource templates that are currently available on the server.
func (cs *ClientSession) ListResourceTemplates(ctx context.Context, params *ListResourceTemplatesParams) (*ListResourceTemplatesResult, error) {
- return handleSend[*ListResourceTemplatesResult](ctx, methodListResourceTemplates, newClientRequest(cs, orZero[Params](params)))
+ if cs.usesNewProtocol() {
+ if result, ok := cachedListResult(&cs.resourceTemplatesCache, params); ok {
+ return result, nil
+ }
+ params = injectRequestMeta(cs, params)
+ }
+ result, err := handleSend[*ListResourceTemplatesResult](ctx, methodListResourceTemplates, newClientRequest(cs, orZero[Params](params)))
+ if err != nil {
+ return nil, err
+ }
+ if cs.usesNewProtocol() {
+ cs.resourceTemplatesCache.put(params.Cursor, result)
+ }
+ return result, nil
}
// ReadResource asks the server to read a resource and return its contents.
func (cs *ClientSession) ReadResource(ctx context.Context, params *ReadResourceParams) (*ReadResourceResult, error) {
- return handleSend[*ReadResourceResult](ctx, methodReadResource, newClientRequest(cs, orZero[Params](params)))
+ if cs.usesNewProtocol() {
+ var uri string
+ if params != nil {
+ uri = params.URI
+ }
+ if result, ok := cs.readResourceCache.get(uri); ok {
+ return result, nil
+ }
+ params = injectRequestMeta(cs, params)
+ }
+ result, err := handleSend[*ReadResourceResult](ctx, methodReadResource, newClientRequest(cs, orZero[Params](params)))
+ if err != nil {
+ return nil, err
+ }
+ if cs.usesNewProtocol() {
+ cs.readResourceCache.put(params.URI, result)
+ }
+ return result, nil
}
func (cs *ClientSession) Complete(ctx context.Context, params *CompleteParams) (*CompleteResult, error) {
+ if cs.usesNewProtocol() {
+ params = injectRequestMeta(cs, params)
+ }
return handleSend[*CompleteResult](ctx, methodComplete, newClientRequest(cs, orZero[Params](params)))
}
// Subscribe sends a "resources/subscribe" request to the server, asking for
// notifications when the specified resource changes.
func (cs *ClientSession) Subscribe(ctx context.Context, params *SubscribeParams) error {
- _, err := handleSend[*emptyResult](ctx, methodSubscribe, newClientRequest(cs, orZero[Params](params)))
- return err
+ if !cs.usesNewProtocol() {
+ _, err := handleSend[*emptyResult](ctx, methodSubscribe, newClientRequest(cs, orZero[Params](params)))
+ return err
+ }
+ if params == nil || params.URI == "" {
+ return fmt.Errorf("Subscribe: missing URI")
+ }
+ uri := params.URI
+
+ var listenCtx context.Context
+ cs.resourceSubsMu.Lock()
+ if _, exists := cs.resourceSubs[uri]; !exists {
+ var cancel context.CancelFunc
+ listenCtx, cancel = context.WithCancel(context.Background())
+ if cs.resourceSubs == nil {
+ cs.resourceSubs = make(map[string]context.CancelFunc)
+ }
+ cs.resourceSubs[uri] = cancel
+ }
+ cs.resourceSubsMu.Unlock()
+ if listenCtx == nil {
+ // Already subscribed to this URI
+ return nil
+ }
+
+ return cs.subscriptionsListen(listenCtx, &SubscriptionsListenParams{
+ Notifications: &NotificationSubscriptions{
+ ResourceSubscriptions: []string{uri},
+ },
+ })
}
-// Unsubscribe sends a "resources/unsubscribe" request to the server, cancelling
-// a previous subscription.
+// Unsubscribe cancels a previous [ClientSession.Subscribe] for params.URI.
+//
+// Under the legacy protocol it sends a "resources/unsubscribe" request.
+//
+// Under SEP-2575 it cancels the background "subscriptions/listen" stream
+// opened by Subscribe for the URI. Unsubscribe is idempotent: calling it for
+// a URI that is not currently subscribed is a no-op.
func (cs *ClientSession) Unsubscribe(ctx context.Context, params *UnsubscribeParams) error {
- _, err := handleSend[*emptyResult](ctx, methodUnsubscribe, newClientRequest(cs, orZero[Params](params)))
+ if !cs.usesNewProtocol() {
+ _, err := handleSend[*emptyResult](ctx, methodUnsubscribe, newClientRequest(cs, orZero[Params](params)))
+ return err
+ }
+ if params == nil || params.URI == "" {
+ return fmt.Errorf("Unsubscribe: missing URI")
+ }
+ cs.resourceSubsMu.Lock()
+ cancel, ok := cs.resourceSubs[params.URI]
+ delete(cs.resourceSubs, params.URI)
+ cs.resourceSubsMu.Unlock()
+ if ok {
+ cancel()
+ }
+ return nil
+}
+
+// cancelAllResourceSubscriptions cancels every active SEP-2575 resource
+// subscription opened via Subscribe. The listen goroutines exit
+// asynchronously as their contexts unwind. Called from Close.
+func (cs *ClientSession) cancelAllResourceSubscriptions() {
+ cs.resourceSubsMu.Lock()
+ subs := cs.resourceSubs
+ cs.resourceSubs = nil
+ cs.resourceSubsMu.Unlock()
+ for _, cancel := range subs {
+ cancel()
+ }
+}
+
+// SubscriptionsListen opens a SEP-2575 "subscriptions/listen" stream.
+//
+// The server's first message on the stream is "notifications/subscriptions/acknowledged";
+// subsequent opted-in notifications (e.g. tools/list_changed) are delivered through the
+// usual handlers registered in [ClientOptions].
+func (cs *ClientSession) subscriptionsListen(ctx context.Context, params *SubscriptionsListenParams) error {
+ params = injectRequestMeta(cs, params)
+ _, err := handleSend[*SubscriptionsListenResult](ctx, methodSubscriptionsListen, newClientRequest(cs, orZero[Params](params)))
return err
}
+func (c *Client) callSubscriptionsAckHandler(context.Context, *ClientRequest[*SubscriptionsAcknowledgedParams]) (Result, error) {
+ return nil, nil
+}
+
func (c *Client) callToolChangedHandler(ctx context.Context, req *ToolListChangedRequest) (Result, error) {
+ if cs, ok := req.GetSession().(*ClientSession); ok {
+ cs.toolsCache.invalidate()
+ }
if h := c.opts.ToolListChangedHandler; h != nil {
h(ctx, req)
}
@@ -1044,6 +1475,9 @@ func (c *Client) callToolChangedHandler(ctx context.Context, req *ToolListChange
}
func (c *Client) callPromptChangedHandler(ctx context.Context, req *PromptListChangedRequest) (Result, error) {
+ if cs, ok := req.GetSession().(*ClientSession); ok {
+ cs.promptsCache.invalidate()
+ }
if h := c.opts.PromptListChangedHandler; h != nil {
h(ctx, req)
}
@@ -1051,6 +1485,10 @@ func (c *Client) callPromptChangedHandler(ctx context.Context, req *PromptListCh
}
func (c *Client) callResourceChangedHandler(ctx context.Context, req *ResourceListChangedRequest) (Result, error) {
+ if cs, ok := req.GetSession().(*ClientSession); ok {
+ cs.resourcesCache.invalidate()
+ cs.resourceTemplatesCache.invalidate()
+ }
if h := c.opts.ResourceListChangedHandler; h != nil {
h(ctx, req)
}
@@ -1058,6 +1496,9 @@ func (c *Client) callResourceChangedHandler(ctx context.Context, req *ResourceLi
}
func (c *Client) callResourceUpdatedHandler(ctx context.Context, req *ResourceUpdatedNotificationRequest) (Result, error) {
+ if cs, ok := req.GetSession().(*ClientSession); ok && req.Params != nil {
+ cs.readResourceCache.invalidateKey(req.Params.URI)
+ }
if h := c.opts.ResourceUpdatedHandler; h != nil {
h(ctx, req)
}
@@ -1181,3 +1622,67 @@ func paginate[P listParams, R listResult[T], T any](ctx context.Context, params
}
}
}
+
+// AddSendingCustomMethod registers a custom JSON-RPC method
+// that the client may send to the server.
+//
+// Registration is decoupled from invocation: extensions typically call this
+// during setup, while the actual call site uses [CallCustomMethod].
+//
+// if err := mcp.AddSendingCustomMethod[*SearchParams, *SearchResult](c, "acme/search"); err != nil {
+// return err
+// }
+// // ... later, anywhere a *ClientSession is available:
+// result, err := mcp.CallCustomMethod[*SearchParams, *SearchResult](
+// ctx, cs, "acme/search", &SearchParams{Query: "hello"})
+//
+// AddSendingCustomMethod returns an error if method is the name of a standard
+// MCP method. Registering the same method twice replaces the previous
+// registration.
+func AddSendingCustomMethod[P paramsPtr[PT], R Result, PT any](
+ c *Client,
+ method string,
+) error {
+ if _, ok := serverMethodInfos[method]; ok {
+ return fmt.Errorf("mcp: AddSendingCustomMethod: %q shadows a standard MCP method", method)
+ }
+
+ mi := methodInfo{
+ newResult: func() Result {
+ return reflect.New(reflect.TypeFor[R]().Elem()).Interface().(R)
+ },
+ }
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.sendMethods[method] = mi
+ return nil
+}
+
+// CallCustomMethod sends a custom (non-standard) JSON-RPC method to the
+// server and decodes the response into R.
+//
+// The method must have been registered on the session's client via
+// [AddSendingCustomMethod].
+func CallCustomMethod[P paramsPtr[PT], R Result, PT any](
+ ctx context.Context,
+ cs *ClientSession,
+ method string,
+ params P,
+) (R, error) {
+ c := cs.client
+ c.mu.Lock()
+ _, ok := c.sendMethods[method]
+ c.mu.Unlock()
+ if !ok {
+ var zero R
+ return zero, fmt.Errorf("mcp: CallCustomMethod: %q is not registered; call AddSendingCustomMethod first", method)
+ }
+ if cs.usesNewProtocol() {
+ params = injectRequestMeta(cs, params)
+ }
+ return handleSend[R](ctx, method, &ClientRequest[P]{
+ Session: cs,
+ Params: params,
+ })
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/content.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/content.go
index 95ea40d..7af90fe 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/content.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/content.go
@@ -189,6 +189,11 @@ func (c *EmbeddedResource) fromWire(wire *wireContent) {
// ToolUseContent represents a request from the assistant to invoke a tool.
// This content type is only valid in sampling messages.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type ToolUseContent struct {
// ID is a unique identifier for this tool use, used to match with ToolResultContent.
ID string
@@ -229,12 +234,19 @@ func (c *ToolUseContent) fromWire(wire *wireContent) {
// ToolResultContent represents the result of a tool invocation.
// This content type is only valid in sampling messages with role "user".
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type ToolResultContent struct {
// ToolUseID references the ID from the corresponding ToolUseContent.
ToolUseID string
// Content holds the unstructured result of the tool call.
Content []Content
- // StructuredContent holds an optional structured result as a JSON object.
+ // StructuredContent holds an optional structured result. Per SEP-2106, it
+ // may be any valid JSON value (object, array, or primitive) conforming to
+ // the tool's output schema.
StructuredContent any
// IsError indicates whether the tool call ended in an error.
IsError bool
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/event.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/event.go
index 41ff4ae..f0cbb2f 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/event.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/event.go
@@ -52,7 +52,12 @@ func writeEvent(w http.ResponseWriter, evt Event) (int, error) {
if evt.Retry != "" {
fmt.Fprintf(&b, "retry: %s\n", evt.Retry)
}
- fmt.Fprintf(&b, "data: %s\n\n", string(evt.Data))
+ // Write the payload directly into a pre-grown buffer to avoid the extra
+ // copy from string(evt.Data) and repeated buffer regrowths.
+ b.Grow(len("data: \n\n") + len(evt.Data))
+ b.WriteString("data: ")
+ b.Write(evt.Data)
+ b.WriteString("\n\n")
n, err := w.Write(b.Bytes())
rc := http.NewResponseController(w)
// Ignore returned error as flushing is best-effort.
@@ -60,13 +65,21 @@ func writeEvent(w http.ResponseWriter, evt Event) (int, error) {
return n, err
}
-// scanEvents iterates SSE events in the given scanner. The iterated error is
-// terminal: if encountered, the stream is corrupt or broken and should no
-// longer be used.
+// DefaultMaxEventSize is the default maximum number of bytes buffered while
+// reading a single server-sent event before the input is rejected.
+const DefaultMaxEventSize = 16 << 20 // 16 MiB
+
+// scanEventsLimited iterates SSE events in the given reader, buffering at most
+// maxEventSize bytes per event. When maxEventSize > 0, an event is reported as
+// [errMalformedEvent] once its size exceeds it; a non-positive maxEventSize
+// disables the cap.
+//
+// The iterated error is terminal: if encountered, the stream is corrupt or
+// broken and should no longer be used.
//
// TODO(rfindley): consider a different API here that makes failure modes more
// apparent.
-func scanEvents(r io.Reader) iter.Seq2[Event, error] {
+func scanEventsLimited(r io.Reader, maxEventSize int) iter.Seq2[Event, error] {
reader := bufio.NewReader(r)
// TODO: investigate proper behavior when events are out of order, or have
@@ -89,8 +102,9 @@ func scanEvents(r io.Reader) iter.Seq2[Event, error] {
// - Lines starting with ":" are ignored.
// - Records are terminated with two consecutive newlines.
var (
- evt Event
- dataBuf *bytes.Buffer // if non-nil, preceding field was also data
+ evt Event
+ dataBuf *bytes.Buffer // if non-nil, preceding field was also data
+ eventBytes int // bytes read for the current, in-progress event
)
yieldEvent := func() bool {
if dataBuf != nil {
@@ -107,11 +121,20 @@ func scanEvents(r io.Reader) iter.Seq2[Event, error] {
return true
}
for {
- line, err := reader.ReadBytes('\n')
+ budget := -1
+ if maxEventSize > 0 {
+ budget = maxEventSize - eventBytes
+ }
+ line, err := readEventLine(reader, budget)
+ if errors.Is(err, errEventTooLarge) {
+ yield(Event{}, fmt.Errorf("%w: SSE event exceeded %d bytes without terminating", errMalformedEvent, maxEventSize))
+ return
+ }
if err != nil && !errors.Is(err, io.EOF) {
yield(Event{}, fmt.Errorf("error reading event: %v", err))
return
}
+ eventBytes += len(line)
line = bytes.TrimRight(line, "\r\n")
isEOF := errors.Is(err, io.EOF)
@@ -119,6 +142,7 @@ func scanEvents(r io.Reader) iter.Seq2[Event, error] {
if !yieldEvent() {
return
}
+ eventBytes = 0 // reset the budget between events
if isEOF {
return
}
@@ -317,6 +341,31 @@ var ErrEventsPurged = errors.New("data purged")
// transient I/O errors which may be retryable.
var errMalformedEvent = errors.New("malformed event")
+// errEventTooLarge is returned by [readEventLine] when a single line would
+// exceed the remaining per-event byte budget.
+var errEventTooLarge = errors.New("SSE event exceeded maximum size")
+
+// readEventLine reads a single '\n'-terminated line from r. When budget >= 0 it
+// reads at most budget bytes, returning [errEventTooLarge] once that budget is
+// exceeded before a newline arrives.
+func readEventLine(r *bufio.Reader, budget int) ([]byte, error) {
+ if budget < 0 {
+ return r.ReadBytes('\n')
+ }
+ var line []byte
+ for {
+ frag, err := r.ReadSlice('\n')
+ if len(line)+len(frag) > budget {
+ return nil, errEventTooLarge
+ }
+ line = append(line, frag...)
+ if errors.Is(err, bufio.ErrBufferFull) {
+ continue // looking for delim
+ }
+ return line, err
+ }
+}
+
// After implements [EventStore.After].
func (s *MemoryEventStore) After(_ context.Context, sessionID, streamID string, index int) iter.Seq2[[]byte, error] {
// Return the data items to yield.
@@ -332,12 +381,15 @@ func (s *MemoryEventStore) After(_ context.Context, sessionID, streamID string,
if !ok {
return nil, fmt.Errorf("MemoryEventStore.After: unknown stream ID %v in session %q", streamID, sessionID)
}
- start := index + 1
- if dl.first > start {
+ start := (index + 1) - dl.first
+ if start < 0 {
return nil, fmt.Errorf("MemoryEventStore.After: index %d, stream ID %v, session %q: %w",
index, streamID, sessionID, ErrEventsPurged)
}
- return slices.Clone(dl.data[start-dl.first:]), nil
+ if start >= len(dl.data) {
+ return nil, nil
+ }
+ return slices.Clone(dl.data[start:]), nil
}
return func(yield func([]byte, error) bool) {
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/logging.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/logging.go
index b1bd82b..e8d0cd7 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/logging.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/logging.go
@@ -13,6 +13,8 @@ import (
"slices"
"sync"
"time"
+
+ "golang.org/x/time/rate"
)
// Logging levels.
@@ -66,7 +68,19 @@ func compareLevels(l1, l2 LoggingLevel) int {
return cmp.Compare(mcpLevelToSlog(l1), mcpLevelToSlog(l2))
}
+type logLevelContextKey struct{}
+
+func logLevelFromContext(ctx context.Context) (LoggingLevel, bool) {
+ v, ok := ctx.Value(logLevelContextKey{}).(LoggingLevel)
+ return v, ok
+}
+
// LoggingHandlerOptions are options for a LoggingHandler.
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type LoggingHandlerOptions struct {
// The value for the "logger" field of logging notifications.
LoggerName string
@@ -77,16 +91,21 @@ type LoggingHandlerOptions struct {
}
// A LoggingHandler is a [slog.Handler] for MCP.
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type LoggingHandler struct {
opts LoggingHandlerOptions
ss *ServerSession
// Ensures that the buffer reset is atomic with the write (see Handle).
// A pointer so that clones share the mutex. See
// https://github.com/golang/example/blob/master/slog-handler-guide/README.md#getting-the-mutex-right.
- mu *sync.Mutex
- lastMessageSent time.Time // for rate-limiting
- buf *bytes.Buffer
- handler slog.Handler
+ mu *sync.Mutex
+ limiter *rate.Limiter // for rate-limiting
+ buf *bytes.Buffer
+ handler slog.Handler
}
// ensureLogger returns l if non-nil, otherwise a discard logger.
@@ -99,6 +118,11 @@ func ensureLogger(l *slog.Logger) *slog.Logger {
// NewLoggingHandler creates a [LoggingHandler] that logs to the given [ServerSession] using a
// [slog.JSONHandler].
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func NewLoggingHandler(ss *ServerSession, opts *LoggingHandlerOptions) *LoggingHandler {
var buf bytes.Buffer
jsonHandler := slog.NewJSONHandler(&buf, &slog.HandlerOptions{
@@ -118,6 +142,9 @@ func NewLoggingHandler(ss *ServerSession, opts *LoggingHandlerOptions) *LoggingH
}
if opts != nil {
lh.opts = *opts
+ if opts.MinInterval > 0 {
+ lh.limiter = rate.NewLimiter(rate.Every(opts.MinInterval), 1)
+ }
}
return lh
}
@@ -126,6 +153,9 @@ func NewLoggingHandler(ss *ServerSession, opts *LoggingHandlerOptions) *LoggingH
func (h *LoggingHandler) Enabled(ctx context.Context, level slog.Level) bool {
// This is also checked in ServerSession.LoggingMessage, so checking it here
// is just an optimization that skips building the JSON.
+ if mcpLevel, ok := logLevelFromContext(ctx); ok {
+ return mcpLevel != "" && level >= mcpLevelToSlog(mcpLevel)
+ }
h.ss.mu.Lock()
mcpLevel := h.ss.state.LogLevel
h.ss.mu.Unlock()
@@ -157,11 +187,7 @@ func (h *LoggingHandler) Handle(ctx context.Context, r slog.Record) error {
func (h *LoggingHandler) handle(ctx context.Context, r slog.Record) error {
// Observe the rate limit.
- // TODO(jba): use golang.org/x/time/rate.
- h.mu.Lock()
- skip := time.Since(h.lastMessageSent) < h.opts.MinInterval
- h.mu.Unlock()
- if skip {
+ if h.limiter != nil && !h.limiter.Allow() {
return nil
}
@@ -184,10 +210,6 @@ func (h *LoggingHandler) handle(ctx context.Context, r slog.Record) error {
return err
}
- h.mu.Lock()
- h.lastMessageSent = time.Now()
- h.mu.Unlock()
-
params := &LoggingMessageParams{
Logger: h.opts.LoggerName,
Level: slogLevelToMCP(r.Level),
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/mrtr.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/mrtr.go
new file mode 100644
index 0000000..008c0f8
--- /dev/null
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/mrtr.go
@@ -0,0 +1,308 @@
+// Copyright 2025 The Go MCP SDK Authors. All rights reserved.
+// Use of this source code is governed by the license
+// that can be found in the LICENSE file.
+
+package mcp
+
+import (
+ "context"
+ "fmt"
+ "log/slog"
+ "sync"
+
+ "github.com/modelcontextprotocol/go-sdk/jsonrpc"
+ "golang.org/x/sync/errgroup"
+)
+
+const maxMultiRoundTripRetries = 10
+const maxLoadSheddingMultiRoundTripRetries = 3
+
+// MultiRoundTripOptions configures the client-side multi round-trip request (SEP-2322)
+// middleware. The middleware is enabled by default and automatically fulfills input
+// requests from the server by invoking the appropriate client handlers and
+// retrying the original call.
+type MultiRoundTripOptions struct {
+ // Disabled prevents the automatic multi-round-tirp middleware from being installed.
+ // When true, the client returns input-required results directly and callers must
+ // handle the retry loop themselves using [CallToolResult.NeedsInput],
+ // [GetPromptResult.NeedsInput], or [ReadResourceResult.NeedsInput].
+ Disabled bool
+}
+
+type multiRoundTripResponse interface {
+ setResultType(resultType)
+ inputRequests() map[string]InputRequest
+ requestState() string
+ hasContent() bool
+}
+
+func handleMultiRoundTripResult(ss *ServerSession, logger *slog.Logger, res multiRoundTripResponse) error {
+ if res == nil {
+ return nil
+ }
+ hasInputRequests := res.inputRequests() != nil
+
+ if hasInputRequests && res.hasContent() {
+ logger.Warn("handler returned both content and inputRequests")
+ return &jsonrpc.Error{
+ Code: jsonrpc.CodeInternalError,
+ Message: "server bug: result has both content and inputRequests",
+ }
+ }
+
+ if clientSupportsMultiRoundTrip(ss) {
+ // For older clients the resultType is left unset. Input requests will be handled
+ // by serverMultiRoundTripMiddleware client calls and handler reinvocation.
+ if hasInputRequests {
+ res.setResultType(resultTypeInputRequired)
+ } else {
+ res.setResultType(resultTypeComplete)
+ }
+ }
+ return nil
+}
+
+func clientSupportsMultiRoundTrip(ss *ServerSession) bool {
+ protocolVersion := latestProtocolVersion
+ if iparams := ss.InitializeParams(); iparams != nil {
+ protocolVersion = iparams.ProtocolVersion
+ }
+ return protocolVersion >= protocolVersion20260728
+}
+
+func clientMultiRoundTripMiddleware() Middleware {
+ return func(next MethodHandler) MethodHandler {
+ return func(ctx context.Context, method string, req Request) (Result, error) {
+ if method != methodCallTool && method != methodGetPrompt && method != methodReadResource {
+ return next(ctx, method, req)
+ }
+
+ loadSheddingFailures := 0
+ for retries := 1; ; retries++ {
+ res, err := next(ctx, method, req)
+ if err != nil {
+ return res, err
+ }
+ mrtrResult, ok := res.(multiRoundTripResponse)
+ if !ok {
+ return res, nil
+ }
+ reqMap := mrtrResult.inputRequests()
+ if reqMap == nil {
+ return res, nil
+ }
+ if len(reqMap) == 0 {
+ loadSheddingFailures++
+ }
+ if loadSheddingFailures >= maxLoadSheddingMultiRoundTripRetries {
+ return nil, fmt.Errorf("multi-round-trip: exceeded maximum load-shedding retries (%d)", maxLoadSheddingMultiRoundTripRetries)
+ }
+ if retries >= maxMultiRoundTripRetries {
+ return nil, fmt.Errorf("multi-round-trip: exceeded maximum retries (%d)", maxMultiRoundTripRetries)
+ }
+ cs, ok := req.GetSession().(*ClientSession)
+ if !ok {
+ return res, nil
+ }
+ responses, err := fulfillInputRequests(ctx, cs, reqMap)
+ if err != nil {
+ return nil, err
+ }
+ req, err = setMultiRoundTripRetryParams(method, req, responses, mrtrResult.requestState())
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+}
+
+// serverMultiRoundTripMiddleware is a receiving middleware for servers that transparently
+// handles multi-round-trip for clients on older protocol versions. When a handler returns
+// InputRequests and the client does not support multi-round-trip, the middleware fulfills
+// the requests by calling the client directly and reinvokes the handler once with the responses.
+func serverMultiRoundTripMiddleware() Middleware {
+ return func(next MethodHandler) MethodHandler {
+ return func(ctx context.Context, method string, req Request) (Result, error) {
+ if method != methodCallTool && method != methodGetPrompt && method != methodReadResource {
+ return next(ctx, method, req)
+ }
+
+ ss, ok := req.GetSession().(*ServerSession)
+ if !ok {
+ return next(ctx, method, req)
+ }
+ if clientSupportsMultiRoundTrip(ss) {
+ return next(ctx, method, req)
+ }
+
+ res, err := next(ctx, method, req)
+ if err != nil {
+ return res, err
+ }
+ mrtrResult, ok := res.(multiRoundTripResponse)
+ if !ok {
+ return res, nil
+ }
+ reqMap := mrtrResult.inputRequests()
+ if reqMap == nil {
+ return res, nil
+ }
+ if len(reqMap) == 0 {
+ return nil, fmt.Errorf("the server is busy, retry later")
+ }
+ responses, err := fulfillServerInputRequests(ctx, ss, reqMap)
+ if err != nil {
+ return nil, err
+ }
+ req, err = setMultiRoundTripRetryParams(method, req, responses, mrtrResult.requestState())
+ if err != nil {
+ return nil, err
+ }
+ return next(ctx, method, req)
+ }
+ }
+}
+
+func fulfillServerInputRequests(ctx context.Context, ss *ServerSession, requests InputRequestMap) (InputResponseMap, error) {
+ g, ctx := errgroup.WithContext(ctx)
+ var mu sync.Mutex
+ responses := make(InputResponseMap, len(requests))
+ for id, ir := range requests {
+ g.Go(func() error {
+ resp, err := fulfillServerInputRequest(ctx, ss, ir)
+ if err != nil {
+ return fmt.Errorf("fulfilling input request %q: %w", id, err)
+ }
+ mu.Lock()
+ responses[id] = resp
+ mu.Unlock()
+ return nil
+ })
+ }
+ if err := g.Wait(); err != nil {
+ return nil, fmt.Errorf("multi-round-trip: %w", err)
+ }
+ return responses, nil
+}
+
+func fulfillServerInputRequest(ctx context.Context, ss *ServerSession, ir InputRequest) (InputResponse, error) {
+ switch p := ir.(type) {
+ case *ElicitParams:
+ return ss.Elicit(ctx, p)
+ case *CreateMessageParams:
+ return ss.CreateMessageWithTools(ctx, createMessageParamsToWithTools(p))
+ case *CreateMessageWithToolsParams:
+ return ss.CreateMessageWithTools(ctx, p)
+ case *ListRootsParams:
+ return ss.ListRoots(ctx, p)
+ default:
+ return nil, fmt.Errorf("unknown input request type: %T", ir)
+ }
+}
+
+func createMessageParamsToWithTools(p *CreateMessageParams) *CreateMessageWithToolsParams {
+ var msgs []*SamplingMessageV2
+ for _, m := range p.Messages {
+ msgs = append(msgs, &SamplingMessageV2{Content: []Content{m.Content}, Role: m.Role})
+ }
+ return &CreateMessageWithToolsParams{
+ Meta: p.Meta,
+ IncludeContext: p.IncludeContext,
+ MaxTokens: p.MaxTokens,
+ Messages: msgs,
+ Metadata: p.Metadata,
+ ModelPreferences: p.ModelPreferences,
+ StopSequences: p.StopSequences,
+ SystemPrompt: p.SystemPrompt,
+ Temperature: p.Temperature,
+ }
+}
+
+// setMultiRoundTripRetryParams returns the request for the next round of a
+// multi-round-trip retry: a request whose params are a shallow copy of the
+// original, carrying the fulfilled responses and the request state to echo.
+// The original params are never mutated: on the client side they are
+// caller-owned, and a params struct reused across calls must not carry one
+// call's inputResponses and requestState into the next, where a server
+// gating on them (for example an elicitation confirmation) would treat the
+// new call as already answered.
+//
+// An unrecognized params type is an error. It cannot occur on the server
+// side, but client sending middleware runs before the retry loop and may
+// substitute its own params.
+func setMultiRoundTripRetryParams(method string, req Request, responses InputResponseMap, state string) (Request, error) {
+ var retryParams Params
+ switch p := req.GetParams().(type) {
+ case *CallToolParams:
+ cp := *p
+ cp.InputResponses = responses
+ cp.RequestState = state
+ retryParams = &cp
+ case *CallToolParamsRaw:
+ cp := *p
+ cp.InputResponses = responses
+ cp.RequestState = state
+ retryParams = &cp
+ case *GetPromptParams:
+ cp := *p
+ cp.InputResponses = responses
+ cp.RequestState = state
+ retryParams = &cp
+ case *ReadResourceParams:
+ cp := *p
+ cp.InputResponses = responses
+ cp.RequestState = state
+ retryParams = &cp
+ default:
+ return nil, fmt.Errorf("multi-round-trip: unsupported params type %T", p)
+ }
+ switch s := req.GetSession().(type) {
+ case *ClientSession:
+ return newClientRequest(s, retryParams), nil
+ case *ServerSession:
+ // Rebuild with the same constructor handleReceive uses: the
+ // receiving dispatch type-asserts on the request's concrete
+ // *ServerRequest[P] type, and Extra must carry over.
+ return s.receivingMethodInfos()[method].newRequest(s, retryParams, req.GetExtra()), nil
+ default:
+ return nil, fmt.Errorf("multi-round-trip: unsupported session type %T", s)
+ }
+}
+
+func fulfillInputRequests(ctx context.Context, cs *ClientSession, requests InputRequestMap) (InputResponseMap, error) {
+ g, ctx := errgroup.WithContext(ctx)
+ var mu sync.Mutex
+ responses := make(InputResponseMap, len(requests))
+ for id, ir := range requests {
+ g.Go(func() error {
+ resp, err := fulfillInputRequest(ctx, cs, ir)
+ if err != nil {
+ return fmt.Errorf("fulfilling input request %q: %w", id, err)
+ }
+ mu.Lock()
+ responses[id] = resp
+ mu.Unlock()
+ return nil
+ })
+ }
+ if err := g.Wait(); err != nil {
+ return nil, fmt.Errorf("multi round-trip: %w", err)
+ }
+ return responses, nil
+}
+
+func fulfillInputRequest(ctx context.Context, cs *ClientSession, ir InputRequest) (InputResponse, error) {
+ switch p := ir.(type) {
+ case *ElicitParams:
+ return cs.client.elicit(ctx, newClientRequest(cs, p))
+ case *CreateMessageParams:
+ return cs.client.createMessage(ctx, &CreateMessageWithToolsRequest{Session: cs, Params: createMessageParamsToWithTools(p)})
+ case *CreateMessageWithToolsParams:
+ return cs.client.createMessage(ctx, &CreateMessageWithToolsRequest{Session: cs, Params: p})
+ case *ListRootsParams:
+ return cs.client.listRoots(ctx, newClientRequest(cs, p))
+ default:
+ return nil, fmt.Errorf("unknown input request type: %T", ir)
+ }
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/protocol.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/protocol.go
index 1646788..63d7015 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/protocol.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/protocol.go
@@ -13,6 +13,185 @@ import (
"github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug"
)
+// resultType indicates whether a result is complete or requires further input
+// from the client via the multi round-trip request protocol.
+type resultType string
+
+const (
+ // resultTypeComplete indicates the result is final.
+ // This is the default when ResultType is empty.
+ resultTypeComplete resultType = "complete"
+
+ // resultTypeInputRequired indicates the server needs additional client
+ // input before it can complete the request. The client should fulfill the
+ // InputRequests and retry the call with the responses.
+ resultTypeInputRequired resultType = "input_required"
+)
+
+type completeResultWithType struct {
+ ResultType resultType `json:"resultType,omitempty"`
+}
+
+func (r *completeResultWithType) setResultType(rt resultType) { r.ResultType = rt }
+func (*completeResultWithType) isCompleteResult() {}
+
+type completeResultResponse interface {
+ setResultType(resultType)
+ isCompleteResult()
+}
+
+func setCompleteResultType(res Result) {
+ if r, ok := res.(completeResultResponse); ok {
+ r.setResultType(resultTypeComplete)
+ }
+}
+
+// InputRequest is a type for parameters that a server can include in the response
+// to request input from client (SEP-2322). Implementations are [*ElicitParams],
+// [*CreateMessageParams], and [*ListRootsParams].
+type InputRequest interface{ isInputRequest() }
+
+// InputRequestMap maps server-assigned request IDs to [InputRequest] values.
+// It is used in result types to tell the client what input the server needs.
+type InputRequestMap map[string]InputRequest
+
+func (m InputRequestMap) MarshalJSON() ([]byte, error) {
+ if m == nil {
+ return json.Marshal(map[string]any(nil))
+ }
+ type wire struct {
+ Method string `json:"method"`
+ Params InputRequest `json:"params,omitempty"`
+ }
+ typeToMethod := func(v InputRequest) (string, error) {
+ switch v.(type) {
+ case *ElicitParams:
+ return methodElicit, nil
+ case *CreateMessageParams, *CreateMessageWithToolsParams:
+ return methodCreateMessage, nil
+ case *ListRootsParams:
+ return methodListRoots, nil
+ default:
+ return "", fmt.Errorf("unsupported type: %T", v)
+ }
+ }
+ converted := map[string]*wire{}
+ for k, v := range m {
+ method, err := typeToMethod(v)
+ if err != nil {
+ return nil, err
+ }
+ if ep, ok := v.(*ElicitParams); ok {
+ v = ep.inferElicitMode()
+ }
+ converted[k] = &wire{Method: method, Params: v}
+ }
+ return json.Marshal(converted)
+}
+
+func (m *InputRequestMap) UnmarshalJSON(data []byte) error {
+ type raw struct {
+ Method string `json:"method"`
+ Params json.RawMessage `json:"params"`
+ }
+ var rawMap map[string]*raw
+ if err := json.Unmarshal(data, &rawMap); err != nil {
+ return err
+ }
+ if rawMap == nil {
+ return nil
+ }
+ result := make(InputRequestMap, len(rawMap))
+ for k, raw := range rawMap {
+ switch raw.Method {
+ case methodElicit:
+ var p ElicitParams
+ if err := json.Unmarshal(raw.Params, &p); err != nil {
+ return err
+ }
+ result[k] = &p
+ case methodCreateMessage:
+ var p CreateMessageWithToolsParams
+ if err := json.Unmarshal(raw.Params, &p); err != nil {
+ return err
+ }
+ result[k] = &p
+ case methodListRoots:
+ var p ListRootsParams
+ if err := json.Unmarshal(raw.Params, &p); err != nil {
+ return err
+ }
+ result[k] = &p
+ default:
+ return fmt.Errorf("unsupported InputRequest method: %q", raw.Method)
+ }
+ }
+ *m = result
+ return nil
+}
+
+// InputResponse is a type for results that a client sends back when fulfilling
+// a server input request (SEP-2322). Implementations are [*ElicitResult],
+// [*CreateMessageResult], and [*ListRootsResult].
+type InputResponse interface{ isInputResponse() }
+
+// InputResponseMap maps request IDs (from [InputRequestMap]) to [InputResponse]
+// values. It is used in params types when retrying a call after an
+// input-required result.
+type InputResponseMap map[string]InputResponse
+
+func (m *InputResponseMap) UnmarshalJSON(data []byte) error {
+ var rawMap map[string]json.RawMessage
+ if err := json.Unmarshal(data, &rawMap); err != nil {
+ return err
+ }
+ result := make(InputResponseMap, len(rawMap))
+ for k, raw := range rawMap {
+ v, err := unmarshalInputResponse(raw)
+ if err != nil {
+ return fmt.Errorf("inputResponses[%q]: %w", k, err)
+ }
+ result[k] = v
+ }
+ *m = result
+ return nil
+}
+
+// unmarshalInputResponse determines the concrete InputResponse type from the
+// JSON structure by searching for a discriminating key in a raw message.
+func unmarshalInputResponse(data json.RawMessage) (InputResponse, error) {
+ var probe struct {
+ Action json.RawMessage `json:"action"`
+ Role json.RawMessage `json:"role"`
+ Roots json.RawMessage `json:"roots"`
+ }
+ if err := json.Unmarshal(data, &probe); err != nil {
+ return nil, err
+ }
+ switch {
+ case probe.Roots != nil:
+ var p ListRootsResult
+ if err := json.Unmarshal(data, &p); err != nil {
+ return nil, err
+ }
+ return &p, nil
+ case probe.Action != nil:
+ var p ElicitResult
+ if err := json.Unmarshal(data, &p); err != nil {
+ return nil, err
+ }
+ return &p, nil
+ case probe.Role != nil:
+ var p CreateMessageWithToolsResult
+ if err := json.Unmarshal(data, &p); err != nil {
+ return nil, err
+ }
+ return &p, nil
+ default:
+ return nil, fmt.Errorf(`cannot determine InputResponse type: expected "action", "role", or "roots" key`)
+ }
+}
+
// Optional annotations for the client. The client can use annotations to inform
// how objects are used or displayed.
type Annotations struct {
@@ -46,6 +225,14 @@ type CallToolParams struct {
// Arguments holds the tool arguments. It can hold any value that can be
// marshaled to JSON.
Arguments any `json:"arguments,omitempty"`
+
+ // InputResponses maps input request IDs to responses, provided when
+ // retrying a call after receiving a result with ResultType
+ // ResultTypeInputRequired.
+ InputResponses InputResponseMap `json:"inputResponses,omitempty"`
+ // RequestState is the opaque state from the previous input-required result.
+ // The client must echo this back when retrying.
+ RequestState string `json:"requestState,omitempty"`
}
// CallToolParamsRaw is passed to tool handlers on the server. Its arguments
@@ -61,6 +248,14 @@ type CallToolParamsRaw struct {
// is the responsibility of the tool handler to unmarshal and validate the
// Arguments (see [AddTool]).
Arguments json.RawMessage `json:"arguments,omitempty"`
+
+ // InputResponses maps input request IDs to responses, provided when
+ // retrying a call after receiving a result with ResultType
+ // ResultTypeInputRequired.
+ InputResponses InputResponseMap `json:"inputResponses,omitempty"`
+ // RequestState is the opaque state from the previous input-required result.
+ // The client must echo this back when retrying.
+ RequestState string `json:"requestState,omitempty"`
}
// A CallToolResult is the server's response to a tool call.
@@ -82,7 +277,9 @@ type CallToolResult struct {
Content []Content `json:"content"`
// StructuredContent is an optional value that represents the structured
- // result of the tool call. It must marshal to a JSON object.
+ // result of the tool call. Per SEP-2106, it may marshal to any valid JSON
+ // value (object, array, or primitive) conforming to the tool's
+ // [Tool.OutputSchema].
//
// When using a [ToolHandlerFor] with structured output, you should not
// populate this field. It will be automatically populated with the typed Out
@@ -107,6 +304,24 @@ type CallToolResult struct {
// the Content field.
IsError bool `json:"isError,omitempty"`
+ // InputRequests is a map of server-assigned IDs to input requests.
+ // Populated only when ResultType is ResultTypeInputRequired.
+ // The client must fulfill these and echo the IDs back in InputResponses
+ // when retrying the call.
+ InputRequests InputRequestMap `json:"inputRequests,omitempty"`
+
+ // RequestState is an opaque string the client must echo back when
+ // retrying after an input-required result. Servers use this to carry
+ // context between independent requests.
+ //
+ // Unauthenticated servers must encrypt, sign and verify this value.
+ RequestState string `json:"requestState,omitempty"`
+
+ // ResultType indicates whether this result is complete or requires further
+ // client input. Empty or ResultTypeComplete means the call succeeded
+ // normally. ResultTypeInputRequired means the client should fulfill the
+ // InputRequests and retry the call.
+ resultType resultType
// The error passed to setError, if any.
// It is not marshaled, and therefore it is only visible on the server.
// Its only use is in server sending middleware, where it can be accessed
@@ -114,23 +329,13 @@ type CallToolResult struct {
err error
}
-// seterroroverwrite is a compatibility parameter that restores the pre-1.6.0
-// behavior of [CallToolResult.SetError], where Content was always overwritten
-// with the error text. See the documentation for the mcpgodebug package for
-// instructions on how to enable it.
-// The option will be removed in the 1.8.0 version of the SDK.
-var seterroroverwrite = mcpgodebug.Value("seterroroverwrite")
-
// SetError sets the error for the tool result and sets IsError to true.
// If Content has not already been populated, it is set to the error text.
// If Content has already been populated, it is left unchanged, allowing callers
// to provide a user-friendly message while still recording the underlying error
// for inspection via [GetError] in server middleware.
-//
-// To restore the previous behavior where Content was always overwritten,
-// set MCPGODEBUG=seterroroverwrite=1.
func (r *CallToolResult) SetError(err error) {
- if len(r.Content) == 0 || seterroroverwrite == "1" {
+ if len(r.Content) == 0 {
r.Content = []Content{&TextContent{Text: err.Error()}}
}
r.IsError = true
@@ -145,13 +350,49 @@ func (r *CallToolResult) GetError() error {
func (*CallToolResult) isResult() {}
-// UnmarshalJSON handles the unmarshalling of content into the Content
-// interface.
+func (r *CallToolResult) setResultType(rt resultType) { r.resultType = rt }
+func (r *CallToolResult) requestState() string { return r.RequestState }
+func (r *CallToolResult) inputRequests() map[string]InputRequest {
+ if r == nil {
+ return nil
+ }
+ return r.InputRequests
+}
+func (r *CallToolResult) hasContent() bool {
+ return len(r.Content) > 0 || r.StructuredContent != nil
+}
+
+// NeedsInput reports whether this result requires further client input.
+// This is true when the server returned ResultType "input_required".
+// When NeedsInput returns true, check InputRequests for the set of
+// requests the server needs fulfilled before retrying the call.
+// An empty InputRequests with NeedsInput true indicates load-shedding.
+func (r *CallToolResult) NeedsInput() bool { return r.resultType == resultTypeInputRequired }
+
+func (x *CallToolResult) MarshalJSON() ([]byte, error) {
+ type res CallToolResult // avoid recursion
+ type wire struct {
+ res
+ ResultType resultType `json:"resultType,omitempty"`
+ InputRequests json.RawMessage `json:"inputRequests,omitempty"` // shadows res.InputRequests
+ }
+ w := wire{res: res(*x), ResultType: x.resultType}
+ if x.InputRequests != nil {
+ ir, err := json.Marshal(x.InputRequests)
+ if err != nil {
+ return nil, err
+ }
+ w.InputRequests = ir
+ }
+ return json.Marshal(w)
+}
+
func (x *CallToolResult) UnmarshalJSON(data []byte) error {
type res CallToolResult // avoid recursion
var wire struct {
res
- Content []*wireContent `json:"content"`
+ Content []*wireContent `json:"content"`
+ ResultType resultType `json:"resultType"`
}
if err := internaljson.Unmarshal(data, &wire); err != nil {
return err
@@ -160,15 +401,18 @@ func (x *CallToolResult) UnmarshalJSON(data []byte) error {
if wire.res.Content, err = contentsFromWire(wire.Content, nil); err != nil {
return err
}
+ wire.res.resultType = wire.ResultType
*x = CallToolResult(wire.res)
return nil
}
func (x *CallToolParams) isParams() {}
+func (x *CallToolParams) isNil() bool { return x == nil }
func (x *CallToolParams) GetProgressToken() any { return getProgressToken(x) }
func (x *CallToolParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *CallToolParamsRaw) isParams() {}
+func (x *CallToolParamsRaw) isNil() bool { return x == nil }
func (x *CallToolParamsRaw) GetProgressToken() any { return getProgressToken(x) }
func (x *CallToolParamsRaw) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -187,10 +431,16 @@ type CancelledParams struct {
}
func (x *CancelledParams) isParams() {}
+func (x *CancelledParams) isNil() bool { return x == nil }
func (x *CancelledParams) GetProgressToken() any { return getProgressToken(x) }
func (x *CancelledParams) SetProgressToken(t any) { setProgressToken(x, t) }
// RootCapabilities describes a client's support for roots.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type RootCapabilities struct {
// ListChanged reports whether the client supports notifications for
// changes to the roots list.
@@ -218,14 +468,27 @@ type ClientCapabilities struct {
// Deprecated: use RootsV2. As described in #607, Roots should have been a
// pointer to a RootCapabilities value. Roots will be continue to be
// populated, but any new fields will only be added in the RootsV2 field.
+ //
+ // The roots feature itself is also deprecated by SEP-2577; see RootsV2.
Roots struct {
// ListChanged reports whether the client supports notifications for
// changes to the roots list.
ListChanged bool `json:"listChanged,omitempty"`
} `json:"roots,omitempty"`
- // RootsV2 is present if the client supports roots. When capabilities are explicitly configured via [ClientOptions.Capabilities]
+ // RootsV2 is present if the client supports roots. When capabilities are
+ // explicitly configured via [ClientOptions.Capabilities].
+ //
+ // Deprecated: the roots feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
RootsV2 *RootCapabilities `json:"-"`
// Sampling is present if the client supports sampling from an LLM.
+ //
+ // Deprecated: the sampling feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
Sampling *SamplingCapabilities `json:"sampling,omitempty"`
// Elicitation is present if the client supports elicitation from the server.
Elicitation *ElicitationCapabilities `json:"elicitation,omitempty"`
@@ -374,7 +637,8 @@ type CompleteParams struct {
Ref *CompleteReference `json:"ref"`
}
-func (*CompleteParams) isParams() {}
+func (x *CompleteParams) isParams() {}
+func (x *CompleteParams) isNil() bool { return x == nil }
type CompletionResultDetails struct {
HasMore bool `json:"hasMore,omitempty"`
@@ -384,6 +648,7 @@ type CompletionResultDetails struct {
// The server's response to a completion/complete request
type CompleteResult struct {
+ completeResultWithType
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta `json:"_meta,omitempty"`
@@ -392,6 +657,12 @@ type CompleteResult struct {
func (*CompleteResult) isResult() {}
+// CreateMessageParams holds parameters for a sampling/createMessage request.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type CreateMessageParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -399,10 +670,11 @@ type CreateMessageParams struct {
// A request to include context from one or more MCP servers (including the
// caller), to be attached to the prompt. The client may ignore this request.
//
- // The default is "none". Values "thisServer" and
- // "allServers" are soft-deprecated. Servers SHOULD only use these values if
- // the client declares ClientCapabilities.sampling.context. These values may
- // be removed in future spec releases.
+ // The default is "none". The values "thisServer" and "allServers" are
+ // deprecated as of protocol version 2025-11-25 (SEP-2596) and will be
+ // removed no later than the sampling feature itself (SEP-2577). Servers
+ // SHOULD omit this field or use "none". See
+ // https://modelcontextprotocol.io/seps/2596-feature-lifecycle-and-deprecation-policy.
IncludeContext string `json:"includeContext,omitempty"`
// The maximum number of tokens to sample, as requested by the server. The
// client may choose to sample fewer tokens than requested.
@@ -422,6 +694,8 @@ type CreateMessageParams struct {
}
func (x *CreateMessageParams) isParams() {}
+func (x *CreateMessageParams) isInputRequest() {}
+func (x *CreateMessageParams) isNil() bool { return x == nil }
func (x *CreateMessageParams) GetProgressToken() any { return getProgressToken(x) }
func (x *CreateMessageParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -430,6 +704,11 @@ func (x *CreateMessageParams) SetProgressToken(t any) { setProgressToken(x, t) }
// and messages that support array content (for parallel tool calls).
//
// Use with [ServerSession.CreateMessageWithTools].
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type CreateMessageWithToolsParams struct {
Meta `json:"_meta,omitempty"`
IncludeContext string `json:"includeContext,omitempty"`
@@ -448,6 +727,8 @@ type CreateMessageWithToolsParams struct {
}
func (x *CreateMessageWithToolsParams) isParams() {}
+func (x *CreateMessageWithToolsParams) isInputRequest() {}
+func (x *CreateMessageWithToolsParams) isNil() bool { return x == nil }
func (x *CreateMessageWithToolsParams) GetProgressToken() any { return getProgressToken(x) }
func (x *CreateMessageWithToolsParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -488,6 +769,11 @@ func (p *CreateMessageWithToolsParams) toBase() (*CreateMessageParams, error) {
// object for compatibility with pre-2025-11-25 implementations. When
// unmarshaling, a single JSON content object is accepted and wrapped in a
// one-element slice.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type SamplingMessageV2 struct {
Content []Content `json:"content"`
Role Role `json:"role"`
@@ -529,6 +815,11 @@ func (m *SamplingMessageV2) UnmarshalJSON(data []byte) error {
// The client should inform the user before returning the sampled message, to
// allow them to inspect the response (human in the loop) and decide whether to
// allow the server to see it.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type CreateMessageResult struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -547,7 +838,8 @@ type CreateMessageResult struct {
StopReason string `json:"stopReason,omitempty"`
}
-func (*CreateMessageResult) isResult() {}
+func (*CreateMessageResult) isResult() {}
+func (*CreateMessageResult) isInputResponse() {}
func (r *CreateMessageResult) UnmarshalJSON(data []byte) error {
type result CreateMessageResult // avoid recursion
var wire struct {
@@ -574,6 +866,11 @@ func (r *CreateMessageResult) UnmarshalJSON(data []byte) error {
//
// When unmarshaling, a single JSON content object is accepted and wrapped in a
// one-element slice, for compatibility with clients that return a single block.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type CreateMessageWithToolsResult struct {
Meta `json:"_meta,omitempty"`
Content []Content `json:"content"`
@@ -592,7 +889,8 @@ var createMessageWithToolsResultAllow = map[string]bool{
"tool_use": true,
}
-func (*CreateMessageWithToolsResult) isResult() {}
+func (*CreateMessageWithToolsResult) isResult() {}
+func (*CreateMessageWithToolsResult) isInputResponse() {}
// MarshalJSON marshals the result. When Content has a single element, it is
// marshaled as a single object for compatibility with pre-2025-11-25
@@ -651,9 +949,17 @@ type GetPromptParams struct {
Arguments map[string]string `json:"arguments,omitempty"`
// The name of the prompt or prompt template.
Name string `json:"name"`
+
+ // InputResponses maps input request IDs to responses, provided when
+ // retrying a call after receiving a result with ResultType
+ // ResultTypeInputRequired.
+ InputResponses InputResponseMap `json:"inputResponses,omitempty"`
+ // RequestState is the opaque state from the previous input-required result.
+ RequestState string `json:"requestState,omitempty"`
}
func (x *GetPromptParams) isParams() {}
+func (x *GetPromptParams) isNil() bool { return x == nil }
func (x *GetPromptParams) GetProgressToken() any { return getProgressToken(x) }
func (x *GetPromptParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -665,10 +971,67 @@ type GetPromptResult struct {
// An optional description for the prompt.
Description string `json:"description,omitempty"`
Messages []*PromptMessage `json:"messages"`
+
+ // InputRequests is populated when ResultType is ResultTypeInputRequired.
+ // See [CallToolResult.InputRequests].
+ InputRequests InputRequestMap `json:"inputRequests,omitempty"`
+ // RequestState is the opaque state for multi-round-trip retries.
+ // See [CallToolResult.RequestState].
+ RequestState string `json:"requestState,omitempty"`
+
+ // ResultType indicates whether this result is complete or requires further
+ // client input. See [CallToolResult.ResultType] for details.
+ resultType resultType
}
func (*GetPromptResult) isResult() {}
+func (r *GetPromptResult) setResultType(rt resultType) { r.resultType = rt }
+func (r *GetPromptResult) requestState() string { return r.RequestState }
+func (r *GetPromptResult) inputRequests() map[string]InputRequest {
+ if r == nil {
+ return nil
+ }
+ return r.InputRequests
+}
+func (r *GetPromptResult) hasContent() bool { return len(r.Messages) > 0 }
+
+// NeedsInput reports whether this result requires further client input.
+// See [CallToolResult.NeedsInput] for details.
+func (r *GetPromptResult) NeedsInput() bool { return r.resultType == resultTypeInputRequired }
+
+func (x *GetPromptResult) MarshalJSON() ([]byte, error) {
+ type res GetPromptResult
+ type wire struct {
+ res
+ ResultType resultType `json:"resultType,omitempty"`
+ InputRequests json.RawMessage `json:"inputRequests,omitempty"` // shadows res.InputRequests
+ }
+ w := wire{res: res(*x), ResultType: x.resultType}
+ if x.InputRequests != nil {
+ ir, err := json.Marshal(x.InputRequests)
+ if err != nil {
+ return nil, err
+ }
+ w.InputRequests = ir
+ }
+ return json.Marshal(w)
+}
+
+func (x *GetPromptResult) UnmarshalJSON(data []byte) error {
+ type res GetPromptResult
+ var wire struct {
+ res
+ ResultType resultType `json:"resultType"`
+ }
+ if err := internaljson.Unmarshal(data, &wire); err != nil {
+ return err
+ }
+ wire.res.resultType = wire.ResultType
+ *x = GetPromptResult(wire.res)
+ return nil
+}
+
// InitializeParams is sent by the client to initialize the session.
type InitializeParams struct {
// This property is reserved by the protocol to allow clients and servers to
@@ -706,6 +1069,7 @@ func (p *initializeParamsV2) toV1() *InitializeParams {
}
func (x *InitializeParams) isParams() {}
+func (x *InitializeParams) isNil() bool { return x == nil }
func (x *InitializeParams) GetProgressToken() any { return getProgressToken(x) }
func (x *InitializeParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -739,6 +1103,7 @@ type InitializedParams struct {
}
func (x *InitializedParams) isParams() {}
+func (x *InitializedParams) isNil() bool { return x == nil }
func (x *InitializedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *InitializedParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -751,16 +1116,90 @@ type ListPromptsParams struct {
Cursor string `json:"cursor,omitempty"`
}
+type DiscoverParams struct {
+ Meta `json:"_meta,omitempty"`
+}
+
+func (x *DiscoverParams) isParams() {}
+func (x *DiscoverParams) isNil() bool { return x == nil }
+func (x *DiscoverParams) GetProgressToken() any { return getProgressToken(x) }
+func (x *DiscoverParams) SetProgressToken(t any) { setProgressToken(x, t) }
+
+type DiscoverResult struct {
+ completeResultWithType
+ Meta `json:"_meta,omitempty"`
+ Cacheable
+ // The versions of the Model Context Protocol that the server supports.
+ SupportedVersions []string `json:"supportedVersions"`
+ // The server's capabilities.
+ Capabilities *ServerCapabilities `json:"capabilities"`
+ // Instructions describing how to use the server and its features.
+ Instructions string `json:"instructions,omitempty"`
+}
+
+func (*DiscoverResult) isResult() {}
+
func (x *ListPromptsParams) isParams() {}
+func (x *ListPromptsParams) isNil() bool { return x == nil }
func (x *ListPromptsParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListPromptsParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListPromptsParams) cursorPtr() *string { return &x.Cursor }
+// CacheableResult is a result that supports a time-to-live (TTL) hint for
+// client-side caching.
+type CacheableResult interface {
+ Result
+ GetTTLMs() int
+ GetCacheScope() string
+}
+
+// Cacheable describes a result that supports a time-to-live (TTL) hint for
+// client-side caching.
+type Cacheable struct {
+ // A hint from the server indicating how long (in milliseconds) the
+ // client MAY cache this response before re-fetching. Semantics are
+ // analogous to HTTP Cache-Control max-age.
+ //
+ // If 0, the response SHOULD be considered immediately stale.
+ // If positive, the client SHOULD consider the result fresh for this
+ // many milliseconds after receiving the response.
+ TTLMs int `json:"ttlMs"`
+
+ // Indicates the intended scope of the cached response, analogous to
+ // HTTP Cache-Control: public vs Cache-Control: private.
+ //
+ // "public": Any client or intermediary MAY cache and serve the response.
+ // "private": Only the requesting user's client MAY cache the response.
+ //
+ // Defaults to "public" if absent.
+ CacheScope string `json:"cacheScope"`
+}
+
+// GetTTLMs returns the TTL hint in milliseconds.
+func (c Cacheable) GetTTLMs() int { return c.TTLMs }
+
+// GetCacheScope returns the cache scope.
+func (c Cacheable) GetCacheScope() string { return c.CacheScope }
+
+// normalize fills in the protocol default for any cache field left
+// unset. An absent cacheScope means "public", but the field is required on the
+// wire, so the default is materialized here rather than sent empty.
+//
+// Values already present are preserved: this must not undo a decision made by
+// a resource handler or by [ServerOptions.SetCacheable].
+func (c *Cacheable) normalize() {
+ if c.CacheScope == "" {
+ c.CacheScope = "public"
+ }
+}
+
// The server's response to a prompts/list request from the client.
type ListPromptsResult struct {
+ completeResultWithType
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta `json:"_meta,omitempty"`
+ Cacheable
// An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
@@ -780,15 +1219,18 @@ type ListResourceTemplatesParams struct {
}
func (x *ListResourceTemplatesParams) isParams() {}
+func (x *ListResourceTemplatesParams) isNil() bool { return x == nil }
func (x *ListResourceTemplatesParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListResourceTemplatesParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListResourceTemplatesParams) cursorPtr() *string { return &x.Cursor }
// The server's response to a resources/templates/list request from the client.
type ListResourceTemplatesResult struct {
+ completeResultWithType
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta `json:"_meta,omitempty"`
+ Cacheable
// An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
@@ -808,15 +1250,18 @@ type ListResourcesParams struct {
}
func (x *ListResourcesParams) isParams() {}
+func (x *ListResourcesParams) isNil() bool { return x == nil }
func (x *ListResourcesParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListResourcesParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListResourcesParams) cursorPtr() *string { return &x.Cursor }
// The server's response to a resources/list request from the client.
type ListResourcesResult struct {
+ completeResultWithType
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta `json:"_meta,omitempty"`
+ Cacheable
// An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
@@ -826,6 +1271,12 @@ type ListResourcesResult struct {
func (x *ListResourcesResult) isResult() {}
func (x *ListResourcesResult) nextCursorPtr() *string { return &x.NextCursor }
+// ListRootsParams holds parameters for a roots/list request.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type ListRootsParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -833,12 +1284,19 @@ type ListRootsParams struct {
}
func (x *ListRootsParams) isParams() {}
+func (x *ListRootsParams) isInputRequest() {}
+func (x *ListRootsParams) isNil() bool { return x == nil }
func (x *ListRootsParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListRootsParams) SetProgressToken(t any) { setProgressToken(x, t) }
// The client's response to a roots/list request from the server. This result
// contains an array of Root objects, each representing a root directory or file
// that the server can operate on.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type ListRootsResult struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -846,7 +1304,8 @@ type ListRootsResult struct {
Roots []*Root `json:"roots"`
}
-func (*ListRootsResult) isResult() {}
+func (*ListRootsResult) isResult() {}
+func (*ListRootsResult) isInputResponse() {}
type ListToolsParams struct {
// This property is reserved by the protocol to allow clients and servers to
@@ -858,15 +1317,18 @@ type ListToolsParams struct {
}
func (x *ListToolsParams) isParams() {}
+func (x *ListToolsParams) isNil() bool { return x == nil }
func (x *ListToolsParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ListToolsParams) SetProgressToken(t any) { setProgressToken(x, t) }
func (x *ListToolsParams) cursorPtr() *string { return &x.Cursor }
// The server's response to a tools/list request from the client.
type ListToolsResult struct {
+ completeResultWithType
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
Meta `json:"_meta,omitempty"`
+ Cacheable
// An opaque token representing the pagination position after the last returned
// result. If present, there may be more results available.
NextCursor string `json:"nextCursor,omitempty"`
@@ -880,8 +1342,20 @@ func (x *ListToolsResult) nextCursorPtr() *string { return &x.NextCursor }
//
// These map to syslog message severities, as specified in RFC-5424:
// https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type LoggingLevel string
+// LoggingMessageParams holds the parameters for a notifications/message
+// notification.
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type LoggingMessageParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -896,6 +1370,7 @@ type LoggingMessageParams struct {
}
func (x *LoggingMessageParams) isParams() {}
+func (x *LoggingMessageParams) isNil() bool { return x == nil }
func (x *LoggingMessageParams) GetProgressToken() any { return getProgressToken(x) }
func (x *LoggingMessageParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -903,6 +1378,11 @@ func (x *LoggingMessageParams) SetProgressToken(t any) { setProgressToken(x, t)
//
// Keys not declared here are currently left unspecified by the spec and are up
// to the client to interpret.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type ModelHint struct {
// A hint for a model name.
//
@@ -929,6 +1409,11 @@ type ModelHint struct {
// These preferences are always advisory. The client may ignore them. It is also
// up to the client to decide how to interpret these preferences and how to
// balance them against other considerations.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type ModelPreferences struct {
// How much to prioritize cost when selecting a model. A value of 0 means cost
// is not important, while a value of 1 means cost is the most important factor.
@@ -958,6 +1443,7 @@ type PingParams struct {
}
func (x *PingParams) isParams() {}
+func (x *PingParams) isNil() bool { return x == nil }
func (x *PingParams) GetProgressToken() any { return getProgressToken(x) }
func (x *PingParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -978,7 +1464,8 @@ type ProgressNotificationParams struct {
Total float64 `json:"total,omitempty"`
}
-func (*ProgressNotificationParams) isParams() {}
+func (x *ProgressNotificationParams) isParams() {}
+func (x *ProgressNotificationParams) isNil() bool { return x == nil }
// IconTheme specifies the theme an icon is designed for.
type IconTheme string
@@ -1048,6 +1535,7 @@ type PromptListChangedParams struct {
}
func (x *PromptListChangedParams) isParams() {}
+func (x *PromptListChangedParams) isNil() bool { return x == nil }
func (x *PromptListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *PromptListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -1086,9 +1574,17 @@ type ReadResourceParams struct {
// The URI of the resource to read. The URI can use any protocol; it is up to
// the server how to interpret it.
URI string `json:"uri"`
+
+ // InputResponses maps input request IDs to responses, provided when
+ // retrying a call after receiving a result with ResultType
+ // ResultTypeInputRequired.
+ InputResponses InputResponseMap `json:"inputResponses,omitempty"`
+ // RequestState is the opaque state from the previous input-required result.
+ RequestState string `json:"requestState,omitempty"`
}
func (x *ReadResourceParams) isParams() {}
+func (x *ReadResourceParams) isNil() bool { return x == nil }
func (x *ReadResourceParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ReadResourceParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -1096,12 +1592,70 @@ func (x *ReadResourceParams) SetProgressToken(t any) { setProgressToken(x, t) }
type ReadResourceResult struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
- Meta `json:"_meta,omitempty"`
+ Meta `json:"_meta,omitempty"`
+ Cacheable
Contents []*ResourceContents `json:"contents"`
+
+ // InputRequests is populated when ResultType is ResultTypeInputRequired.
+ // See [CallToolResult.InputRequests].
+ InputRequests InputRequestMap `json:"inputRequests,omitempty"`
+ // RequestState is the opaque state for multi-round-trip retries.
+ // See [CallToolResult.RequestState].
+ RequestState string `json:"requestState,omitempty"`
+
+ // ResultType indicates whether this result is complete or requires further
+ // client input. See [CallToolResult.ResultType] for details.
+ resultType resultType
}
func (*ReadResourceResult) isResult() {}
+func (r *ReadResourceResult) setResultType(rt resultType) { r.resultType = rt }
+func (r *ReadResourceResult) requestState() string { return r.RequestState }
+func (r *ReadResourceResult) inputRequests() map[string]InputRequest {
+ if r == nil {
+ return nil
+ }
+ return r.InputRequests
+}
+func (r *ReadResourceResult) hasContent() bool { return len(r.Contents) > 0 }
+
+// NeedsInput reports whether this result requires further client input.
+// See [CallToolResult.NeedsInput] for details.
+func (r *ReadResourceResult) NeedsInput() bool { return r.resultType == resultTypeInputRequired }
+
+func (x *ReadResourceResult) MarshalJSON() ([]byte, error) {
+ type res ReadResourceResult
+ type wire struct {
+ res
+ ResultType resultType `json:"resultType,omitempty"`
+ InputRequests json.RawMessage `json:"inputRequests,omitempty"` // shadows res.InputRequests
+ }
+ w := wire{res: res(*x), ResultType: x.resultType}
+ if x.InputRequests != nil {
+ ir, err := json.Marshal(x.InputRequests)
+ if err != nil {
+ return nil, err
+ }
+ w.InputRequests = ir
+ }
+ return json.Marshal(w)
+}
+
+func (x *ReadResourceResult) UnmarshalJSON(data []byte) error {
+ type res ReadResourceResult
+ var wire struct {
+ res
+ ResultType resultType `json:"resultType"`
+ }
+ if err := internaljson.Unmarshal(data, &wire); err != nil {
+ return err
+ }
+ wire.res.resultType = wire.ResultType
+ *x = ReadResourceResult(wire.res)
+ return nil
+}
+
// A known resource that the server is capable of reading.
type Resource struct {
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
@@ -1145,6 +1699,7 @@ type ResourceListChangedParams struct {
}
func (x *ResourceListChangedParams) isParams() {}
+func (x *ResourceListChangedParams) isNil() bool { return x == nil }
func (x *ResourceListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ResourceListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -1184,6 +1739,11 @@ type ResourceTemplate struct {
type Role string
// Represents a root directory or file that the server can operate on.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type Root struct {
// See [specification/2025-06-18/basic/index#general-fields] for notes on _meta
// usage.
@@ -1198,6 +1758,13 @@ type Root struct {
URI string `json:"uri"`
}
+// RootsListChangedParams holds parameters for a notifications/roots/list_changed
+// notification.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type RootsListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -1205,6 +1772,7 @@ type RootsListChangedParams struct {
}
func (x *RootsListChangedParams) isParams() {}
+func (x *RootsListChangedParams) isNil() bool { return x == nil }
func (x *RootsListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *RootsListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -1212,6 +1780,11 @@ func (x *RootsListChangedParams) SetProgressToken(t any) { setProgressToken(x, t
// below directly above ClientCapabilities.
// SamplingCapabilities describes the client's support for sampling.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type SamplingCapabilities struct {
// Context indicates the client supports includeContext values other than "none".
Context *SamplingContextCapabilities `json:"context,omitempty"`
@@ -1220,12 +1793,27 @@ type SamplingCapabilities struct {
}
// SamplingContextCapabilities indicates the client supports context inclusion.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type SamplingContextCapabilities struct{}
// SamplingToolsCapabilities indicates the client supports tool use in sampling.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type SamplingToolsCapabilities struct{}
// ToolChoice controls how the model uses tools during sampling.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type ToolChoice struct {
// Mode controls tool invocation behavior:
// - "auto": Model decides whether to use tools (default)
@@ -1252,6 +1840,11 @@ type URLElicitationCapabilities struct{}
//
// For assistant messages, Content may be text, image, audio, or tool_use.
// For user messages, Content may be text, image, audio, or tool_result.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type SamplingMessage struct {
Content Content `json:"content"`
Role Role `json:"role"`
@@ -1277,6 +1870,12 @@ func (m *SamplingMessage) UnmarshalJSON(data []byte) error {
return nil
}
+// SetLoggingLevelParams holds parameters for a logging/setLevel request.
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type SetLoggingLevelParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -1288,6 +1887,7 @@ type SetLoggingLevelParams struct {
}
func (x *SetLoggingLevelParams) isParams() {}
+func (x *SetLoggingLevelParams) isNil() bool { return x == nil }
func (x *SetLoggingLevelParams) GetProgressToken() any { return getProgressToken(x) }
func (x *SetLoggingLevelParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -1346,6 +1946,13 @@ type Tool struct {
Icons []Icon `json:"icons,omitempty"`
}
+// hintomitempty is a compatibility parameter that restores the pre-1.7.0
+// behavior of [ToolAnnotations] JSON marshaling, where false-valued bare bool
+// fields (ReadOnlyHint, IdempotentHint) were omitted from the output.
+// See the documentation for the mcpgodebug package for instructions on how to
+// enable it.
+var hintomitempty = mcpgodebug.Value("hintomitempty")
+
// Additional properties describing a Tool to clients.
//
// NOTE: all properties in ToolAnnotations are hints. They are not
@@ -1368,7 +1975,7 @@ type ToolAnnotations struct {
// (This property is meaningful only when ReadOnlyHint == false.)
//
// Default: false
- IdempotentHint bool `json:"idempotentHint,omitempty"`
+ IdempotentHint bool `json:"idempotentHint"`
// If true, this tool may interact with an "open world" of external entities. If
// false, the tool's domain of interaction is closed. For example, the world of
// a web search tool is open, whereas that of a memory tool is not.
@@ -1378,11 +1985,30 @@ type ToolAnnotations struct {
// If true, the tool does not modify its environment.
//
// Default: false
- ReadOnlyHint bool `json:"readOnlyHint,omitempty"`
+ ReadOnlyHint bool `json:"readOnlyHint"`
// A human-readable title for the tool.
Title string `json:"title,omitempty"`
}
+// MarshalJSON implements [json.Marshaler] for ToolAnnotations.
+//
+// To restore the previous behavior where false-valued ReadOnlyHint and
+// IdempotentHint were omitted, set MCPGODEBUG=hintomitempty=1.
+func (t ToolAnnotations) MarshalJSON() ([]byte, error) {
+ if hintomitempty == "1" {
+ type compat struct {
+ DestructiveHint *bool `json:"destructiveHint,omitempty"`
+ IdempotentHint bool `json:"idempotentHint,omitempty"`
+ OpenWorldHint *bool `json:"openWorldHint,omitempty"`
+ ReadOnlyHint bool `json:"readOnlyHint,omitempty"`
+ Title string `json:"title,omitempty"`
+ }
+ return json.Marshal(compat(t))
+ }
+ type nomethod ToolAnnotations
+ return json.Marshal(nomethod(t))
+}
+
type ToolListChangedParams struct {
// This property is reserved by the protocol to allow clients and servers to
// attach additional metadata to their responses.
@@ -1390,6 +2016,7 @@ type ToolListChangedParams struct {
}
func (x *ToolListChangedParams) isParams() {}
+func (x *ToolListChangedParams) isNil() bool { return x == nil }
func (x *ToolListChangedParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ToolListChangedParams) SetProgressToken(t any) { setProgressToken(x, t) }
@@ -1403,7 +2030,8 @@ type SubscribeParams struct {
URI string `json:"uri"`
}
-func (*SubscribeParams) isParams() {}
+func (x *SubscribeParams) isParams() {}
+func (x *SubscribeParams) isNil() bool { return x == nil }
// Sent from the client to request cancellation of resources/updated
// notifications from the server. This should follow a previous
@@ -1416,7 +2044,8 @@ type UnsubscribeParams struct {
URI string `json:"uri"`
}
-func (*UnsubscribeParams) isParams() {}
+func (x *UnsubscribeParams) isParams() {}
+func (x *UnsubscribeParams) isNil() bool { return x == nil }
// A notification from the server to the client, informing it that a resource
// has changed and may need to be read again. This should only be sent if the
@@ -1429,7 +2058,63 @@ type ResourceUpdatedNotificationParams struct {
URI string `json:"uri"`
}
-func (*ResourceUpdatedNotificationParams) isParams() {}
+func (x *ResourceUpdatedNotificationParams) isParams() {}
+func (x *ResourceUpdatedNotificationParams) isNil() bool { return x == nil }
+
+// NotificationSubscriptions describes the set of server-to-client
+// notifications a client wishes to receive on a [SubscriptionsListenParams]
+// stream. Each field is an explicit opt-in: a server MUST NOT push
+// notifications of a type the client did not request.
+type NotificationSubscriptions struct {
+ // ToolsListChanged opts in to "notifications/tools/list_changed".
+ ToolsListChanged bool `json:"toolsListChanged,omitempty"`
+ // PromptsListChanged opts in to "notifications/prompts/list_changed".
+ PromptsListChanged bool `json:"promptsListChanged,omitempty"`
+ // ResourcesListChanged opts in to "notifications/resources/list_changed".
+ ResourcesListChanged bool `json:"resourcesListChanged,omitempty"`
+ // ResourceSubscriptions enumerates the resource URIs for which the client
+ // wants "notifications/resources/updated". Replaces the legacy
+ // resources/subscribe RPC.
+ ResourceSubscriptions []string `json:"resourceSubscriptions,omitempty"`
+}
+
+// SubscriptionsListenParams are the parameters for the
+// "subscriptions/listen" RPC.
+type SubscriptionsListenParams struct {
+ // Meta carries the per-request `_meta` triple.
+ Meta `json:"_meta,omitempty"`
+ // Notifications declares which notification types the client wants to
+ // receive on this stream.
+ Notifications *NotificationSubscriptions `json:"notifications"`
+}
+
+func (x *SubscriptionsListenParams) isParams() {}
+func (x *SubscriptionsListenParams) isNil() bool { return x == nil }
+
+// SubscriptionsAcknowledgedParams are the parameters for the
+// "notifications/subscriptions/acknowledged" notification, which the server
+// MUST send as the first message on a subscriptions/listen stream. It carries
+// the subset of the requested [NotificationSubscriptions] that the server has
+// agreed to honor.
+type SubscriptionsAcknowledgedParams struct {
+ Meta `json:"_meta,omitempty"`
+ Notifications NotificationSubscriptions `json:"notifications"`
+}
+
+func (x *SubscriptionsAcknowledgedParams) isParams() {}
+func (x *SubscriptionsAcknowledgedParams) isNil() bool { return x == nil }
+
+// SubscriptionsListenResult is the response to a "subscriptions/listen"
+// request, signalling that the subscription has ended gracefully (for example,
+// during server shutdown). Because the listen stream is long-lived, this
+// result is sent only when the server tears the subscription down; an abrupt
+// transport close carries no response.
+type SubscriptionsListenResult struct {
+ completeResultWithType
+ Meta `json:"_meta"`
+}
+
+func (*SubscriptionsListenResult) isResult() {}
// TODO(jba): add CompleteRequest and related types.
@@ -1468,11 +2153,28 @@ type ElicitParams struct {
ElicitationID string `json:"elicitationId,omitempty"`
}
-func (x *ElicitParams) isParams() {}
+func (x *ElicitParams) isParams() {}
+func (x *ElicitParams) isInputRequest() {}
+func (x *ElicitParams) isNil() bool { return x == nil }
func (x *ElicitParams) GetProgressToken() any { return getProgressToken(x) }
func (x *ElicitParams) SetProgressToken(t any) { setProgressToken(x, t) }
+// inferElicitMode returns x with Mode populated by inference if it was empty.
+// Mode is inferred as "url" when URL or ElicitationID is set, otherwise "form".
+func (x *ElicitParams) inferElicitMode() *ElicitParams {
+ if x == nil || x.Mode != "" {
+ return x
+ }
+ x2 := *x
+ if x.URL != "" || x.ElicitationID != "" {
+ x2.Mode = "url"
+ } else {
+ x2.Mode = "form"
+ }
+ return &x2
+}
+
// The client's response to an elicitation/create request from the server.
type ElicitResult struct {
// This property is reserved by the protocol to allow clients and servers to
@@ -1488,7 +2190,8 @@ type ElicitResult struct {
Content map[string]any `json:"content,omitempty"`
}
-func (*ElicitResult) isResult() {}
+func (*ElicitResult) isResult() {}
+func (*ElicitResult) isInputResponse() {}
// ElicitationCompleteParams is sent from the server to the client, informing it that an out-of-band elicitation interaction has completed.
type ElicitationCompleteParams struct {
@@ -1500,18 +2203,21 @@ type ElicitationCompleteParams struct {
ElicitationID string `json:"elicitationId"`
}
-func (*ElicitationCompleteParams) isParams() {}
+func (x *ElicitationCompleteParams) isParams() {}
+func (x *ElicitationCompleteParams) isNil() bool { return x == nil }
-// An Implementation describes the name and version of an MCP implementation, with an optional
-// title for UI representation.
+// An Implementation describes the name and version of an MCP implementation, with
+// optional display metadata.
type Implementation struct {
// Intended for programmatic or logical use, but used as a display name in past
// specs or fallback (if title isn't present).
Name string `json:"name"`
// Intended for UI and end-user contexts — optimized to be human-readable and
// easily understood, even by those unfamiliar with domain-specific terminology.
- Title string `json:"title,omitempty"`
- Version string `json:"version"`
+ Title string `json:"title,omitempty"`
+ // A human-readable description of the implementation.
+ Description string `json:"description,omitempty"`
+ Version string `json:"version"`
// WebsiteURL for the server, if any.
WebsiteURL string `json:"websiteUrl,omitempty"`
// Icons for the Server, if any.
@@ -1522,6 +2228,11 @@ type Implementation struct {
type CompletionCapabilities struct{}
// LoggingCapabilities describes the server's support for sending log messages to the client.
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
type LoggingCapabilities struct{}
// PromptCapabilities describes the server's support for prompts.
@@ -1532,7 +2243,7 @@ type PromptCapabilities struct {
// ResourceCapabilities describes the server's support for resources.
type ResourceCapabilities struct {
- // ListChanged reports whether the client supports notifications for
+ // ListChanged reports whether this server supports notifications for
// changes to the resource list.
ListChanged bool `json:"listChanged,omitempty"`
// Subscribe reports whether this server supports subscribing to resource
@@ -1542,7 +2253,7 @@ type ResourceCapabilities struct {
// ToolCapabilities describes the server's support for tools.
type ToolCapabilities struct {
- // ListChanged reports whether the client supports notifications for
+ // ListChanged reports whether this server supports notifications for
// changes to the tool list.
ListChanged bool `json:"listChanged,omitempty"`
}
@@ -1565,6 +2276,11 @@ type ServerCapabilities struct {
// suggestions.
Completions *CompletionCapabilities `json:"completions,omitempty"`
// Logging is present if the server supports log messages.
+ //
+ // Deprecated: the logging feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
Logging *LoggingCapabilities `json:"logging,omitempty"`
// Prompts is present if the server supports prompts.
Prompts *PromptCapabilities `json:"prompts,omitempty"`
@@ -1606,6 +2322,7 @@ const (
methodCallTool = "tools/call"
notificationCancelled = "notifications/cancelled"
methodComplete = "completion/complete"
+ methodDiscover = "server/discover"
methodCreateMessage = "sampling/createMessage"
methodElicit = "elicitation/create"
notificationElicitationComplete = "notifications/elicitation/complete"
@@ -1627,6 +2344,60 @@ const (
notificationRootsListChanged = "notifications/roots/list_changed"
methodSetLevel = "logging/setLevel"
methodSubscribe = "resources/subscribe"
+ methodSubscriptionsListen = "subscriptions/listen"
notificationToolListChanged = "notifications/tools/list_changed"
methodUnsubscribe = "resources/unsubscribe"
+ notificationSubscriptionsAck = "notifications/subscriptions/acknowledged"
+)
+
+// Per-request _meta field names for the >= 2026-07-28 protocol version.
+//
+// These keys appear inside a Params._meta map and carry information that
+// previously came from the initialization handshake (SEP-2575).
+const (
+ // MetaKeyProtocolVersion identifies the MCP protocol version that the
+ // request follows.
+ MetaKeyProtocolVersion = "io.modelcontextprotocol/protocolVersion"
+ // MetaKeyClientInfo carries the client's [Implementation].
+ MetaKeyClientInfo = "io.modelcontextprotocol/clientInfo"
+ // MetaKeyServerInfo carries the server's [Implementation] on responses.
+ MetaKeyServerInfo = "io.modelcontextprotocol/serverInfo"
+ // MetaKeyClientCapabilities carries the client's [ClientCapabilities].
+ MetaKeyClientCapabilities = "io.modelcontextprotocol/clientCapabilities"
+ // MetaKeyLogLevel identifies the desired log level for the request.
+ //
+ // Deprecated: the logging feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
+ MetaKeyLogLevel = "io.modelcontextprotocol/logLevel"
+ // MetaKeySubscriptionID identifies the subscriptions/listen request that an
+ // out-of-band notification belongs to.
+ MetaKeySubscriptionID = "io.modelcontextprotocol/subscriptionId"
)
+
+// UnsupportedProtocolVersionData is the SEP-2575 payload carried in the
+// `data` field of a JSON-RPC error response with code
+// [CodeUnsupportedProtocolVersion]. The server uses it to advertise which
+// versions it supports so the client can pick a mutually supported one.
+type UnsupportedProtocolVersionData struct {
+ // Supported is the list of protocol versions the server supports.
+ Supported []string `json:"supported"`
+ // Requested is the protocol version the client asked for.
+ Requested string `json:"requested"`
+}
+
+// MissingRequiredClientCapabilityData is the SEP-2575 payload carried in the
+// `data` field of a JSON-RPC error response with code
+// [CodeMissingRequiredClientCapabilities]. The server uses it to indicate
+// which client capabilities are required to process the request but were not
+// declared by the client in its per-request `_meta` field.
+//
+// Handlers that require a specific client capability should inspect the
+// per-request [ServerRequest.ClientCapabilities] and return a JSON-RPC error
+// populated with this structure when the required capability is missing.
+type MissingRequiredClientCapabilityData struct {
+ // RequiredCapabilities is the set of capabilities the server requires
+ // from the client to process the request.
+ RequiredCapabilities *ClientCapabilities `json:"requiredCapabilities"`
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/requests.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/requests.go
index 4280941..64414ca 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/requests.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/requests.go
@@ -19,12 +19,14 @@ type (
ReadResourceRequest = ServerRequest[*ReadResourceParams]
RootsListChangedRequest = ServerRequest[*RootsListChangedParams]
SubscribeRequest = ServerRequest[*SubscribeParams]
+ SubscriptionsListenRequest = ServerRequest[*SubscriptionsListenParams]
UnsubscribeRequest = ServerRequest[*UnsubscribeParams]
)
type (
CreateMessageRequest = ClientRequest[*CreateMessageParams]
CreateMessageWithToolsRequest = ClientRequest[*CreateMessageWithToolsParams]
+ DiscoverRequest = ClientRequest[*DiscoverParams]
ElicitRequest = ClientRequest[*ElicitParams]
initializedClientRequest = ClientRequest[*InitializedParams]
InitializeRequest = ClientRequest[*InitializeParams]
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/resource.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/resource.go
index bc4b3cb..fff38a2 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/resource.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/resource.go
@@ -15,6 +15,7 @@ import (
"path/filepath"
"strings"
+ "github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug"
"github.com/modelcontextprotocol/go-sdk/internal/util"
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
"github.com/yosida95/uritemplate/v3"
@@ -37,8 +38,25 @@ type serverResourceTemplate struct {
// If it cannot find the resource, it should return the result of calling [ResourceNotFoundError].
type ResourceHandler func(context.Context, *ReadResourceRequest) (*ReadResourceResult, error)
+// customresnotfounderrcode is a compatibility parameter that restores the
+// pre-1.7.0 behavior of [ResourceNotFoundError] and [CodeResourceNotFound],
+// where the error code was a custom -32002. See the documentation for the mcpgodebug
+// package for instructions on how to enable it.
+// The option will be removed in the future version of the SDK.
+var customresnotfounderrcode = mcpgodebug.Value("customresnotfounderrcode")
+
+func init() {
+ if customresnotfounderrcode == "1" {
+ CodeResourceNotFound = -32002
+ }
+}
+
// ResourceNotFoundError returns an error indicating that a resource being read could
// not be found.
+//
+// By default, the error code is -32602 (Invalid Params), as specified in the
+// MCP specification (SEP-2164). To restore the pre-1.7.0 release behavior where the
+// error code was -32002, set MCPGODEBUG=customresnotfounderrcode=1.
func ResourceNotFoundError(uri string) error {
return &jsonrpc.Error{
Code: CodeResourceNotFound,
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/server.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/server.go
index 2850437..5014a4f 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/server.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/server.go
@@ -27,6 +27,7 @@ import (
"github.com/google/jsonschema-go/jsonschema"
internaljson "github.com/modelcontextprotocol/go-sdk/internal/json"
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
+ "github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug"
"github.com/modelcontextprotocol/go-sdk/internal/util"
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
"github.com/yosida95/uritemplate/v3"
@@ -43,17 +44,29 @@ type Server struct {
// fixed at creation
impl *Implementation
opts ServerOptions
-
- mu sync.Mutex
- prompts *featureSet[*serverPrompt]
- tools *featureSet[*serverTool]
- resources *featureSet[*serverResource]
- resourceTemplates *featureSet[*serverResourceTemplate]
- sessions []*ServerSession
- sendingMethodHandler_ MethodHandler
- receivingMethodHandler_ MethodHandler
- resourceSubscriptions map[string]map[*ServerSession]bool // uri -> session -> bool
- pendingNotifications map[string]*time.Timer // notification name -> timer for pending notification send
+ // protocolVersions is the descending-ordered list of protocol versions
+ // this server advertises and negotiates: [supportedProtocolVersions],
+ // narrowed by [ServerOptions.SupportedProtocolVersions].
+ protocolVersions []string
+
+ mu sync.Mutex
+ prompts *featureSet[*serverPrompt]
+ tools *featureSet[*serverTool]
+ resources *featureSet[*serverResource]
+ resourceTemplates *featureSet[*serverResourceTemplate]
+ sessions []*ServerSession
+ sendingMethodHandler_ MethodHandler
+ receivingMethodHandler_ MethodHandler
+ toolChangeSubscriptions map[*ServerSession]jsonrpc.ID // session -> requestID for "tools/changed"
+ promptChangeSubscriptions map[*ServerSession]jsonrpc.ID // session -> requestID for "prompts/changed"
+ resourceChangeSubscriptions map[*ServerSession]jsonrpc.ID // session -> requestID for "resources/changed"
+ resourceSubscriptions map[string]map[*ServerSession]jsonrpc.ID // uri -> session -> requestID
+ pendingNotifications map[string]*time.Timer // notification name -> timer for pending notification send
+ // receiveMethods is the merged map of methods this server may receive
+ // from a client: it always contains the standard server methods (from
+ // serverMethodInfos) plus any custom methods registered via
+ // [AddReceivingCustomMethod].
+ receiveMethods map[string]methodInfo
}
// ServerOptions is used to configure behavior of the server.
@@ -70,6 +83,12 @@ type ServerOptions struct {
// If zero, defaults to [DefaultPageSize].
PageSize int
// If non-nil, called when "notifications/roots/list_changed" is received.
+ //
+ // Deprecated: the roots feature is deprecated as of protocol version
+ // 2026-07-28 (SEP-2577). It remains functional during the deprecation
+ // window (at least twelve months). Migrate to passing paths via tool
+ // parameters, resource URIs, or configuration. See
+ // https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
RootsListChangedHandler func(context.Context, *RootsListChangedRequest)
// If non-nil, called when "notifications/progress" is received.
ProgressNotificationHandler func(context.Context, *ProgressNotificationServerRequest)
@@ -79,6 +98,13 @@ type ServerOptions struct {
// If the peer fails to respond to pings originating from the keepalive check,
// the session is automatically closed.
KeepAlive time.Duration
+ // KeepAliveFailureThreshold is the number of consecutive keepalive ping
+ // failures tolerated before the session is closed. A value of 0 or 1
+ // closes the session on the first failure (the default). Higher values
+ // align with the spec's "multiple failed pings MAY trigger a connection
+ // reset" guidance, letting a transient miss pass without tearing down an
+ // otherwise live session. Has no effect unless KeepAlive is non-zero.
+ KeepAliveFailureThreshold int
// Function called when a client session subscribes to a resource.
SubscribeHandler func(context.Context, *SubscribeRequest) error
// Function called when a client session unsubscribes from a resource.
@@ -143,7 +169,35 @@ type ServerOptions struct {
//
// As a special case, if GetSessionID returns the empty string, the
// Mcp-Session-Id header will not be set.
+ //
+ // GetSessionID is not consulted when [StreamableHTTPOptions.Stateless] is
+ // true, since stateless servers do not maintain sessions.
GetSessionID func() string
+
+ // SetCacheable, if non-nil, decides the cache-control fields (ttlMs and
+ // cacheScope) of every result that carries them: server/discover, the
+ // four list methods, and resources/read.
+ //
+ // It is called once per such result, after the corresponding handler has
+ // returned, with c holding the values that handler produced.
+ SetCacheable func(ctx context.Context, req Request, c *Cacheable)
+
+ // SupportedProtocolVersions, if non-empty, restricts the protocol versions
+ // this server advertises. If empty, every version returned by
+ // [SupportedProtocolVersions] is used.
+ // The list can only narrow support, never widen it.
+ // A request using the >= 2026-07-28 protocol at an excluded version is
+ // rejected with error code [CodeUnsupportedProtocolVersion].
+ //
+ // The legacy initialize handshake never rejects. The lifecycle spec
+ // requires the server to answer a request it does not support with a
+ // version it does, so an excluded version is answered with the newest
+ // listed version that handshake can negotiate, and the client is expected
+ // to disconnect when it cannot speak it. A list holding no such version
+ // (one restricted to 2026-07-28 and later) is answered with 2025-11-25,
+ // the newest handshake-era version, so that the client disconnects rather
+ // than reading the answer as a negotiation into the new protocol.
+ SupportedProtocolVersions []string
}
// NewServer creates a new MCP server. The resulting server has no features:
@@ -180,22 +234,44 @@ func NewServer(impl *Implementation, options *ServerOptions) *Server {
opts.GetSessionID = rand.Text
}
+ protocolVersions := SupportedProtocolVersions()
+ if len(opts.SupportedProtocolVersions) > 0 {
+ for _, v := range opts.SupportedProtocolVersions {
+ if !slices.Contains(supportedProtocolVersions, v) {
+ panic(fmt.Errorf("unsupported protocol version %q", v))
+ }
+ }
+ protocolVersions = slices.DeleteFunc(protocolVersions, func(v string) bool {
+ return !slices.Contains(opts.SupportedProtocolVersions, v)
+ })
+ }
+
if opts.Logger == nil { // ensure we have a logger
opts.Logger = ensureLogger(nil)
}
- return &Server{
- impl: impl,
- opts: opts,
- prompts: newFeatureSet(func(p *serverPrompt) string { return p.prompt.Name }),
- tools: newFeatureSet(func(t *serverTool) string { return t.tool.Name }),
- resources: newFeatureSet(func(r *serverResource) string { return r.resource.URI }),
- resourceTemplates: newFeatureSet(func(t *serverResourceTemplate) string { return t.resourceTemplate.URITemplate }),
- sendingMethodHandler_: defaultSendingMethodHandler,
- receivingMethodHandler_: defaultReceivingMethodHandler[*ServerSession],
- resourceSubscriptions: make(map[string]map[*ServerSession]bool),
- pendingNotifications: make(map[string]*time.Timer),
+ receiveMethods := make(map[string]methodInfo, len(serverMethodInfos))
+ maps.Copy(receiveMethods, serverMethodInfos)
+
+ s := &Server{
+ impl: impl,
+ opts: opts,
+ protocolVersions: protocolVersions,
+ prompts: newFeatureSet(func(p *serverPrompt) string { return p.prompt.Name }),
+ tools: newFeatureSet(func(t *serverTool) string { return t.tool.Name }),
+ resources: newFeatureSet(func(r *serverResource) string { return r.resource.URI }),
+ resourceTemplates: newFeatureSet(func(t *serverResourceTemplate) string { return t.resourceTemplate.URITemplate }),
+ sendingMethodHandler_: defaultSendingMethodHandler,
+ receivingMethodHandler_: defaultReceivingMethodHandler[*ServerSession],
+ toolChangeSubscriptions: make(map[*ServerSession]jsonrpc.ID),
+ promptChangeSubscriptions: make(map[*ServerSession]jsonrpc.ID),
+ resourceChangeSubscriptions: make(map[*ServerSession]jsonrpc.ID),
+ resourceSubscriptions: make(map[string]map[*ServerSession]jsonrpc.ID),
+ pendingNotifications: make(map[string]*time.Timer),
+ receiveMethods: receiveMethods,
}
+ s.AddReceivingMiddleware(serverMultiRoundTripMiddleware())
+ return s
}
// AddPrompt adds a [Prompt] to the server, or replaces one with the same name.
@@ -220,7 +296,8 @@ func (s *Server) RemovePrompts(names ...string) {
// that takes no input, or one where any input is valid, set [Tool.InputSchema] to
// `{"type": "object"}`, using your preferred library or `json.RawMessage`.
//
-// If present, [Tool.OutputSchema] must also have type "object".
+// If present, [Tool.OutputSchema] may be any valid JSON Schema (object, array,
+// primitive, or composition).
//
// When the handler is invoked as part of a CallTool request, req.Params.Arguments
// will be a json.RawMessage.
@@ -247,6 +324,9 @@ func (s *Server) AddTool(t *Tool, h ToolHandler) {
panic(fmt.Errorf("AddTool %q: missing input schema", t.Name))
}
if s, ok := t.InputSchema.(*jsonschema.Schema); ok {
+ if s == nil {
+ panic(fmt.Errorf("AddTool %q: input schema is nil", t.Name))
+ }
if s.Type != "object" {
panic(fmt.Errorf(`AddTool %q: input schema must have type "object"`, t.Name))
}
@@ -261,19 +341,19 @@ func (s *Server) AddTool(t *Tool, h ToolHandler) {
}
if t.OutputSchema != nil {
if s, ok := t.OutputSchema.(*jsonschema.Schema); ok {
- if s.Type != "object" {
- panic(fmt.Errorf(`AddTool %q: output schema must have type "object"`, t.Name))
+ if s == nil {
+ panic(fmt.Errorf("AddTool %q: output schema is nil", t.Name))
}
} else {
- var m map[string]any
+ var m any
if err := remarshal(t.OutputSchema, &m); err != nil {
- panic(fmt.Errorf("AddTool %q: can't marshal output schema to a JSON object: %v", t.Name, err))
- }
- if typ := m["type"]; typ != "object" {
- panic(fmt.Errorf(`AddTool %q: output schema must have type "object" (got %v)`, t.Name, typ))
+ panic(fmt.Errorf("AddTool %q: can't marshal output schema to JSON: %v", t.Name, err))
}
}
}
+ if err := validateParamHeaderAnnotations(t); err != nil {
+ panic(fmt.Errorf("AddTool %q: invalid parameter header annotations: %v", t.Name, err))
+ }
st := &serverTool{tool: t, handler: h}
// Assume there was a change, since add replaces existing tools.
// (It's possible a tool was replaced with an identical one, but not worth checking.)
@@ -319,7 +399,7 @@ func toolForErr[In, Out any](t *Tool, h ToolHandlerFor[In, Out], cache *SchemaCa
}
// Validate input and apply defaults.
var err error
- input, err = applySchema(input, inputResolved)
+ input, err = applySchema(input, inputResolved, false)
if err != nil {
var errRes CallToolResult
errRes.SetError(fmt.Errorf("validating \"arguments\": %v", err))
@@ -358,8 +438,12 @@ func toolForErr[In, Out any](t *Tool, h ToolHandlerFor[In, Out], cache *SchemaCa
}
// Marshal the output and put the RawMessage in the StructuredContent field.
+ // Skip when the handler returned input requests (multi round-trip): content and
+ // inputRequests are mutually exclusive on the wire.
var outval any = out
- if elemZero != nil {
+ if res.InputRequests != nil {
+ outval = nil
+ } else if elemZero != nil {
// Avoid typed nil, which will serialize as JSON null.
// Instead, use the zero value of the unpointered type.
var z Out
@@ -377,7 +461,7 @@ func toolForErr[In, Out any](t *Tool, h ToolHandlerFor[In, Out], cache *SchemaCa
//
// We validate against the JSON, rather than the output value, as
// some types may have custom JSON marshalling (issue #447).
- outJSON, err = applySchema(outJSON, outputResolved)
+ outJSON, err = applySchema(outJSON, outputResolved, true)
if err != nil {
return nil, fmt.Errorf("validating tool output: %w", err)
}
@@ -386,10 +470,18 @@ func toolForErr[In, Out any](t *Tool, h ToolHandlerFor[In, Out], cache *SchemaCa
// If the Content field isn't being used, return the serialized JSON in a
// TextContent block, as the spec suggests:
// https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content.
+ //
+ // Ensure a serialized-JSON TextContent fallback is present in case of servers using array
+ // or primitive structuredContent, so that pre-SEP-2106 clients can recover the structured
+ // payload from unstructured content.
if res.Content == nil {
res.Content = []Content{&TextContent{
Text: string(outJSON),
}}
+ } else if !isObjectJSON(outJSON) {
+ res.Content = append(res.Content, &TextContent{
+ Text: string(outJSON),
+ })
}
}
return res, nil
@@ -437,6 +529,9 @@ func setSchema[T any](sfield *any, rfield **jsonschema.Resolved, cache *SchemaCa
if err != nil {
return zero, err
}
+ if internalSchema == nil {
+ return zero, fmt.Errorf("schema is nil for type %v", rt)
+ }
*sfield = internalSchema
resolved, err := internalSchema.Resolve(&jsonschema.ResolveOptions{ValidateDefaults: true})
@@ -466,6 +561,10 @@ func setSchema[T any](sfield *any, rfield **jsonschema.Resolved, cache *SchemaCa
}
}
+ if internalSchema == nil {
+ return zero, fmt.Errorf("schema is nil for type %v", rt)
+ }
+
resolved, err := internalSchema.Resolve(&jsonschema.ResolveOptions{ValidateDefaults: true})
if err != nil {
return zero, err
@@ -493,9 +592,10 @@ func setSchema[T any](sfield *any, rfield **jsonschema.Resolved, cache *SchemaCa
// empty object schema value.
//
// If the tool's output schema is nil, and the Out type is not 'any', the
-// output schema is set to the schema inferred from the Out type argument,
-// which must also be a map or struct. If the Out type is 'any', the output
-// schema is omitted.
+// output schema is set to the schema inferred from the Out type argument.
+// Per SEP-2106, the Out type may be any Go type whose inferred schema is a
+// valid JSON Schema (struct, map, slice, primitive, etc.). If the Out type is
+// 'any', the output schema is omitted.
//
// Unlike [Server.AddTool], AddTool does a lot automatically, and forces
// tools to conform to the MCP spec. See [ToolHandlerFor] for a detailed
@@ -604,19 +704,36 @@ func (s *Server) capabilities() *ServerCapabilities {
return caps
}
+// disablecompleteparamsvalidation is a compatibility parameter that restores
+// the previous behavior of [Server.complete], where required fields on
+// [CompleteParams] were not validated before dispatching to the completion
+// handler. See the documentation for the mcpgodebug package for instructions
+// how to enable it.
+// The option will be removed in a future version of the SDK.
+var disablecompleteparamsvalidation = mcpgodebug.Value("disablecompleteparamsvalidation")
+
func (s *Server) complete(ctx context.Context, req *CompleteRequest) (*CompleteResult, error) {
+ if disablecompleteparamsvalidation != "1" {
+ if req.Params.Ref == nil {
+ return nil, fmt.Errorf("%w: missing required 'ref' field", jsonrpc2.ErrInvalidParams)
+ }
+ if req.Params.Argument.Name == "" {
+ return nil, fmt.Errorf("%w: missing required 'argument.name' field", jsonrpc2.ErrInvalidParams)
+ }
+ }
if s.opts.CompletionHandler == nil {
return nil, jsonrpc2.ErrMethodNotFound
}
return s.opts.CompletionHandler(ctx, req)
}
-// Map from notification name to its corresponding params. The params have no fields,
-// so a single struct can be reused.
-var changeNotificationParams = map[string]Params{
- notificationToolListChanged: &ToolListChangedParams{},
- notificationPromptListChanged: &PromptListChangedParams{},
- notificationResourceListChanged: &ResourceListChangedParams{},
+// Map from notification name to a function creating its corresponding Params.
+// We need to create a fresh one each time to add the jsonrpc ID. See
+// [injectMetaSubscriptionID].
+var changeNotificationParams = map[string]func() Params{
+ notificationToolListChanged: func() Params { return &ToolListChangedParams{} },
+ notificationPromptListChanged: func() Params { return &PromptListChangedParams{} },
+ notificationResourceListChanged: func() Params { return &ResourceListChangedParams{} },
}
// How long to wait before sending a change notification.
@@ -650,12 +767,75 @@ func (s *Server) changeAndNotify(notification string, change func() bool) {
// notifySessions sends the notification n to all existing sessions.
// It is called asynchronously by changeAndNotify.
+//
+// Legacy (pre-SEP-2575) sessions receive the notification on the shared
+// session channel. Sessions speaking the new protocol receive it only if they
+// have an active subscriptions/listen stream that opted in to this
+// notification type.
func (s *Server) notifySessions(n string) {
s.mu.Lock()
- sessions := slices.Clone(s.sessions)
s.pendingNotifications[n] = nil
+ // Legacy (pre-SEP-2575) sessions receive list-changed notifications on the
+ // shared session channel without opt-in; collect them while we hold the lock.
+ var legacySessions []*ServerSession
+ for _, sess := range s.sessions {
+ if sess.InitializeParams().isNil() || sess.InitializeParams().ProtocolVersion < protocolVersion20260728 {
+ legacySessions = append(legacySessions, sess)
+ }
+ }
+ var subscribers map[*ServerSession]jsonrpc.ID
+ switch n {
+ case notificationToolListChanged:
+ subscribers = maps.Clone(s.toolChangeSubscriptions)
+ case notificationPromptListChanged:
+ subscribers = maps.Clone(s.promptChangeSubscriptions)
+ case notificationResourceListChanged:
+ subscribers = maps.Clone(s.resourceChangeSubscriptions)
+ }
s.mu.Unlock() // Don't hold the lock during notification: it causes deadlock.
- notifySessions(sessions, n, changeNotificationParams[n], s.opts.Logger)
+
+ // Notify legacy sessions on the shared session channel regardless of
+ // their subscription status.
+ notifySessions(legacySessions, n, changeNotificationParams[n](), s.opts.Logger)
+
+ // Notify modern sessions only if they have an active subscription for
+ // this notification type.
+ s.notifySubscribedSessions(subscribers, n, changeNotificationParams[n])
+}
+
+// notifySubscribedSessions delivers a list-changed or resource-updated
+// notification to each session in subscribers, stamping the session's
+// listen-request ID into the params' _meta so the receiving client can demultiplex
+// notifications belonging to different concurrent listens.
+func (s *Server) notifySubscribedSessions(subscribers map[*ServerSession]jsonrpc.ID, method string, makeParams func() Params) {
+ if len(subscribers) == 0 {
+ return
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ for sess, reqID := range subscribers {
+ params := makeParams()
+ injectMetaSubscriptionID(params, reqID)
+ req := newRequest(sess, params)
+ if err := handleNotify(ctx, method, req); err != nil {
+ s.opts.Logger.Warn(fmt.Sprintf("calling %s: %v", method, err))
+ }
+ }
+}
+
+// injectMetaSubscriptionID stamps the listen request's JSON-RPC ID into the
+// params' _meta under [MetaKeySubscriptionID], so the receiving client can
+// correlate the notification with the [subscriptions/listen] stream it
+// originated.
+//
+// [subscriptions/listen]: https://modelcontextprotocol.io/seps/2575-stateless-mcp#multiple-concurrent-subscriptions
+func injectMetaSubscriptionID(params Params, reqID jsonrpc.ID) {
+ m := params.GetMeta()
+ if m == nil {
+ m = map[string]any{}
+ }
+ m[MetaKeySubscriptionID] = reqID.Raw()
+ params.SetMeta(m)
}
// shouldSendListChangedNotification checks if the server's capabilities allow
@@ -698,18 +878,23 @@ func (s *Server) Sessions() iter.Seq[*ServerSession] {
return slices.Values(clients)
}
-func (s *Server) listPrompts(_ context.Context, req *ListPromptsRequest) (*ListPromptsResult, error) {
+func (s *Server) listPrompts(ctx context.Context, req *ListPromptsRequest) (*ListPromptsResult, error) {
s.mu.Lock()
defer s.mu.Unlock()
if req.Params == nil {
req.Params = &ListPromptsParams{}
}
- return paginateList(s.prompts, s.opts.PageSize, req.Params, &ListPromptsResult{}, func(res *ListPromptsResult, prompts []*serverPrompt) {
+ res, err := paginateList(s.prompts, s.opts.PageSize, req.Params, &ListPromptsResult{}, func(res *ListPromptsResult, prompts []*serverPrompt) {
res.Prompts = []*Prompt{} // avoid JSON null
for _, p := range prompts {
res.Prompts = append(res.Prompts, p.prompt)
}
})
+ if err != nil {
+ return nil, err
+ }
+ s.resolveCacheable(ctx, req, &res.Cacheable)
+ return res, nil
}
func (s *Server) getPrompt(ctx context.Context, req *GetPromptRequest) (*GetPromptResult, error) {
@@ -723,27 +908,102 @@ func (s *Server) getPrompt(ctx context.Context, req *GetPromptRequest) (*GetProm
Message: fmt.Sprintf("unknown prompt %q", req.Params.Name),
}
}
- return prompt.handler(ctx, req)
+ res, err := prompt.handler(ctx, req)
+ if err == nil && res != nil {
+ if err := handleMultiRoundTripResult(req.Session, s.opts.Logger, res); err != nil {
+ return nil, err
+ }
+ }
+ return res, err
+}
+
+// discover is the server-side handler for the SEP-2575 "server/discover" RPC.
+//
+// It returns the protocol versions supported by the underlying transport,
+// the server's capabilities, the server's identity, and the server's
+// instructions, allowing clients to negotiate without performing the legacy
+// initialize handshake.
+func (s *Server) discover(ctx context.Context, req *ServerRequest[*DiscoverParams]) (*DiscoverResult, error) {
+ req.Session.mu.Lock()
+ versions := req.Session.supportedVersions
+ req.Session.mu.Unlock()
+ if versions == nil {
+ versions = slices.Clone(s.protocolVersions)
+ }
+ // Read the request-scoped identity/capabilities before acquiring the
+ // session lock: these accessors may fall back to Session.InitializeParams
+ // (which also locks Session.mu), so calling them from inside updateState
+ // would self-deadlock.
+ init := &InitializeParams{
+ ProtocolVersion: req.ProtocolVersion(),
+ Capabilities: req.ClientCapabilities(),
+ ClientInfo: req.ClientInfo(),
+ }
+ // Only persist InitializeParams when the transport can actually serve
+ // the new protocol. On transports that cannot (notably stateful
+ // StreamableHTTPHandler), a discover request creates a session that
+ // is never surfaced to the client via Mcp-Session-Id; leaving
+ // InitializeParams nil lets serveStatefulPOST's safety-net cleanup
+ // close it instead of leaking.
+ if slices.ContainsFunc(versions, func(v string) bool { return v >= protocolVersion20260728 }) {
+ req.Session.updateState(func(state *ServerSessionState) {
+ state.InitializeParams = init
+ })
+ }
+ res := &DiscoverResult{
+ SupportedVersions: versions,
+ Capabilities: s.capabilities(),
+ Instructions: s.opts.Instructions,
+ }
+ s.resolveCacheable(ctx, req, &res.Cacheable)
+ return res, nil
}
-func (s *Server) listTools(_ context.Context, req *ListToolsRequest) (*ListToolsResult, error) {
+// filterSupportedVersions returns the subset of versions that the Transport
+// can serve. If t does not implement [ProtocolVersionSupporter], every version
+// is included.
+func filterSupportedVersions(t Transport, versions []string) []string {
+ pvs, ok := t.(ProtocolVersionSupporter)
+ if !ok {
+ return slices.Clone(versions)
+ }
+ out := make([]string, 0, len(versions))
+ for _, v := range versions {
+ if pvs.SupportsProtocolVersion(v) {
+ out = append(out, v)
+ }
+ }
+ return out
+}
+
+func (s *Server) listTools(ctx context.Context, req *ListToolsRequest) (*ListToolsResult, error) {
s.mu.Lock()
defer s.mu.Unlock()
if req.Params == nil {
req.Params = &ListToolsParams{}
}
- return paginateList(s.tools, s.opts.PageSize, req.Params, &ListToolsResult{}, func(res *ListToolsResult, tools []*serverTool) {
+ res, err := paginateList(s.tools, s.opts.PageSize, req.Params, &ListToolsResult{}, func(res *ListToolsResult, tools []*serverTool) {
res.Tools = []*Tool{} // avoid JSON null
for _, t := range tools {
res.Tools = append(res.Tools, t.tool)
}
})
+ if err != nil {
+ return nil, err
+ }
+ s.resolveCacheable(ctx, req, &res.Cacheable)
+ return res, nil
}
-func (s *Server) callTool(ctx context.Context, req *CallToolRequest) (*CallToolResult, error) {
+// getServerTool looks up a server tool by name.
+func (s *Server) getServerTool(name string) (*serverTool, bool) {
s.mu.Lock()
- st, ok := s.tools.get(req.Params.Name)
- s.mu.Unlock()
+ defer s.mu.Unlock()
+ return s.tools.get(name)
+}
+
+func (s *Server) callTool(ctx context.Context, req *CallToolRequest) (*CallToolResult, error) {
+ st, ok := s.getServerTool(req.Params.Name)
if !ok {
return nil, &jsonrpc.Error{
Code: jsonrpc.CodeInvalidParams,
@@ -751,41 +1011,56 @@ func (s *Server) callTool(ctx context.Context, req *CallToolRequest) (*CallToolR
}
}
res, err := st.handler(ctx, req)
- if err == nil && res != nil && res.Content == nil {
- res2 := *res
- res2.Content = []Content{} // avoid "null"
- res = &res2
+ if err == nil && res != nil {
+ if err := handleMultiRoundTripResult(req.Session, s.opts.Logger, res); err != nil {
+ return nil, err
+ }
+ if res.Content == nil && res.resultType != resultTypeInputRequired {
+ res2 := *res
+ res2.Content = []Content{} // avoid "null"
+ res = &res2
+ }
}
return res, err
}
-func (s *Server) listResources(_ context.Context, req *ListResourcesRequest) (*ListResourcesResult, error) {
+func (s *Server) listResources(ctx context.Context, req *ListResourcesRequest) (*ListResourcesResult, error) {
s.mu.Lock()
defer s.mu.Unlock()
if req.Params == nil {
req.Params = &ListResourcesParams{}
}
- return paginateList(s.resources, s.opts.PageSize, req.Params, &ListResourcesResult{}, func(res *ListResourcesResult, resources []*serverResource) {
+ res, err := paginateList(s.resources, s.opts.PageSize, req.Params, &ListResourcesResult{}, func(res *ListResourcesResult, resources []*serverResource) {
res.Resources = []*Resource{} // avoid JSON null
for _, r := range resources {
res.Resources = append(res.Resources, r.resource)
}
})
+ if err != nil {
+ return nil, err
+ }
+ s.resolveCacheable(ctx, req, &res.Cacheable)
+ return res, nil
}
-func (s *Server) listResourceTemplates(_ context.Context, req *ListResourceTemplatesRequest) (*ListResourceTemplatesResult, error) {
+func (s *Server) listResourceTemplates(ctx context.Context, req *ListResourceTemplatesRequest) (*ListResourceTemplatesResult, error) {
s.mu.Lock()
defer s.mu.Unlock()
if req.Params == nil {
req.Params = &ListResourceTemplatesParams{}
}
- return paginateList(s.resourceTemplates, s.opts.PageSize, req.Params, &ListResourceTemplatesResult{},
+ res, err := paginateList(s.resourceTemplates, s.opts.PageSize, req.Params, &ListResourceTemplatesResult{},
func(res *ListResourceTemplatesResult, rts []*serverResourceTemplate) {
res.ResourceTemplates = []*ResourceTemplate{} // avoid JSON null
for _, rt := range rts {
res.ResourceTemplates = append(res.ResourceTemplates, rt.resourceTemplate)
}
})
+ if err != nil {
+ return nil, err
+ }
+ s.resolveCacheable(ctx, req, &res.Cacheable)
+ return res, nil
}
func (s *Server) readResource(ctx context.Context, req *ReadResourceRequest) (*ReadResourceResult, error) {
@@ -802,7 +1077,17 @@ func (s *Server) readResource(ctx context.Context, req *ReadResourceRequest) (*R
if err != nil {
return nil, err
}
- if res == nil || res.Contents == nil {
+ if res == nil {
+ return nil, fmt.Errorf("reading resource %s: read handler returned nil information", uri)
+ }
+ if err := handleMultiRoundTripResult(req.Session, s.opts.Logger, res); err != nil {
+ return nil, err
+ }
+ s.resolveCacheable(ctx, req, &res.Cacheable)
+ if res.resultType == resultTypeInputRequired {
+ return res, nil
+ }
+ if res.Contents == nil {
return nil, fmt.Errorf("reading resource %s: read handler returned nil information", uri)
}
// As a convenience, populate some fields.
@@ -817,6 +1102,22 @@ func (s *Server) readResource(ctx context.Context, req *ReadResourceRequest) (*R
return res, nil
}
+// resolveCacheable settles the cache-control fields of an outgoing result.
+//
+// On entry c holds whatever the feature handler produced, which is the zero
+// value for results the SDK builds itself. [ServerOptions.SetCacheable] may
+// then rewrite it, and any cacheScope still unset is filled with the protocol
+// default.
+//
+// The list methods call this with s.mu held, so SetCacheable must not call
+// back into the server; see its documentation.
+func (s *Server) resolveCacheable(ctx context.Context, req Request, c *Cacheable) {
+ if s.opts.SetCacheable != nil {
+ s.opts.SetCacheable(ctx, req, c)
+ }
+ c.normalize()
+}
+
// lookupResourceHandler returns the resource handler and MIME type for the resource or
// resource template matching uri. If none, the last return value is false.
func (s *Server) lookupResourceHandler(uri string) (ResourceHandler, string, bool) {
@@ -882,14 +1183,36 @@ func fileResourceHandler(dir string) ResourceHandler {
func (s *Server) ResourceUpdated(ctx context.Context, params *ResourceUpdatedNotificationParams) error {
s.mu.Lock()
subscribedSessions := s.resourceSubscriptions[params.URI]
- sessions := slices.Collect(maps.Keys(subscribedSessions))
+ // Only add legacy sessions for the notification, new ones use the new notification mechanism.
+ var legacySessions []*ServerSession
+ newSessions := make(map[*ServerSession]jsonrpc.ID)
+ for sess, reqID := range subscribedSessions {
+ if sess.InitializeParams().isNil() || sess.InitializeParams().ProtocolVersion < protocolVersion20260728 {
+ legacySessions = append(legacySessions, sess)
+ } else {
+ newSessions[sess] = reqID
+ }
+ }
s.mu.Unlock()
- notifySessions(sessions, notificationResourceUpdated, params, s.opts.Logger)
- s.opts.Logger.Info("resource updated notification sent", "uri", params.URI, "subscriber_count", len(sessions))
+
+ notifySessions(legacySessions, notificationResourceUpdated, params, s.opts.Logger)
+
+ // Notify modern sessions, injecting the per-session subscription ID into the notification's metadata.
+ s.notifySubscribedSessions(newSessions, notificationResourceUpdated, func() Params {
+ p := *params
+ return &p
+ })
+ s.opts.Logger.Info("resource updated notification sent",
+ "uri", params.URI,
+ "subscriber_count", len(legacySessions)+len(newSessions))
return nil
}
func (s *Server) subscribe(ctx context.Context, req *SubscribeRequest) (*emptyResult, error) {
+ requestID, ok := ctx.Value(idContextKey{}).(jsonrpc.ID)
+ if !ok || !requestID.IsValid() {
+ return nil, fmt.Errorf("%w: subscribe requires a request ID", jsonrpc2.ErrInvalidRequest)
+ }
if s.opts.SubscribeHandler == nil {
return nil, fmt.Errorf("%w: server does not support resource subscriptions", jsonrpc2.ErrMethodNotFound)
}
@@ -900,10 +1223,10 @@ func (s *Server) subscribe(ctx context.Context, req *SubscribeRequest) (*emptyRe
s.mu.Lock()
defer s.mu.Unlock()
if s.resourceSubscriptions[req.Params.URI] == nil {
- s.resourceSubscriptions[req.Params.URI] = make(map[*ServerSession]bool)
+ s.resourceSubscriptions[req.Params.URI] = make(map[*ServerSession]jsonrpc.ID)
}
- s.resourceSubscriptions[req.Params.URI][req.Session] = true
- s.opts.Logger.Info("resource subscribed", "uri", req.Params.URI, "session_id", req.Session.ID())
+ s.resourceSubscriptions[req.Params.URI][req.Session] = requestID
+ s.opts.Logger.Info("resource subscribed", "uri", req.Params.URI, "session_id", req.Session.ID(), "request_id", requestID)
return &emptyResult{}, nil
}
@@ -930,6 +1253,91 @@ func (s *Server) unsubscribe(ctx context.Context, req *UnsubscribeRequest) (*emp
return &emptyResult{}, nil
}
+func (s *Server) subscriptionsListen(ctx context.Context, req *SubscriptionsListenRequest) (*SubscriptionsListenResult, error) {
+ requestID, ok := ctx.Value(idContextKey{}).(jsonrpc.ID)
+ if !ok || !requestID.IsValid() {
+ return nil, fmt.Errorf("%w: subscriptions/listen requires a request ID", jsonrpc2.ErrInvalidRequest)
+ }
+
+ if req.Params.Notifications == nil {
+ return nil, fmt.Errorf("%w: missing required 'notifications' field", jsonrpc2.ErrInvalidParams)
+ }
+
+ allowed := s.allowedSubscriptions(req.Params.Notifications)
+ s.mu.Lock()
+ if allowed.ToolsListChanged {
+ s.toolChangeSubscriptions[req.Session] = requestID
+ }
+ if allowed.PromptsListChanged {
+ s.promptChangeSubscriptions[req.Session] = requestID
+ }
+ if allowed.ResourcesListChanged {
+ s.resourceChangeSubscriptions[req.Session] = requestID
+ }
+ s.mu.Unlock()
+ defer func() {
+ s.mu.Lock()
+ delete(s.toolChangeSubscriptions, req.Session)
+ delete(s.promptChangeSubscriptions, req.Session)
+ delete(s.resourceChangeSubscriptions, req.Session)
+ s.mu.Unlock()
+ }()
+
+ for _, uri := range allowed.ResourceSubscriptions {
+ _, err := s.subscribe(ctx, &SubscribeRequest{
+ Session: req.Session,
+ Params: &SubscribeParams{
+ URI: uri,
+ Meta: req.Params.GetMeta(),
+ },
+ })
+ if err != nil {
+ return nil, err
+ }
+ defer s.unsubscribe(ctx, &UnsubscribeRequest{
+ Session: req.Session,
+ Params: &UnsubscribeParams{
+ URI: uri,
+ Meta: req.Params.GetMeta(),
+ },
+ })
+ }
+
+ ackParams := &SubscriptionsAcknowledgedParams{
+ Notifications: allowed,
+ Meta: Meta{MetaKeySubscriptionID: requestID.Raw()},
+ }
+ if err := req.Session.notifySubscriptionAcked(ctx, ackParams); err != nil {
+ return nil, fmt.Errorf("sending subscriptions/acknowledged: %w", err)
+ }
+
+ // If there are any active subscriptions, we block until the context is cancelled. Otherwise, we return immediately.
+ if len(allowed.ResourceSubscriptions) > 0 || allowed.ToolsListChanged || allowed.PromptsListChanged || allowed.ResourcesListChanged {
+ <-ctx.Done()
+ }
+ return &SubscriptionsListenResult{
+ Meta: Meta{MetaKeySubscriptionID: requestID.Raw()},
+ }, nil
+}
+
+func (s *Server) allowedSubscriptions(want *NotificationSubscriptions) NotificationSubscriptions {
+ caps := s.capabilities()
+ agreed := NotificationSubscriptions{}
+ if want.ToolsListChanged && caps.Tools != nil && caps.Tools.ListChanged {
+ agreed.ToolsListChanged = true
+ }
+ if want.PromptsListChanged && caps.Prompts != nil && caps.Prompts.ListChanged {
+ agreed.PromptsListChanged = true
+ }
+ if want.ResourcesListChanged && caps.Resources != nil && caps.Resources.ListChanged {
+ agreed.ResourcesListChanged = true
+ }
+ if len(want.ResourceSubscriptions) > 0 && caps.Resources != nil && caps.Resources.Subscribe {
+ agreed.ResourceSubscriptions = slices.Clone(want.ResourceSubscriptions)
+ }
+ return agreed
+}
+
// Run runs the server over the given transport, which must be persistent.
//
// Run blocks until the client terminates the connection or the provided
@@ -999,6 +1407,10 @@ func (s *Server) disconnect(cc *ServerSession) {
for _, subscribedSessions := range s.resourceSubscriptions {
delete(subscribedSessions, cc)
}
+ delete(s.toolChangeSubscriptions, cc)
+ delete(s.promptChangeSubscriptions, cc)
+ delete(s.resourceChangeSubscriptions, cc)
+
s.opts.Logger.Info("server session disconnected", "session_id", cc.ID())
}
@@ -1032,6 +1444,21 @@ func (s *Server) Connect(ctx context.Context, t Transport, opts *ServerSessionOp
return nil, err
}
+ // Compute the protocol versions this session can serve, filtered by the
+ // transport's capabilities (if it implements [ProtocolVersionSupporter]).
+ // The list is consumed by the SEP-2575 server/discover handler.
+ //
+ // The write is guarded by ss.mu to establish a happens-before edge with
+ // the matching read in Server.discover, which runs on the jsonrpc2 read
+ // goroutine spawned inside connect(). The two are not concurrent in
+ // wall-clock terms (no incoming message is dispatched until the caller
+ // has fed the transport, which happens after Server.Connect returns),
+ // but without the lock the Go memory model gives the read goroutine no
+ // guarantee of seeing this write, and -race flags it.
+ ss.mu.Lock()
+ ss.supportedVersions = filterSupportedVersions(t, s.protocolVersions)
+ ss.mu.Unlock()
+
// Start keepalive before returning the session to avoid race conditions with Close.
// This is safe because the spec allows sending pings before initialization (see ServerSession.handle for details).
if s.opts.KeepAlive > 0 {
@@ -1094,6 +1521,13 @@ func (ss *ServerSession) NotifyProgress(ctx context.Context, params *ProgressNot
return handleNotify(ctx, notificationProgress, newServerRequest(ss, orZero[Params](params)))
}
+// notifySubscriptionAcked sends a "notifications/subscriptions/acknowledged"
+// notification on the listen stream represented by this session, indicating
+// the subscription filter the server accepted (SEP-2575).
+func (ss *ServerSession) notifySubscriptionAcked(ctx context.Context, params *SubscriptionsAcknowledgedParams) error {
+ return handleNotify(ctx, notificationSubscriptionsAck, newServerRequest(ss, orZero[Params](params)))
+}
+
func newServerRequest[P Params](ss *ServerSession, params P) *ServerRequest[P] {
return &ServerRequest[P]{Session: ss, Params: params}
}
@@ -1116,8 +1550,20 @@ type ServerSession struct {
mcpConn Connection
keepaliveCancel context.CancelFunc
+ // supportedVersions is the subset of [Server.protocolVersions] that the
+ // transport can actually serve, computed once at connection time from
+ // [ProtocolVersionSupporter] (if implemented by the transport) and used by
+ // the SEP-2575 server/discover handler.
+ supportedVersions []string
+
mu sync.Mutex
state ServerSessionState
+ // listenIDs holds the request IDs of in-flight subscriptions/listen
+ // handlers on this session. subscriptions/listen parks on ctx.Done until
+ // cancelled, so ServerSession.Close must cancel these contexts explicitly
+ // via jsonrpc2.Connection.Cancel to avoid deadlocking on the jsonrpc2
+ // drain. See modelcontextprotocol/go-sdk#1160.
+ listenIDs []jsonrpc.ID
}
func (ss *ServerSession) updateState(mut func(*ServerSessionState)) {
@@ -1164,6 +1610,23 @@ func (ss *ServerSession) ID() string {
return ""
}
+// assertServerInitiatedRequestAllowed returns an error when the session is
+// negotiated at protocol version >= 2026-07-28, where the spec (SEP-2322 /
+// SEP-2575) forbids server-initiated JSON-RPC requests for elicitation,
+// sampling, and roots: those interactions MUST be embedded as [InputRequests]
+// in an [InputRequiredResult] returned from a handler for one of the multi
+// round-trip methods (`tools/call`, `prompts/get`, `resources/read`).
+func (ss *ServerSession) assertServerInitiatedRequestAllowed(method string) error {
+ if iparams := ss.InitializeParams(); iparams != nil &&
+ iparams.ProtocolVersion >= protocolVersion20260728 {
+ return fmt.Errorf(
+ "%q cannot be sent while serving a request on protocol version %s: "+
+ "return an InputRequests map instead (multi round-trip requests, SEP-2322)",
+ method, iparams.ProtocolVersion)
+ }
+ return nil
+}
+
// Ping pings the client.
func (ss *ServerSession) Ping(ctx context.Context, params *PingParams) error {
_, err := handleSend[*emptyResult](ctx, methodPing, newServerRequest(ss, orZero[Params](params)))
@@ -1171,10 +1634,19 @@ func (ss *ServerSession) Ping(ctx context.Context, params *PingParams) error {
}
// ListRoots lists the client roots.
+//
+// Deprecated: the roots feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). Migrate to passing paths via tool parameters,
+// resource URIs, or configuration. See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func (ss *ServerSession) ListRoots(ctx context.Context, params *ListRootsParams) (*ListRootsResult, error) {
if err := ss.checkInitialized(methodListRoots); err != nil {
return nil, err
}
+ if err := ss.assertServerInitiatedRequestAllowed(methodListRoots); err != nil {
+ return nil, err
+ }
return handleSend[*ListRootsResult](ctx, methodListRoots, newServerRequest(ss, orZero[Params](params)))
}
@@ -1183,10 +1655,19 @@ func (ss *ServerSession) ListRoots(ctx context.Context, params *ListRootsParams)
// If the client returns multiple content blocks (e.g. parallel tool calls),
// CreateMessage returns an error. Use [ServerSession.CreateMessageWithTools]
// for tool-enabled sampling.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). Migrate to calling LLM provider APIs directly
+// from your server. See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func (ss *ServerSession) CreateMessage(ctx context.Context, params *CreateMessageParams) (*CreateMessageResult, error) {
if err := ss.checkInitialized(methodCreateMessage); err != nil {
return nil, err
}
+ if err := ss.assertServerInitiatedRequestAllowed(methodCreateMessage); err != nil {
+ return nil, err
+ }
if params == nil {
params = &CreateMessageParams{Messages: []*SamplingMessage{}}
}
@@ -1220,10 +1701,19 @@ func (ss *ServerSession) CreateMessage(ctx context.Context, params *CreateMessag
// returning a [CreateMessageWithToolsResult] that supports array content
// (for parallel tool calls). Use this instead of [ServerSession.CreateMessage]
// when the request includes tools.
+//
+// Deprecated: the sampling feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). Migrate to calling LLM provider APIs directly
+// from your server. See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func (ss *ServerSession) CreateMessageWithTools(ctx context.Context, params *CreateMessageWithToolsParams) (*CreateMessageWithToolsResult, error) {
if err := ss.checkInitialized(methodCreateMessage); err != nil {
return nil, err
}
+ if err := ss.assertServerInitiatedRequestAllowed(methodCreateMessage); err != nil {
+ return nil, err
+ }
if params == nil {
params = &CreateMessageWithToolsParams{Messages: []*SamplingMessageV2{}}
}
@@ -1240,19 +1730,14 @@ func (ss *ServerSession) Elicit(ctx context.Context, params *ElicitParams) (*Eli
if err := ss.checkInitialized(methodElicit); err != nil {
return nil, err
}
+ if err := ss.assertServerInitiatedRequestAllowed(methodElicit); err != nil {
+ return nil, err
+ }
if params == nil {
return nil, fmt.Errorf("%w: params cannot be nil", jsonrpc2.ErrInvalidParams)
}
- if params.Mode == "" {
- params2 := *params
- if params.URL != "" || params.ElicitationID != "" {
- params2.Mode = "url"
- } else {
- params2.Mode = "form"
- }
- params = ¶ms2
- }
+ params = params.inferElicitMode()
if iparams := ss.InitializeParams(); iparams == nil || iparams.Capabilities == nil || iparams.Capabilities.Elicitation == nil {
return nil, fmt.Errorf("client does not support elicitation")
@@ -1276,7 +1761,7 @@ func (ss *ServerSession) Elicit(ctx context.Context, params *ElicitParams) (*Eli
return nil, err
}
- if res.Action != "accept" {
+ if res.Action != "accept" || res.Content == nil {
return res, nil
}
@@ -1306,13 +1791,36 @@ func (ss *ServerSession) Elicit(ctx context.Context, params *ElicitParams) (*Eli
return res, nil
}
+// NotifyElicitationComplete tells the client that the out-of-band ("url" mode)
+// elicitation identified by params.ElicitationID has finished.
+func (ss *ServerSession) NotifyElicitationComplete(ctx context.Context, params *ElicitationCompleteParams) error {
+ if params == nil {
+ return fmt.Errorf("%w: params cannot be nil", jsonrpc2.ErrInvalidParams)
+ }
+ if params.ElicitationID == "" {
+ return fmt.Errorf("%w: ElicitationID cannot be empty", jsonrpc2.ErrInvalidParams)
+ }
+ return handleNotify(ctx, notificationElicitationComplete, newServerRequest(ss, orZero[Params](params)))
+}
+
// Log sends a log message to the client.
-// The message is not sent if the client has not called SetLevel, or if its level
-// is below that of the last SetLevel.
+//
+// For new-protocol (>= 2026-07-28) requests, the level is taken from the
+// originating request's `_meta` field (SEP-2575); an absent or empty value
+// suppresses the message per spec. For old-protocol requests, the level is
+// taken from the session state set via `logging/setLevel`.
+//
+// Deprecated: the logging feature is deprecated as of protocol version
+// 2026-07-28 (SEP-2577). It remains functional during the deprecation window
+// (at least twelve months). See
+// https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging.
func (ss *ServerSession) Log(ctx context.Context, params *LoggingMessageParams) error {
- ss.mu.Lock()
- logLevel := ss.state.LogLevel
- ss.mu.Unlock()
+ logLevel, ok := logLevelFromContext(ctx)
+ if !ok {
+ ss.mu.Lock()
+ logLevel = ss.state.LogLevel
+ ss.mu.Unlock()
+ }
if logLevel == "" {
// The spec is unclear, but seems to imply that no log messages are sent until the client
// sets the level.
@@ -1362,6 +1870,7 @@ func (s *Server) AddReceivingMiddleware(middleware ...Middleware) {
// curating these method flags.
var serverMethodInfos = map[string]methodInfo{
methodComplete: newServerMethodInfo(serverMethod((*Server).complete), 0),
+ methodDiscover: newServerMethodInfo(serverMethod((*Server).discover), missingParamsOK),
methodInitialize: initializeMethodInfo(),
methodPing: newServerMethodInfo(serverSessionMethod((*ServerSession).ping), missingParamsOK),
methodListPrompts: newServerMethodInfo(serverMethod((*Server).listPrompts), missingParamsOK),
@@ -1373,6 +1882,7 @@ var serverMethodInfos = map[string]methodInfo{
methodReadResource: newServerMethodInfo(serverMethod((*Server).readResource), 0),
methodSetLevel: newServerMethodInfo(serverSessionMethod((*ServerSession).setLevel), 0),
methodSubscribe: newServerMethodInfo(serverMethod((*Server).subscribe), 0),
+ methodSubscriptionsListen: newServerMethodInfo(serverMethod((*Server).subscriptionsListen), 0),
methodUnsubscribe: newServerMethodInfo(serverMethod((*Server).unsubscribe), 0),
notificationCancelled: newServerMethodInfo(serverSessionMethod((*ServerSession).cancel), notification|missingParamsOK),
notificationInitialized: newServerMethodInfo(serverSessionMethod((*ServerSession).initialized), notification|missingParamsOK),
@@ -1401,7 +1911,15 @@ func initializeMethodInfo() methodInfo {
func (ss *ServerSession) sendingMethodInfos() map[string]methodInfo { return clientMethodInfos }
-func (ss *ServerSession) receivingMethodInfos() map[string]methodInfo { return serverMethodInfos }
+func (s *Server) receivingMethodInfos() map[string]methodInfo {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.receiveMethods
+}
+
+func (ss *ServerSession) receivingMethodInfos() map[string]methodInfo {
+ return ss.server.receivingMethodInfos()
+}
func (ss *ServerSession) sendingMethodHandler() MethodHandler {
s := ss.server
@@ -1426,16 +1944,57 @@ func (ss *ServerSession) handle(ctx context.Context, req *jsonrpc.Request) (any,
initialized := ss.state.InitializeParams != nil
ss.mu.Unlock()
- // From the spec:
- // "The client SHOULD NOT send requests other than pings before the server
- // has responded to the initialize request."
+ // Per-request protocol detection (SEP-2575): if the request carries
+ // `io.modelcontextprotocol/protocolVersion` in its `_meta` field, it
+ // follows the new sessionless protocol. The initialization gate is
+ // skipped for such requests.
+ validatedMeta, perRequestErr := validateRequestMeta(req)
+ if perRequestErr != nil {
+ return nil, perRequestErr
+ }
+
+ if validatedMeta.usesNewProtocol &&
+ !slices.Contains(ss.server.protocolVersions, validatedMeta.initializeParams.ProtocolVersion) {
+ data, _ := json.Marshal(UnsupportedProtocolVersionData{
+ Supported: ss.server.protocolVersions,
+ Requested: validatedMeta.initializeParams.ProtocolVersion,
+ })
+ return nil, &jsonrpc.Error{
+ Code: CodeUnsupportedProtocolVersion,
+ Message: "unsupported protocol version",
+ Data: data,
+ }
+ }
+
switch req.Method {
- case methodInitialize, methodPing, notificationInitialized:
+ case methodInitialize, methodPing, notificationInitialized, notificationRootsListChanged, methodSetLevel, methodSubscribe, methodUnsubscribe:
+ if validatedMeta.usesNewProtocol {
+ ss.server.opts.Logger.Error("method removed in the new protocol", "method", req.Method)
+ return nil, &jsonrpc.Error{
+ Code: jsonrpc.CodeMethodNotFound,
+ Message: fmt.Sprintf("%q is not supported in the new protocol", req.Method),
+ }
+ }
+ case methodDiscover:
+ // In case of methodDiscover call the state.initializeParams is populated
+ // within the discover handle function to make sure the method is supported
+ // when the user is probing a pre-2026-07-28 server.
+ if !validatedMeta.usesNewProtocol {
+ return nil, &jsonrpc.Error{
+ Code: jsonrpc.CodeMethodNotFound,
+ Message: fmt.Sprintf("%q is only supported in protocol version >= %s", req.Method, protocolVersion20260728),
+ }
+ }
default:
- if !initialized {
+ if !initialized && !validatedMeta.usesNewProtocol && req.IsCall() {
ss.server.opts.Logger.Error("method invalid during initialization", "method", req.Method)
return nil, fmt.Errorf("method %q is invalid during session initialization", req.Method)
}
+ if !initialized && validatedMeta.usesNewProtocol && validatedMeta.initializeParams != nil {
+ ss.updateState(func(state *ServerSessionState) {
+ state.InitializeParams = validatedMeta.initializeParams
+ })
+ }
}
// modelcontextprotocol/go-sdk#26: handle calls asynchronously, and
@@ -1449,7 +2008,63 @@ func (ss *ServerSession) handle(ctx context.Context, req *jsonrpc.Request) (any,
// server->client calls and notifications to the incoming request from which
// they originated. See [idContextKey] for details.
ctx = context.WithValue(ctx, idContextKey{}, req.ID)
- return handleReceive(ctx, ss, req)
+ if validatedMeta.usesNewProtocol {
+ ctx = context.WithValue(ctx, logLevelContextKey{}, validatedMeta.logLevel)
+ }
+
+ // subscriptions/listen parks on ctx.Done until the peer cancels it (or the
+ // underlying reader breaks). Track the request ID so ServerSession.Close
+ // can cancel the in-flight handler via jsonrpc2.Connection.Cancel and
+ // avoid deadlocking on the jsonrpc2 drain.
+ if req.Method == methodSubscriptionsListen {
+ ss.mu.Lock()
+ ss.listenIDs = append(ss.listenIDs, req.ID)
+ ss.mu.Unlock()
+ // The listen completes when the handler returns (peer cancellation,
+ // stream break, or error); drop the ID so completed listens don't
+ // accumulate in the slice indefinitely.
+ defer func() {
+ ss.mu.Lock()
+ for i, id := range ss.listenIDs {
+ if id == req.ID {
+ ss.listenIDs = append(ss.listenIDs[:i], ss.listenIDs[i+1:]...)
+ break
+ }
+ }
+ ss.mu.Unlock()
+ }()
+ }
+
+ res, err := handleReceive(ctx, ss, req)
+ if err != nil {
+ return nil, err
+ }
+ if validatedMeta.usesNewProtocol {
+ setCompleteResultType(res)
+ annotateServerInfo(res, ss.server.impl)
+ }
+ return res, nil
+}
+
+// annotateServerInfo sets [MetaKeyServerInfo] on the result's `_meta` unless
+// it is already present. Per SEP-2575, servers should identify themselves in
+// each result's `_meta`.
+func annotateServerInfo(res Result, impl *Implementation) {
+ if res == nil || impl == nil {
+ return
+ }
+ if _, isEmpty := res.(*emptyResult); isEmpty {
+ return
+ }
+ m := res.GetMeta()
+ if m == nil {
+ m = map[string]any{}
+ }
+ if _, ok := m[MetaKeyServerInfo]; ok {
+ return
+ }
+ m[MetaKeyServerInfo] = impl
+ res.SetMeta(m)
}
// InitializeParams returns the InitializeParams provided during the client's
@@ -1464,15 +2079,28 @@ func (ss *ServerSession) initialize(ctx context.Context, params *InitializeParam
if params == nil {
return nil, fmt.Errorf("%w: \"params\" must be be provided", jsonrpc2.ErrInvalidParams)
}
+ var (
+ wasInit bool
+ negotiated string
+ )
ss.updateState(func(state *ServerSessionState) {
- state.InitializeParams = params
+ wasInit = state.InitializeParams != nil
+ if !wasInit {
+ state.InitializeParams = params
+ state.NegotiatedProtocolVersion = negotiatedVersion(params.ProtocolVersion, ss.server.protocolVersions)
+ }
+ negotiated = state.NegotiatedProtocolVersion
})
+ if wasInit {
+ ss.server.opts.Logger.Error("duplicate initialize request")
+ return nil, fmt.Errorf("duplicate %q received", methodInitialize)
+ }
s := ss.server
return &InitializeResult{
// TODO(rfindley): alter behavior when falling back to an older version:
// reject unsupported features.
- ProtocolVersion: negotiatedVersion(params.ProtocolVersion),
+ ProtocolVersion: negotiated,
Capabilities: s.capabilities(),
Instructions: s.opts.Instructions,
ServerInfo: s.impl,
@@ -1515,6 +2143,18 @@ func (ss *ServerSession) Close() error {
// Close is idempotent and conn.Close() handles concurrent calls correctly
ss.keepaliveCancel()
}
+
+ // Unblock any in-flight subscriptions/listen handlers, which otherwise park
+ // on ctx.Done and would deadlock conn.Close (which waits for in-flight
+ // requests to drain).
+ ss.mu.Lock()
+ ids := ss.listenIDs
+ ss.listenIDs = nil
+ ss.mu.Unlock()
+ for _, id := range ids {
+ ss.conn.Cancel(id)
+ }
+
err := ss.conn.Close()
if ss.onClose != nil && ss.calledOnClose.CompareAndSwap(false, true) {
@@ -1531,7 +2171,7 @@ func (ss *ServerSession) Wait() error {
// startKeepalive starts the keepalive mechanism for this server session.
func (ss *ServerSession) startKeepalive(interval time.Duration) {
- startKeepalive(ss, interval, &ss.keepaliveCancel, ss.server.opts.Logger)
+ startKeepalive(ss, interval, ss.server.opts.KeepAliveFailureThreshold, &ss.keepaliveCancel, ss.server.opts.Logger)
}
// pageToken is the internal structure for the opaque pagination cursor.
@@ -1609,3 +2249,55 @@ func paginateList[P listParams, R listResult[T], T any](fs *featureSet[T], pageS
*res.nextCursorPtr() = nextCursor
return res, nil
}
+
+// AddReceivingCustomMethod registers a handler for a custom (non-standard)
+// JSON-RPC method on the server.
+//
+// When a client sends a request with the given method name, the params will be
+// unmarshaled into P, the handler will be called, and the returned R will be
+// marshaled as the JSON-RPC result.
+//
+// Custom methods go through the server's middleware chain just like standard
+// MCP methods (tools/call, prompts/list, etc.).
+//
+// P and R must implement [Params] and [Result] respectively, which is most
+// easily done by embedding [ParamsBase] and [ResultBase]:
+//
+// type SearchParams struct {
+// mcp.ParamsBase
+// Query string `json:"query"`
+// }
+//
+// type SearchResult struct {
+// mcp.ResultBase
+// Hits []string `json:"hits"`
+// }
+//
+// if err := mcp.AddReceivingCustomMethod(server, "acme/search",
+// func(ctx context.Context, ss *mcp.ServerSession, params *SearchParams) (*SearchResult, error) {
+// return &SearchResult{Hits: []string{"result"}}, nil
+// }); err != nil {
+// return err
+// }
+//
+// AddReceivingCustomMethod returns an error if method is the name of a
+// standard MCP method. Registering the same custom method twice replaces the
+// previous handler.
+func AddReceivingCustomMethod[P paramsPtr[T], R Result, T any](
+ s *Server,
+ method string,
+ handler func(ctx context.Context, ss *ServerSession, params P) (R, error),
+) error {
+ if _, ok := serverMethodInfos[method]; ok {
+ return fmt.Errorf("mcp: AddReceivingCustomMethod: %q shadows a standard MCP method", method)
+ }
+
+ typed := typedServerMethodHandler[P, R](func(ctx context.Context, req *ServerRequest[P]) (R, error) {
+ return handler(ctx, req.Session, req.Params)
+ })
+
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.receiveMethods[method] = newServerMethodInfo(typed, missingParamsOK)
+ return nil
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/session.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/session.go
index dcf9888..08eccaf 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/session.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/session.go
@@ -22,6 +22,13 @@ type ServerSessionState struct {
// InitializedParams are the parameters from 'notifications/initialized'.
InitializedParams *InitializedParams `json:"initializedParams"`
+ // NegotiatedProtocolVersion is the protocol version agreed during
+ // 'initialize', which may differ from the version the client requested if
+ // the server does not support it.
+ //
+ // It is empty for sessions that never ran the initialize handshake.
+ NegotiatedProtocolVersion string `json:"negotiatedProtocolVersion,omitempty"`
+
// LogLevel is the logging level for the session.
LogLevel LoggingLevel `json:"logLevel"`
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/shared.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/shared.go
index b5b09db..2258752 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/shared.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/shared.go
@@ -26,17 +26,29 @@ import (
"github.com/modelcontextprotocol/go-sdk/auth"
internaljson "github.com/modelcontextprotocol/go-sdk/internal/json"
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
+ "github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug"
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
)
+// nowrapinvalidparams is a compatibility parameter that restores the previous
+// behavior of [methodInfo.unmarshalParams]. When unset (the default), a
+// params-decoding failure is wrapped with [jsonrpc2.ErrInvalidParams] so the
+// wire response carries error code -32602 ("invalid params") rather than the
+// zero-value code 0. See:
+// https://github.com/modelcontextprotocol/go-sdk/issues/976#issuecomment-4829124838.
+//
+// See the documentation for the mcpgodebug package for instructions how to enable it.
+// The option will be removed in a future version of the SDK.
+var nowrapinvalidparams = mcpgodebug.Value("nowrapinvalidparams")
+
const (
// latestProtocolVersion is the latest protocol version that this version of
// the SDK supports.
//
// It is the version that the client sends in the initialization request, and
// the default version used by the server.
- latestProtocolVersion = protocolVersion20251125
- protocolVersion20260630 = "2026-06-30"
+ latestProtocolVersion = protocolVersion20260728
+ protocolVersion20260728 = "2026-07-28"
protocolVersion20251125 = "2025-11-25"
protocolVersion20250618 = "2025-06-18"
protocolVersion20250326 = "2025-03-26"
@@ -44,24 +56,57 @@ const (
)
var supportedProtocolVersions = []string{
+ protocolVersion20260728,
protocolVersion20251125,
protocolVersion20250618,
protocolVersion20250326,
protocolVersion20241105,
}
+// SupportedProtocolVersions returns the protocol versions supported by this
+// version of the SDK, newest first.
+//
+// Use it to discover the values accepted by
+// [ServerOptions.SupportedProtocolVersions]. The returned slice is a copy:
+// modifying it does not change what the SDK supports.
+func SupportedProtocolVersions() []string { return slices.Clone(supportedProtocolVersions) }
+
// negotiatedVersion returns the effective protocol version to use, given a
-// client version.
-func negotiatedVersion(clientVersion string) string {
- // In general, prefer to use the clientVersion, but if we don't support the
- // client's version, use the latest version.
+// client version and the versions the server supports, newest first.
+func negotiatedVersion(clientVersion string, supported []string) string {
+ // In general, prefer to use the clientVersion, but if not supported
+ // by the server, use the latest version the server supports.
//
- // This handles the case where a new spec version is released, and the SDK
- // does not support it yet.
- if !slices.Contains(supportedProtocolVersions, clientVersion) {
- return latestProtocolVersion
+ // Cap the supported versions at the legacy protocolVersion20251125, as this
+ // method is used by the initialize method which is deprecated in
+ // version protocolVersion20260728.
+ if slices.Contains(supported, clientVersion) && clientVersion < protocolVersion20260728 {
+ return clientVersion
}
- return clientVersion
+ for _, v := range supported {
+ if v < protocolVersion20260728 {
+ return v
+ }
+ }
+ // If the server was enforced to support only protocolVersion20260728 and
+ // later, the initialize function should not be called.
+ // If a client calls the initialize function, return the protocolVersion20251125.
+ // As according to spec (https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation):
+ // "If the server supports the requested protocol version, it MUST respond with the same version."
+ // "Otherwise, the server MUST respond with another protocol version it supports."
+ // "This SHOULD be the latest version supported by the server."
+ return protocolVersion20251125
+}
+
+// negotiateMutuallySupportedVersion returns a protocol version that is supported
+// by both the client and the server.
+func negotiateMutuallySupportedVersion(supported []string) string {
+ for _, ver := range supportedProtocolVersions {
+ if slices.Contains(supported, ver) {
+ return ver
+ }
+ }
+ return ""
}
// A MethodHandler handles MCP messages.
@@ -112,8 +157,12 @@ func defaultSendingMethodHandler(ctx context.Context, method string, req Request
// Create the result to unmarshal into.
// The concrete type of the result is the return type of the receiving function.
res := info.newResult()
- if err := call(ctx, req.GetSession().getConn(), method, params, res); err != nil {
- return nil, err
+ if method == methodSubscriptionsListen {
+ callSubscriptionsListen(ctx, req.GetSession().getConn(), method, params)
+ } else {
+ if err := call(ctx, req.GetSession().getConn(), method, params, res); err != nil {
+ return nil, err
+ }
}
return res, nil
}
@@ -287,7 +336,17 @@ func newMethodInfo[P paramsPtr[T], R Result, T any](flags methodFlags) methodInf
var p P
if m != nil {
if err := internaljson.Unmarshal(m, &p); err != nil {
- return nil, fmt.Errorf("unmarshaling %q into a %T: %w", m, p, err)
+ // Legacy behavior: pre-fix versions surfaced this as a
+ // plain wrapped error, which caused the wire response to
+ // carry code 0 instead of -32602. Restore via
+ // MCPGODEBUG=nowrapinvalidparams=1.
+ if nowrapinvalidparams == "1" {
+ return nil, fmt.Errorf("unmarshaling %q into a %T: %w", m, p, err)
+ }
+ // Wrap jsonrpc2.ErrInvalidParams so toWireError surfaces
+ // code -32602 ("invalid params") while preserving the
+ // descriptive message.
+ return nil, fmt.Errorf("%w: unmarshaling %q into a %T: %w", jsonrpc2.ErrInvalidParams, m, p, err)
}
}
// We must check missingParamsOK here, in addition to checkRequest, to
@@ -346,15 +405,29 @@ func clientSessionMethod[P Params, R Result](f func(*ClientSession, context.Cont
const (
// CodeHeaderMismatch indicates that HTTP headers do not match the corresponding values
// in the request body, or that required headers are missing or malformed.
- CodeHeaderMismatch = -32001
- // CodeResourceNotFound indicates that a requested resource could not be found.
- CodeResourceNotFound = -32002
+ CodeHeaderMismatch = -32020
+ // CodeMissingRequiredClientCapabilities is the JSON-RPC error code defined by
+ // SEP-2575 for MissingRequiredClientCapabilitiesError.
+ CodeMissingRequiredClientCapabilities = -32021
+ // CodeUnsupportedProtocolVersion is the JSON-RPC error code defined by
+ // SEP-2575 for UnsupportedProtocolVersionError.
+ CodeUnsupportedProtocolVersion = -32022
// CodeURLElicitationRequired indicates that the server requires URL elicitation
// before processing the request. The client should execute the elicitation handler
// with the elicitations provided in the error data.
CodeURLElicitationRequired = -32042
)
+// CodeResourceNotFound indicates that a requested resource could not be found.
+//
+// By default, the value is -32602 (Invalid Params), as specified in the
+// MCP specification (SEP-2164). To restore the pre-1.7.0 release behavior where the
+// error code was -32002, set MCPGODEBUG=customresnotfounderrcode=1.
+//
+// Deprecated: Use [jsonrpc.CodeInvalidParams] directly. This variable will be
+// removed in a future version.
+var CodeResourceNotFound int64 = jsonrpc.CodeInvalidParams
+
// URLElicitationRequiredError returns an error indicating that URL elicitation is required
// before the request can be processed. The elicitations parameter should contain the
// elicitation requests that must be completed.
@@ -457,6 +530,79 @@ func setProgressToken(p Params, pt any) {
m[progressTokenKey] = pt
}
+// extractRequestMeta performs a lightweight partial unmarshal of the `_meta`
+// field from a JSON-RPC request's raw params.
+func extractRequestMeta(rawParams json.RawMessage) Meta {
+ if len(rawParams) == 0 {
+ return nil
+ }
+ var meta struct {
+ Meta Meta `json:"_meta"`
+ }
+ if err := internaljson.Unmarshal(rawParams, &meta); err != nil {
+ return nil
+ }
+ return meta.Meta
+}
+
+type validatedMeta struct {
+ usesNewProtocol bool
+ initializeParams *InitializeParams
+ logLevel LoggingLevel
+}
+
+// validateRequestMeta inspects a JSON-RPC request to detect whether it follows
+// the >= 2026-07-28 protocol via the `_meta` field.
+// If the request has no _meta, or no protocolVersion in _meta, it returns a non-nil
+// validatedMeta with usesNewProtocol set to false, and a nil error.
+// If the request has a protocolVersion in _meta it validates the presence of
+// clientCapabilities in _meta. If it is missing or invalid, it returns nil and
+// a non-nil error. clientInfo is optional; if present but invalid, an error is
+// returned. Otherwise, it returns usesNewProtocol set to true and the populated
+// initializeParams.
+// Notifications always report usesNewProtocol false and never error.
+func validateRequestMeta(req *jsonrpc.Request) (*validatedMeta, error) {
+ // SEP-2575 defines the `_meta` triple for calls only: NotificationParams
+ // declares `_meta` optional with no protocolVersion, so a notification
+ // neither selects the new protocol nor is discarded for carrying an
+ // incomplete triple.
+ if !req.IsCall() {
+ return &validatedMeta{usesNewProtocol: false, initializeParams: nil}, nil
+ }
+ meta := extractRequestMeta(req.Params)
+ if meta == nil {
+ return &validatedMeta{usesNewProtocol: false, initializeParams: nil}, nil
+ }
+ protocolVersion, ok := meta[MetaKeyProtocolVersion].(string)
+ if !ok || protocolVersion < protocolVersion20260728 {
+ return &validatedMeta{usesNewProtocol: false, initializeParams: nil}, nil
+ }
+ var clientInfo *Implementation
+ if _, present := meta[MetaKeyClientInfo]; present {
+ var ok bool
+ clientInfo, ok = decodeMetaValue[*Implementation](meta, MetaKeyClientInfo)
+ if !ok {
+ return nil, &jsonrpc.Error{
+ Code: jsonrpc.CodeInvalidParams,
+ Message: fmt.Sprintf("invalid _meta field %q", MetaKeyClientInfo),
+ }
+ }
+ }
+ capabilities, ok := decodeMetaValue[*clientCapabilitiesV2](meta, MetaKeyClientCapabilities)
+ if !ok {
+ return nil, &jsonrpc.Error{
+ Code: jsonrpc.CodeInvalidParams,
+ Message: fmt.Sprintf("missing or invalid _meta field %q", MetaKeyClientCapabilities),
+ }
+ }
+ logLevel, _ := decodeMetaValue[LoggingLevel](meta, MetaKeyLogLevel)
+ return &validatedMeta{usesNewProtocol: true, initializeParams: &InitializeParams{
+ ProtocolVersion: protocolVersion,
+ Capabilities: capabilities.toV1(),
+ ClientInfo: clientInfo,
+ }, logLevel: logLevel}, nil
+}
+
// A Request is a method request with parameters and additional information, such as the session.
// Request is implemented by [*ClientRequest] and [*ServerRequest].
type Request interface {
@@ -495,6 +641,8 @@ type RequestExtra struct {
// to configure the reconnection delay.
//
// [SEP-1699]: https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1699
+ // This mechanism is deprecated in protocol version 2026-07-28 as the resumability
+ // feature is removed.
CloseSSEStream func(CloseSSEStreamArgs)
}
@@ -517,6 +665,94 @@ func (r *ServerRequest[P]) GetParams() Params { return r.Params }
func (r *ClientRequest[P]) GetExtra() *RequestExtra { return nil }
func (r *ServerRequest[P]) GetExtra() *RequestExtra { return r.Extra }
+// ProtocolVersion returns the protocol version negotiated for this request.
+//
+// For requests following the >= 2026-07-28 protocol, the value is read from
+// the per-request `_meta` field. For older protocol requests, the value falls
+// back to the session-level [InitializeParams] established during the
+// initialize handshake.
+func (r *ServerRequest[P]) ProtocolVersion() string {
+ if m := getRequestMeta(r); m != nil {
+ if v, ok := m[MetaKeyProtocolVersion].(string); ok {
+ return v
+ }
+ }
+ if r.Session != nil {
+ if p := r.Session.InitializeParams(); p != nil {
+ return p.ProtocolVersion
+ }
+ }
+ return ""
+}
+
+// ClientInfo returns the [Implementation] identifying the calling client.
+//
+// For requests following the >= 2026-07-28 protocol, the value is read from
+// the per-request `_meta` field. For older protocol requests, the value falls
+// back to the session-level [InitializeParams].
+func (r *ServerRequest[P]) ClientInfo() *Implementation {
+ if m := getRequestMeta(r); m != nil {
+ if v, ok := decodeMetaValue[*Implementation](m, MetaKeyClientInfo); ok {
+ return v
+ }
+ }
+ if r.Session != nil {
+ if p := r.Session.InitializeParams(); p != nil {
+ return p.ClientInfo
+ }
+ }
+ return nil
+}
+
+// ClientCapabilities returns the [ClientCapabilities] of the calling client.
+//
+// For requests following the >= 2026-07-28 protocol, the value is read from
+// the per-request `_meta` field. For older protocol requests, the value falls
+// back to the session-level [InitializeParams].
+func (r *ServerRequest[P]) ClientCapabilities() *ClientCapabilities {
+ if m := getRequestMeta(r); m != nil {
+ if v, ok := decodeMetaValue[*clientCapabilitiesV2](m, MetaKeyClientCapabilities); ok {
+ return v.toV1()
+ }
+ }
+ if r.Session != nil {
+ if p := r.Session.InitializeParams(); p != nil {
+ return p.Capabilities
+ }
+ }
+ return nil
+}
+
+// getRequestMeta returns the raw `_meta` map from the request's params, or
+// nil if the params are absent.
+func getRequestMeta[P Params](r *ServerRequest[P]) map[string]any {
+ // In practice P is a pointer type implementing Params.
+ if any(r.Params) == nil || r.Params.isNil() {
+ return nil
+ }
+ return r.Params.GetMeta()
+}
+
+// decodeMetaValue decodes a typed value out of a `_meta` map. Values may
+// arrive either as the typed Go value (when constructed in-process) or as
+// the generic JSON map produced by encoding/json after wire transit. In the
+// latter case, the value is re-encoded and decoded into the target type.
+func decodeMetaValue[T any](m map[string]any, key string) (T, bool) {
+ var zero T
+ raw, ok := m[key]
+ if !ok || raw == nil {
+ return zero, false
+ }
+ if v, ok := raw.(T); ok {
+ return v, true
+ }
+ var v T
+ if err := remarshal(raw, &v); err != nil {
+ return zero, false
+ }
+ return v, true
+}
+
func serverRequestFor[P Params](s *ServerSession, p P) *ServerRequest[P] {
return &ServerRequest[P]{Session: s, Params: p}
}
@@ -534,8 +770,27 @@ type Params interface {
// isParams discourages implementation of Params outside of this package.
isParams()
+
+ // isNil returns true if the underlying value is nil.
+ isNil() bool
+}
+
+// ParamsBase can be embedded in custom parameter structs to satisfy the
+// [Params] interface. It provides the required [Meta] field and the unexported
+// isParams marker method.
+//
+// type SearchParams struct {
+// mcp.ParamsBase
+// Query string `json:"query"`
+// }
+type ParamsBase struct {
+ Meta `json:"_meta,omitempty"`
}
+func (*ParamsBase) isParams() {}
+
+func (p *ParamsBase) isNil() bool { return p == nil }
+
// RequestParams is a parameter (input) type for an MCP request.
type RequestParams interface {
Params
@@ -560,6 +815,20 @@ type Result interface {
SetMeta(map[string]any)
}
+// ResultBase can be embedded in custom result structs to satisfy the
+// [Result] interface. It provides the required [Meta] field and the unexported
+// isResult marker method.
+//
+// type SearchResult struct {
+// mcp.ResultBase
+// Hits []string `json:"hits"`
+// }
+type ResultBase struct {
+ Meta `json:"_meta,omitempty"`
+}
+
+func (*ResultBase) isResult() {}
+
// emptyResult is returned by methods that have no result, like ping.
// Those methods cannot return nil, because jsonrpc2 cannot handle nils.
type emptyResult struct{}
@@ -588,9 +857,20 @@ type keepaliveSession interface {
// It assigns the cancel function to the provided cancelPtr and starts a goroutine
// that sends ping messages at the specified interval.
//
-// logger must be non-nil; ping failures (which terminate the keepalive loop and
-// close the session) are reported via logger so they are not silently dropped.
-func startKeepalive(session keepaliveSession, interval time.Duration, cancelPtr *context.CancelFunc, logger *slog.Logger) {
+// failureThreshold is the number of consecutive ping failures tolerated before
+// the session is closed; a value below 1 is treated as 1 (close on the first
+// failure). A successful ping resets the counter. This mirrors the spec's
+// "multiple failed pings MAY trigger a connection reset" language, letting a
+// transient miss pass without tearing down an otherwise live session.
+//
+// logger must be non-nil; ping failures (both the tolerated ones and the final
+// one that closes the session) are reported via logger so they are not silently
+// dropped.
+func startKeepalive(session keepaliveSession, interval time.Duration, failureThreshold int, cancelPtr *context.CancelFunc, logger *slog.Logger) {
+ if failureThreshold < 1 {
+ failureThreshold = 1
+ }
+
ctx, cancel := context.WithCancel(context.Background())
// Assign cancel function before starting goroutine to avoid race condition.
// We cannot return it because the caller may need to cancel during the
@@ -601,6 +881,7 @@ func startKeepalive(session keepaliveSession, interval time.Duration, cancelPtr
ticker := time.NewTicker(interval)
defer ticker.Stop()
+ consecutiveFailures := 0
for {
select {
case <-ctx.Done():
@@ -609,17 +890,32 @@ func startKeepalive(session keepaliveSession, interval time.Duration, cancelPtr
pingCtx, pingCancel := context.WithTimeout(context.Background(), interval/2)
err := session.Ping(pingCtx, nil)
pingCancel()
- if err != nil {
- if errors.Is(err, jsonrpc2.ErrMethodNotFound) {
- // Peer doesn't support ping, stop the keepalive process.
- return
- }
- // Ping failed; log it before closing the session so the
- // failure is observable to operators. See #218.
- logger.Error("keepalive ping failed; closing session", "error", err)
- _ = session.Close()
+ if err == nil {
+ consecutiveFailures = 0
+ continue
+ }
+ if errors.Is(err, jsonrpc2.ErrMethodNotFound) {
+ // Peer doesn't support ping, stop the keepalive process.
return
}
+ consecutiveFailures++
+ if consecutiveFailures < failureThreshold {
+ // Tolerate transient failures below the threshold; log so
+ // the misses are still observable to operators. See #218.
+ logger.Warn("keepalive ping failed; tolerating below threshold",
+ "error", err,
+ "consecutiveFailures", consecutiveFailures,
+ "failureThreshold", failureThreshold)
+ continue
+ }
+ // Threshold reached; log before closing the session so the
+ // failure is observable to operators. See #218.
+ logger.Error("keepalive ping failed; closing session",
+ "error", err,
+ "consecutiveFailures", consecutiveFailures,
+ "failureThreshold", failureThreshold)
+ _ = session.Close()
+ return
}
}
}()
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/sse.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/sse.go
index 7efaa95..0a5bf7f 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/sse.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/sse.go
@@ -8,6 +8,7 @@ import (
"bytes"
"context"
"crypto/rand"
+ "errors"
"fmt"
"io"
"mime"
@@ -65,6 +66,12 @@ type SSEOptions struct {
// Only disable this if you understand the security implications.
// See: https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices#local-mcp-server-compromise
DisableLocalhostProtection bool
+
+ // MaxRequestBodyBytes limits the number of bytes read from an incoming
+ // POST body before the server responds with 413 Request Entity Too Large.
+ // It matches [StreamableHTTPOptions.MaxRequestBodyBytes]: if zero,
+ // [DefaultMaxRequestBodyBytes] is used; a negative value disables the limit.
+ MaxRequestBodyBytes int64
}
// NewSSEHandler returns a new [SSEHandler] that creates and manages MCP
@@ -122,6 +129,12 @@ type SSEServerTransport struct {
// Response is the hanging response body to the incoming GET request.
Response http.ResponseWriter
+ // MaxRequestBodyBytes limits the number of bytes read from a POSTed
+ // message body before [SSEServerTransport.ServeHTTP] responds with 413
+ // Request Entity Too Large. If zero, [DefaultMaxRequestBodyBytes] is used;
+ // a negative value disables the limit. See [SSEOptions.MaxRequestBodyBytes].
+ MaxRequestBodyBytes int64
+
// incoming is the queue of incoming messages.
// It is never closed, and by convention, incoming is non-nil if and only if
// the transport is connected.
@@ -143,9 +156,22 @@ func (t *SSEServerTransport) ServeHTTP(w http.ResponseWriter, req *http.Request)
return
}
+ limit := t.MaxRequestBodyBytes
+ if limit == 0 {
+ limit = DefaultMaxRequestBodyBytes
+ }
+ if limit > 0 && req.Body != nil {
+ req.Body = http.MaxBytesReader(w, req.Body, limit)
+ }
+
// Read and parse the message.
data, err := io.ReadAll(req.Body)
if err != nil {
+ var mbe *http.MaxBytesError
+ if errors.As(err, &mbe) {
+ http.Error(w, fmt.Sprintf("request body exceeds %d bytes", mbe.Limit), http.StatusRequestEntityTooLarge)
+ return
+ }
http.Error(w, "failed to read body", http.StatusBadRequest)
return
}
@@ -189,10 +215,17 @@ func (t *SSEServerTransport) Connect(context.Context) (Connection, error) {
return &sseServerConn{t: t}, nil
}
+// SupportsProtocolVersion reports whether the HTTP+SSE transport can serve the
+// given protocol version. MCP 2026-07-28 defines only the stdio and Streamable
+// HTTP bindings, so this (deprecated) transport does not advertise that revision.
+func (t *SSEServerTransport) SupportsProtocolVersion(version string) bool {
+ return version < protocolVersion20260728
+}
+
func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// DNS rebinding protection: auto-enabled for localhost servers.
// See: https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices#local-mcp-server-compromise
- if !h.opts.DisableLocalhostProtection && disablelocalhostprotection != "1" {
+ if !h.opts.DisableLocalhostProtection {
if localAddr, ok := req.Context().Value(http.LocalAddrContextKey).(net.Addr); ok && localAddr != nil {
if util.IsLoopback(localAddr.String()) && !util.IsLoopback(req.Host) {
http.Error(w, fmt.Sprintf("Forbidden: invalid Host header %q", req.Host), http.StatusForbidden)
@@ -202,7 +235,7 @@ func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
// Validate 'Content-Type' header.
- if disablecontenttypecheck != "1" && req.Method == http.MethodPost {
+ if req.Method == http.MethodPost {
mediaType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type"))
if err != nil || mediaType != "application/json" {
http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
@@ -253,7 +286,11 @@ func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
- transport := &SSEServerTransport{Endpoint: endpoint.RequestURI(), Response: w}
+ transport := &SSEServerTransport{
+ Endpoint: endpoint.RequestURI(),
+ Response: w,
+ MaxRequestBodyBytes: h.opts.MaxRequestBodyBytes,
+ }
// The session is terminated when the request exits.
h.mu.Lock()
@@ -360,6 +397,11 @@ type SSEClientTransport struct {
// HTTPClient is the client to use for making HTTP requests. If nil,
// http.DefaultClient is used.
HTTPClient *http.Client
+
+ // MaxEventSize bounds the number of bytes buffered while reading a single
+ // server-sent event. A value of 0 selects [DefaultMaxEventSize], a negative
+ // value disables the cap.
+ MaxEventSize int
}
// Connect connects through the client endpoint.
@@ -390,9 +432,14 @@ func (c *SSEClientTransport) Connect(ctx context.Context) (Connection, error) {
return nil, fmt.Errorf("failed to connect: %s", http.StatusText(resp.StatusCode))
}
+ maxEventSize := c.MaxEventSize
+ if maxEventSize == 0 {
+ maxEventSize = DefaultMaxEventSize
+ }
+
msgEndpoint, err := func() (*url.URL, error) {
var evt Event
- for evt, err = range scanEvents(resp.Body) {
+ for evt, err = range scanEventsLimited(resp.Body, maxEventSize) {
break
}
if err != nil {
@@ -421,7 +468,7 @@ func (c *SSEClientTransport) Connect(ctx context.Context) (Connection, error) {
go func() {
defer s.Close() // close the transport when the GET exits
- for evt, err := range scanEvents(resp.Body) {
+ for evt, err := range scanEventsLimited(resp.Body, maxEventSize) {
if err != nil {
return
}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable.go
index 43fe03e..f24badb 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable.go
@@ -37,6 +37,7 @@ import (
"github.com/modelcontextprotocol/go-sdk/internal/util"
"github.com/modelcontextprotocol/go-sdk/internal/xcontext"
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
+ "golang.org/x/oauth2"
)
// A StreamableHTTPHandler is an http.Handler that serves streamable MCP
@@ -127,12 +128,21 @@ func (i *sessionInfo) stopTimer() {
type StreamableHTTPOptions struct {
// Stateless controls whether the session is 'stateless'.
//
- // A stateless server does not validate the Mcp-Session-Id header, and uses a
- // temporary session with default initialization parameters. Any
+ // A stateless server does not read or set the Mcp-Session-Id header, and
+ // uses a temporary session with default initialization parameters for each
+ // request. [ServerOptions.GetSessionID] is not consulted. Any
// server->client request is rejected immediately as there's no way for the
// client to respond. Server->Client notifications may reach the client if
// they are made in the context of an incoming request, as described in the
// documentation for [StreamableServerTransport].
+ // In Stateless mode, GET and DELETE requests return 405 Method Not Allowed.
+ //
+ // This mode aligns with the sessionless direction of the MCP spec; see
+ // [SEP-2567]. The previous behavior, in which stateless servers still
+ // honored Mcp-Session-Id, can be restored temporarily via the
+ // MCPGODEBUG compatibility parameter "allowsessionsinstateless=1".
+ //
+ // [SEP-2567]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2567
Stateless bool
// TODO(#148): support session retention (?)
@@ -174,8 +184,7 @@ type StreamableHTTPOptions struct {
// CrossOriginProtection allows to customize cross-origin protection.
// The deny handler set in the CrossOriginProtection through SetDenyHandler
// is ignored.
- // If nil, no cross-origin protection is applied. Use the `enableoriginverification`
- // MCPGODEBUG compatibility parameter to enable the default protection until v1.8.0.
+ // If nil, no cross-origin protection is applied.
//
// Deprecated: wrap the handler with cross-origin protection middleware
// instead. For example:
@@ -184,8 +193,36 @@ type StreamableHTTPOptions struct {
// protection := http.NewCrossOriginProtection()
// protectedHandler := protection.Handler(handler)
CrossOriginProtection *http.CrossOriginProtection
+
+ // MaxRequestBodyBytes limits the number of bytes read from any incoming
+ // HTTP request body. Requests that exceed this limit are rejected with
+ // 413 Request Entity Too Large.
+ //
+ // The limit is enforced during the read, so it applies uniformly to
+ // requests using Content-Length, Transfer-Encoding: chunked, or HTTP/2
+ // (which has no Content-Length).
+ //
+ // If zero, [DefaultMaxRequestBodyBytes] is used.
+ // A negative value disables the limit entirely; do not use this on
+ // servers exposed to untrusted clients.
+ MaxRequestBodyBytes int64
+
+ // PropagateRequestCancellation, when true, ties the in-flight handler
+ // context to the originating HTTP request's context. Only applies to
+ // requests using the >= 2026-07-28 protocol, where the POST is the whole
+ // request lifecycle.
+ // The handler context cancels whenever the HTTP request context does as the
+ // response can no longer be delivered, so cancelling the handler is safe.
+ //
+ // Requests using older protocol versions (including those routed through
+ // the allowsessionsinstateless compatibility path) are unaffected.
+ PropagateRequestCancellation bool
}
+// DefaultMaxRequestBodyBytes is the default value used for
+// [StreamableHTTPOptions.MaxRequestBodyBytes] when it is left at zero.
+const DefaultMaxRequestBodyBytes = 4 << 20 // 4 MiB
+
// NewStreamableHTTPHandler returns a new [StreamableHTTPHandler].
//
// The getServer function is used to create or look up servers for new
@@ -202,8 +239,8 @@ func NewStreamableHTTPHandler(getServer func(*http.Request) *Server, opts *Strea
h.opts.Logger = ensureLogger(h.opts.Logger)
- if h.opts.CrossOriginProtection == nil && enableoriginverification == "1" {
- h.opts.CrossOriginProtection = &http.CrossOriginProtection{}
+ if h.opts.MaxRequestBodyBytes == 0 {
+ h.opts.MaxRequestBodyBytes = DefaultMaxRequestBodyBytes
}
return h
@@ -232,30 +269,54 @@ func (h *StreamableHTTPHandler) closeAll() {
}
}
-// disablelocalhostprotection is a compatibility parameter that allows to disable
-// DNS rebinding protection, which was added in the 1.4.0 version of the SDK.
-// See the documentation for the mcpgodebug package for instructions how to enable it.
-// The option will be removed in the 1.8.0 version of the SDK.
-var disablelocalhostprotection = mcpgodebug.Value("disablelocalhostprotection")
-
-// enableoriginverification is a compatibility parameter that restores the
-// default cross-origin protection behavior from v1.4.1-v1.5.0. When set to
-// "1", a zero-value CrossOriginProtection will be applied if none is
-// explicitly provided in StreamableHTTPOptions.
-// See the documentation for the mcpgodebug package for instructions how to enable it.
-// The option will be removed in the 1.8.0 version of the SDK.
-var enableoriginverification = mcpgodebug.Value("enableoriginverification")
-
-// disablecontenttypecheck is a compatibility parameter that allows to disable
-// Content-Type validation on POST requests.
+// allowsessionsinstateless is a compatibility parameter that restores the old
+// behavior of reading and using Mcp-Session-Id headers in stateless mode. When
+// set to "1", stateless servers will read the session ID from the request
+// header (or generate one via GetSessionID), set it on response headers, and
+// accept DELETE requests. When unset (the default), stateless servers ignore
+// session IDs entirely and reject DELETE with 405.
// See the documentation for the mcpgodebug package for instructions how to enable it.
-// The option will be removed in the 1.8.0 version of the SDK.
-var disablecontenttypecheck = mcpgodebug.Value("disablecontenttypecheck")
+// The option will be removed in the 1.9.0 version of the SDK.
+var allowsessionsinstateless = mcpgodebug.Value("allowsessionsinstateless")
+
+// noprotocolerrorbody is a compatibility parameter that restores the previous
+// behavior of [streamableClientConn.checkResponse]. When unset (the default),
+// the client attempts to decode the response body of a non-2xx response as a
+// JSON-RPC error. If successful, the underlying JSON-RPC error is surfaced to
+// the caller and wrapped with [jsonrpc2.ErrRejected] so that per-call
+// rejections do not tear down the session. When set to "1", the client
+// ignores response bodies on non-2xx responses and any non-transient error
+// permanently fails the connection.
+var noprotocolerrorbody = mcpgodebug.Value("noprotocolerrorbody")
+
+// plaintextstatefulrejection is a compatibility parameter that restores the
+// previous behavior of a stateful [StreamableHTTPHandler] when it receives a
+// request carrying SEP-2575 per-request metadata (i.e. an
+// `io.modelcontextprotocol/protocolVersion` `_meta` field, or an
+// `MCP-Protocol-Version` header >= 2026-07-28). When unset (the default), the
+// server responds with a JSON-RPC error of code
+// [CodeUnsupportedProtocolVersion] and an [UnsupportedProtocolVersionData]
+// payload listing its supported legacy versions, as required by SEP-2575. When
+// set to "1", the server instead responds with a plain-text `http.Error` body
+// mentioning the `StreamableHTTPOptions.Stateless` field.
+var plaintextstatefulrejection = mcpgodebug.Value("plaintextstatefulrejection")
+
+// writeJSONRPCError writes a JSON-RPC error response with the given HTTP
+// status code, request ID (may be a zero ID for errors that occur before the
+// request body has been parsed), and JSON-RPC error.
+func writeJSONRPCError(w http.ResponseWriter, status int, id jsonrpc.ID, jerr *jsonrpc.Error) {
+ resp := &jsonrpc.Response{ID: id, Error: jerr}
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(status)
+ if data, err := jsonrpc2.EncodeMessage(resp); err == nil {
+ w.Write(data)
+ }
+}
func (h *StreamableHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// DNS rebinding protection: auto-enabled for localhost servers.
// See: https://modelcontextprotocol.io/specification/2025-11-25/basic/security_best_practices#local-mcp-server-compromise
- if !h.opts.DisableLocalhostProtection && disablelocalhostprotection != "1" {
+ if !h.opts.DisableLocalhostProtection {
if localAddr, ok := req.Context().Value(http.LocalAddrContextKey).(net.Addr); ok && localAddr != nil {
if util.IsLoopback(localAddr.String()) && !util.IsLoopback(req.Host) {
http.Error(w, fmt.Sprintf("Forbidden: invalid Host header %q", req.Host), http.StatusForbidden)
@@ -265,283 +326,416 @@ func (h *StreamableHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Reque
}
if h.opts.CrossOriginProtection != nil {
- // Verify the 'Origin' header to protect against CSRF attacks.
if err := h.opts.CrossOriginProtection.Check(req); err != nil {
http.Error(w, err.Error(), http.StatusForbidden)
return
}
}
- // Validate 'Content-Type' header.
- if disablecontenttypecheck != "1" && req.Method == http.MethodPost && baseMediaType(req.Header.Get("Content-Type")) != "application/json" {
+ // Bound the request body to protect against OOM attacks.
+ if req.Body != nil && h.opts.MaxRequestBodyBytes > 0 {
+ req.Body = http.MaxBytesReader(w, req.Body, h.opts.MaxRequestBodyBytes)
+ }
+
+ // [§2.7] of the spec (2025-06-18): validate the MCP-Protocol-Version
+ // header. If provided, it must be a version the server negotiates, which
+ // [ServerOptions.SupportedProtocolVersions] may have narrowed. If absent,
+ // the version is unknown (the request may be an initialize for any
+ // version).
+ //
+ // [§2.7]: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#protocol-version-header
+ protocolVersion := req.Header.Get(protocolVersionHeader)
+ var supportedVersions []string
+ if server := h.getServer(req); server != nil {
+ supportedVersions = server.protocolVersions
+ } else {
+ supportedVersions = supportedProtocolVersions
+ }
+ if protocolVersion != "" && !slices.Contains(supportedVersions, protocolVersion) && protocolVersion < protocolVersion20260728 {
+ http.Error(w, fmt.Sprintf("Bad Request: Unsupported protocol version (supported versions: %s)", strings.Join(supportedVersions, ",")), http.StatusBadRequest)
+ return
+ }
+ req = req.WithContext(context.WithValue(req.Context(), protocolVersionContextKey{}, protocolVersion))
+
+ if h.opts.Stateless {
+ h.serveStateless(w, req)
+ } else {
+ h.serveStateful(w, req)
+ }
+}
+
+// serveStateless handles requests for stateless servers.
+// Stateless servers only support POST. Each request creates a temporary
+// session that is closed when the request completes.
+//
+// When the allowsessionsinstateless compatibility flag is set, DELETE is also
+// accepted (as a no-op) and session IDs are read from the request header.
+func (h *StreamableHTTPHandler) serveStateless(w http.ResponseWriter, req *http.Request) {
+ legacySessions := allowsessionsinstateless == "1"
+
+ if req.Method == http.MethodDelete && legacySessions {
+ h.serveStatelessLegacyDELETE(w, req)
+ return
+ }
+
+ if req.Method != http.MethodPost {
+ // RFC 9110 §15.5.6: 405 responses MUST include Allow header.
+ w.Header().Set("Allow", "POST")
+ http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ if baseMediaType(req.Header.Get("Content-Type")) != "application/json" {
http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
return
}
- // Allow multiple 'Accept' headers.
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept#syntax
+ // Accept must contain both 'application/json' and 'text/event-stream'.
jsonOK, streamOK := streamableAccepts(req.Header.Values("Accept"))
-
- if req.Method == http.MethodGet {
- if !streamOK {
- http.Error(w, "Accept must contain 'text/event-stream' for GET requests", http.StatusBadRequest)
- return
- }
- } else if (!jsonOK || !streamOK) && req.Method != http.MethodDelete { // TODO: consolidate with handling of http method below.
+ if !jsonOK || !streamOK {
http.Error(w, "Accept must contain both 'application/json' and 'text/event-stream'", http.StatusBadRequest)
return
}
- sessionID := req.Header.Get(sessionIDHeader)
- var sessInfo *sessionInfo
- if sessionID != "" {
- h.mu.Lock()
- sessInfo = h.sessions[sessionID]
- h.mu.Unlock()
- if sessInfo == nil && !h.opts.Stateless {
- // Unless we're in 'stateless' mode, which doesn't perform any Session-ID
- // validation, we require that the session ID matches a known session.
- //
- // In stateless mode, a temporary transport is be created below.
- http.Error(w, "session not found", http.StatusNotFound)
+ server := h.getServer(req)
+ if server == nil {
+ http.Error(w, "no server available", http.StatusBadRequest)
+ return
+ }
+
+ info, err := h.ephemeralConnectOpts(req)
+ if err != nil {
+ var mbe *http.MaxBytesError
+ if errors.As(err, &mbe) {
+ http.Error(w, fmt.Sprintf("request body exceeds %d bytes", mbe.Limit), http.StatusRequestEntityTooLarge)
return
}
- // Prevent session hijacking: if the session was created with a user ID,
- // verify that subsequent requests come from the same user.
- if sessInfo != nil && sessInfo.userID != "" {
- tokenInfo := auth.TokenInfoFromContext(req.Context())
- if tokenInfo == nil || tokenInfo.UserID != sessInfo.userID {
- http.Error(w, "session user mismatch", http.StatusForbidden)
- return
- }
- }
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
}
- if req.Method == http.MethodDelete {
+ var sessionID string
+ if legacySessions && !info.usesNewProtocol {
+ sessionID = req.Header.Get(sessionIDHeader)
if sessionID == "" {
- http.Error(w, "Bad Request: DELETE requires an Mcp-Session-Id header", http.StatusBadRequest)
- return
- }
- if sessInfo != nil { // sessInfo may be nil in stateless mode
- // Closing the session also removes it from h.sessions, due to the
- // onClose callback.
- sessInfo.session.Close()
+ sessionID = server.opts.GetSessionID()
}
- w.WriteHeader(http.StatusNoContent)
+ }
+
+ transport := &StreamableServerTransport{
+ SessionID: sessionID,
+ Stateless: true,
+ EventStore: h.opts.EventStore,
+ jsonResponse: h.opts.JSONResponse,
+ logger: h.opts.Logger,
+ shouldPropagateCancellation: info.usesNewProtocol && (info.isSubscriptionsListen || h.opts.PropagateRequestCancellation),
+ }
+
+ session, err := connectStreamable(req.Context(), server, transport, info.opts)
+ if err != nil {
+ h.opts.Logger.Error(fmt.Sprintf("failed to connect: %v", err))
+ http.Error(w, "failed connection", http.StatusInternalServerError)
return
}
+ defer session.Close()
- switch req.Method {
- case http.MethodPost, http.MethodGet:
- if req.Method == http.MethodGet && (h.opts.Stateless || sessionID == "") {
- if h.opts.Stateless {
- // Per MCP spec: server MUST return 405 if it doesn't offer SSE stream.
- // In stateless mode, GET (SSE streaming) is not supported.
- // RFC 9110 §15.5.6: 405 responses MUST include Allow header.
- w.Header().Set("Allow", "POST")
- http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
- } else {
- // In stateful mode, GET is supported but requires a session ID.
- // This is a precondition error, similar to DELETE without session.
- http.Error(w, "Bad Request: GET requires an Mcp-Session-Id header", http.StatusBadRequest)
+ transport.ServeHTTP(w, req)
+}
+
+// serveStatelessLegacyDELETE handles DELETE requests in stateless mode when the
+// allowsessionsinstateless compatibility flag is set. DELETE requires a
+// Mcp-Session-Id header but is otherwise a no-op since stateless servers don't
+// persist sessions.
+func (h *StreamableHTTPHandler) serveStatelessLegacyDELETE(w http.ResponseWriter, req *http.Request) {
+ sessionID := req.Header.Get(sessionIDHeader)
+ if sessionID == "" {
+ http.Error(w, "Bad Request: DELETE requires an Mcp-Session-Id header", http.StatusBadRequest)
+ return
+ }
+ w.WriteHeader(http.StatusNoContent)
+}
+
+type ephemeralConnectInfo struct {
+ opts *ServerSessionOptions
+ usesNewProtocol bool
+ isSubscriptionsListen bool
+}
+
+// ephemeralConnectOpts peeks at the request body to determine connection
+// parameters and whether protocol version >= 2026-06-30 (SEP-2575).
+//
+// For old-protocol requests, default session state is synthesized so that
+// the session's init gate doesn't reject the request.
+//
+// It is used for both stateless servers and stateful servers with no session ID.
+func (h *StreamableHTTPHandler) ephemeralConnectOpts(req *http.Request) (*ephemeralConnectInfo, error) {
+ protocolVersion := protocolVersionFromContext(req.Context())
+ if protocolVersion == "" {
+ protocolVersion = protocolVersion20250326
+ }
+
+ var hasInitialize, hasInitialized, usesNewProtocol, isSubscriptionsListen bool
+ body, err := io.ReadAll(req.Body)
+ if err != nil {
+ // Preserve *http.MaxBytesError so serveStateless can respond with 413.
+ return nil, fmt.Errorf("failed to read body: %w", err)
+ }
+ req.Body.Close()
+ req.Body = io.NopCloser(bytes.NewBuffer(body))
+ msgs, _, err := readBatch(body)
+ if err == nil {
+ for _, msg := range msgs {
+ if r, ok := msg.(*jsonrpc.Request); ok {
+ switch r.Method {
+ case methodInitialize:
+ hasInitialize = true
+ case notificationInitialized:
+ hasInitialized = true
+ case methodSubscriptionsListen:
+ isSubscriptionsListen = true
+ }
+ if protocolVersion >= protocolVersion20260728 {
+ usesNewProtocol = true
+ }
}
- return
}
+ }
+
+ state := new(ServerSessionState)
+ // Only synthesize fake InitializeParams/InitializedParams for old-protocol
+ // requests.
+ if !hasInitialize && !usesNewProtocol {
+ state.InitializeParams = &InitializeParams{
+ ProtocolVersion: protocolVersion,
+ }
+ }
+ if !hasInitialized && !usesNewProtocol {
+ state.InitializedParams = new(InitializedParams)
+ }
+ if !usesNewProtocol {
+ state.LogLevel = "info"
+ }
+ return &ephemeralConnectInfo{
+ opts: &ServerSessionOptions{
+ State: state,
+ },
+ usesNewProtocol: usesNewProtocol,
+ isSubscriptionsListen: isSubscriptionsListen,
+ }, nil
+}
+
+func connectStreamable(ctx context.Context, server *Server, transport *StreamableServerTransport, opts *ServerSessionOptions) (*ServerSession, error) {
+ s, err := server.Connect(ctx, transport, opts)
+ if err != nil {
+ return nil, err
+ }
+ transport.connection.server = server
+ transport.connection.toolLookup = server.getServerTool
+ return s, nil
+}
+
+// serveStateful handles requests for stateful servers.
+// Stateful servers support GET, POST, and DELETE, and maintain persistent
+// sessions keyed by session ID.
+func (h *StreamableHTTPHandler) serveStateful(w http.ResponseWriter, req *http.Request) {
+ switch req.Method {
+ case http.MethodGet:
+ h.serveStatefulGET(w, req)
+ case http.MethodPost:
+ h.serveStatefulPOST(w, req)
+ case http.MethodDelete:
+ h.serveStatefulDELETE(w, req)
default:
// RFC 9110 §15.5.6: 405 responses MUST include Allow header.
- if h.opts.Stateless {
- w.Header().Set("Allow", "POST")
- } else {
- w.Header().Set("Allow", "GET, POST, DELETE")
- }
+ w.Header().Set("Allow", "GET, POST, DELETE")
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
+ }
+}
+
+// lookupSession looks up a session by the Mcp-Session-Id header value.
+// It returns the session info and whether the caller should proceed. If ok is
+// false, an error response has been written. The sessionID must be non-empty;
+// callers are responsible for checking this before calling lookupSession.
+func (h *StreamableHTTPHandler) lookupSession(w http.ResponseWriter, req *http.Request, sessionID string) (info *sessionInfo, ok bool) {
+ h.mu.Lock()
+ info = h.sessions[sessionID]
+ h.mu.Unlock()
+ if info == nil {
+ http.Error(w, "session not found", http.StatusNotFound)
+ return nil, false
+ }
+ if info.userID != "" {
+ tokenInfo := auth.TokenInfoFromContext(req.Context())
+ if tokenInfo == nil || tokenInfo.UserID != info.userID {
+ http.Error(w, "session user mismatch", http.StatusForbidden)
+ return nil, false
+ }
+ }
+ return info, true
+}
+
+// serveStatefulGET handles GET requests for standalone SSE streams.
+// GET requires a valid Mcp-Session-Id header.
+func (h *StreamableHTTPHandler) serveStatefulGET(w http.ResponseWriter, req *http.Request) {
+ if _, streamOK := streamableAccepts(req.Header.Values("Accept")); !streamOK {
+ http.Error(w, "Accept must contain 'text/event-stream' for GET requests", http.StatusBadRequest)
return
}
- // [§2.7] of the spec (2025-06-18) states:
- //
- // "If using HTTP, the client MUST include the MCP-Protocol-Version:
- // HTTP header on all subsequent requests to the MCP
- // server, allowing the MCP server to respond based on the MCP protocol
- // version.
- //
- // For example: MCP-Protocol-Version: 2025-06-18
- // The protocol version sent by the client SHOULD be the one negotiated during
- // initialization.
- //
- // For backwards compatibility, if the server does not receive an
- // MCP-Protocol-Version header, and has no other way to identify the version -
- // for example, by relying on the protocol version negotiated during
- // initialization - the server SHOULD assume protocol version 2025-03-26.
- //
- // If the server receives a request with an invalid or unsupported
- // MCP-Protocol-Version, it MUST respond with 400 Bad Request."
- //
- // Since this wasn't present in the 2025-03-26 version of the spec, this
- // effectively means:
- // 1. IF the client provides a version header, it must be a supported
- // version.
- // 2. In stateless mode, where we've lost the state of the initialize
- // request, we assume that whatever the client tells us is the truth (or
- // assume 2025-03-26 if the client doesn't say anything).
- //
- // This logic matches the typescript SDK.
- //
- // [§2.7]: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#protocol-version-header
- protocolVersion := req.Header.Get(protocolVersionHeader)
- if protocolVersion == "" {
- protocolVersion = protocolVersion20250326
+ sessionID := req.Header.Get(sessionIDHeader)
+ if sessionID == "" {
+ http.Error(w, "Bad Request: GET requires an Mcp-Session-Id header", http.StatusBadRequest)
+ return
+ }
+
+ sessInfo, ok := h.lookupSession(w, req, sessionID)
+ if !ok {
+ return
}
- if !slices.Contains(supportedProtocolVersions, protocolVersion) {
- http.Error(w, fmt.Sprintf("Bad Request: Unsupported protocol version (supported versions: %s)", strings.Join(supportedProtocolVersions, ",")), http.StatusBadRequest)
+
+ sessInfo.transport.ServeHTTP(w, req)
+}
+
+// serveStatefulDELETE handles DELETE requests for session termination.
+// DELETE requires a valid Mcp-Session-Id header.
+func (h *StreamableHTTPHandler) serveStatefulDELETE(w http.ResponseWriter, req *http.Request) {
+ sessionID := req.Header.Get(sessionIDHeader)
+ if sessionID == "" {
+ http.Error(w, "Bad Request: DELETE requires an Mcp-Session-Id header", http.StatusBadRequest)
+ return
+ }
+
+ sessInfo, ok := h.lookupSession(w, req, sessionID)
+ if !ok {
+ return
+ }
+
+ sessInfo.session.Close()
+ w.WriteHeader(http.StatusNoContent)
+}
+
+// serveStatefulPOST handles POST requests for stateful servers.
+// POST may arrive with or without a Mcp-Session-Id header. Without a session
+// ID, a new session is created (this is the normal path for the first
+// initialize request).
+func (h *StreamableHTTPHandler) serveStatefulPOST(w http.ResponseWriter, req *http.Request) {
+ if baseMediaType(req.Header.Get("Content-Type")) != "application/json" {
+ http.Error(w, "Content-Type must be 'application/json'", http.StatusUnsupportedMediaType)
return
}
- if sessInfo == nil {
- server := h.getServer(req)
- if server == nil {
- // The getServer argument to NewStreamableHTTPHandler returned nil.
- http.Error(w, "no server available", http.StatusBadRequest)
+ jsonOK, streamOK := streamableAccepts(req.Header.Values("Accept"))
+ if !jsonOK || !streamOK {
+ http.Error(w, "Accept must contain both 'application/json' and 'text/event-stream'", http.StatusBadRequest)
+ return
+ }
+
+ sessionID := req.Header.Get(sessionIDHeader)
+
+ // Look up existing session if a session ID was provided.
+ if sessionID != "" {
+ sessInfo, ok := h.lookupSession(w, req, sessionID)
+ if !ok {
return
}
- if sessionID == "" {
- // In stateless mode, sessionID may be nonempty even if there's no
- // existing transport.
- sessionID = server.opts.GetSessionID()
- }
- transport := &StreamableServerTransport{
- SessionID: sessionID,
- Stateless: h.opts.Stateless,
- EventStore: h.opts.EventStore,
- jsonResponse: h.opts.JSONResponse,
- logger: h.opts.Logger,
- }
-
- // Sessions without a session ID are also stateless: there's no way to
- // address them.
- stateless := h.opts.Stateless || sessionID == ""
- // To support stateless mode, we initialize the session with a default
- // state, so that it doesn't reject subsequent requests.
- var connectOpts *ServerSessionOptions
- if stateless {
- // Peek at the body to see if it is initialize or initialized.
- // We want those to be handled as usual.
- var hasInitialize, hasInitialized bool
- {
- // TODO: verify that this allows protocol version negotiation for
- // stateless servers.
- body, err := io.ReadAll(req.Body)
- if err != nil {
- http.Error(w, "failed to read body", http.StatusBadRequest)
- return
- }
- req.Body.Close()
-
- // Reset the body so that it can be read later.
- req.Body = io.NopCloser(bytes.NewBuffer(body))
-
- msgs, _, err := readBatch(body)
- if err == nil {
- for _, msg := range msgs {
- if req, ok := msg.(*jsonrpc.Request); ok {
- switch req.Method {
- case methodInitialize:
- hasInitialize = true
- case notificationInitialized:
- hasInitialized = true
- }
- }
- }
- }
- }
+ sessInfo.startPOST()
+ defer sessInfo.endPOST()
+ sessInfo.transport.ServeHTTP(w, req)
+ return
+ }
- // If we don't have InitializeParams or InitializedParams in the request,
- // set the initial state to a default value.
- state := new(ServerSessionState)
- if !hasInitialize {
- state.InitializeParams = &InitializeParams{
- ProtocolVersion: protocolVersion,
- }
- }
- if !hasInitialized {
- state.InitializedParams = new(InitializedParams)
- }
- state.LogLevel = "info"
- connectOpts = &ServerSessionOptions{
- State: state,
- }
- } else {
- // Cleanup is only required in stateful mode, as transportation is
- // not stored in the map otherwise.
- connectOpts = &ServerSessionOptions{
- onClose: func() {
- h.mu.Lock()
- defer h.mu.Unlock()
- if info, ok := h.sessions[transport.SessionID]; ok {
- info.stopTimer()
- delete(h.sessions, transport.SessionID)
- if h.onTransportDeletion != nil {
- h.onTransportDeletion(transport.SessionID)
- }
- }
- },
- }
- }
+ // No session ID: create a new session.
+ server := h.getServer(req)
+ if server == nil {
+ http.Error(w, "no server available", http.StatusBadRequest)
+ return
+ }
+ sessionID = server.opts.GetSessionID()
+
+ transport := &StreamableServerTransport{
+ SessionID: sessionID,
+ Stateless: false,
+ EventStore: h.opts.EventStore,
+ jsonResponse: h.opts.JSONResponse,
+ logger: h.opts.Logger,
+ }
- // Pass req.Context() here, to allow middleware to add context values.
- // The context is detached in the jsonrpc2 library when handling the
- // long-running stream.
- session, err := server.Connect(req.Context(), transport, connectOpts)
+ // Sessions without a session ID (GetSessionID returned "") are ephemeral:
+ // there's no way to address them, so they are closed after the request.
+ // This can happen when ServerOptions.GetSessionID is explicitly set to
+ // return "" to suppress session IDs entirely. It also covers any request
+ // that arrives before a session exists (e.g. initialize or ping) on a
+ // server configured this way.
+ if sessionID == "" {
+ info, err := h.ephemeralConnectOpts(req)
if err != nil {
- http.Error(w, "failed connection", http.StatusInternalServerError)
+ http.Error(w, err.Error(), http.StatusBadRequest)
return
}
- // Capture the user ID from the token info to enable session hijacking
- // prevention on subsequent requests.
- var userID string
- if tokenInfo := auth.TokenInfoFromContext(req.Context()); tokenInfo != nil {
- userID = tokenInfo.UserID
- }
- sessInfo = &sessionInfo{
- session: session,
- transport: transport,
- userID: userID,
+ session, err := connectStreamable(req.Context(), server, transport, info.opts)
+ if err != nil {
+ h.opts.Logger.Error(fmt.Sprintf("failed to connect: %v", err))
+ http.Error(w, "failed connection", http.StatusInternalServerError)
+ return
}
+ defer session.Close()
+ transport.ServeHTTP(w, req)
+ return
+ }
- if stateless {
- // Stateless mode: close the session when the request exits.
- defer session.Close() // close the fake session after handling the request
- } else {
- // Otherwise, save the transport so that it can be reused
-
- // Clean up the session when it times out.
- //
- // Note that the timer here may fire multiple times, but
- // sessInfo.session.Close is idempotent.
- if h.opts.SessionTimeout > 0 {
- sessInfo.timeout = h.opts.SessionTimeout
- sessInfo.timer = time.AfterFunc(sessInfo.timeout, func() {
- sessInfo.session.Close()
- })
- }
+ connectOpts := &ServerSessionOptions{
+ onClose: func() {
h.mu.Lock()
- h.sessions[transport.SessionID] = sessInfo
- h.mu.Unlock()
- defer func() {
- // If initialization failed, clean up the session (#578).
- if session.InitializeParams() == nil {
- // Initialization failed.
- session.Close()
+ defer h.mu.Unlock()
+ if info, ok := h.sessions[transport.SessionID]; ok {
+ info.stopTimer()
+ delete(h.sessions, transport.SessionID)
+ if h.onTransportDeletion != nil {
+ h.onTransportDeletion(transport.SessionID)
}
- }()
- }
+ }
+ },
}
- if req.Method == http.MethodPost {
- sessInfo.startPOST()
- defer sessInfo.endPOST()
+ // Pass req.Context() here, to allow middleware to add context values.
+ // The context is detached in the jsonrpc2 library when handling the
+ // long-running stream.
+ session, err := connectStreamable(req.Context(), server, transport, connectOpts)
+ if err != nil {
+ h.opts.Logger.Error(fmt.Sprintf("failed to connect: %v", err))
+ http.Error(w, "failed connection", http.StatusInternalServerError)
+ return
}
+ // Capture the user ID from the token info to enable session hijacking
+ // prevention on subsequent requests.
+ var userID string
+ if tokenInfo := auth.TokenInfoFromContext(req.Context()); tokenInfo != nil {
+ userID = tokenInfo.UserID
+ }
+ sessInfo := &sessionInfo{
+ session: session,
+ transport: transport,
+ userID: userID,
+ }
+
+ if h.opts.SessionTimeout > 0 {
+ sessInfo.timeout = h.opts.SessionTimeout
+ sessInfo.timer = time.AfterFunc(sessInfo.timeout, func() {
+ sessInfo.session.Close()
+ })
+ }
+ h.mu.Lock()
+ h.sessions[transport.SessionID] = sessInfo
+ h.mu.Unlock()
+ defer func() {
+ // If initialization failed, clean up the session (#578).
+ if session.InitializeParams() == nil {
+ session.Close()
+ }
+ }()
+ sessInfo.startPOST()
+ defer sessInfo.endPOST()
sessInfo.transport.ServeHTTP(w, req)
}
@@ -634,6 +828,10 @@ type StreamableServerTransport struct {
// to write their own streamable HTTP handler.
logger *slog.Logger
+ // shouldPropagateCancellation is forwarded to the underlying
+ // [streamableServerConn]. See its docstring.
+ shouldPropagateCancellation bool
+
// connection is non-nil if and only if the transport has been connected.
connection *streamableServerConn
}
@@ -644,15 +842,16 @@ func (t *StreamableServerTransport) Connect(ctx context.Context) (Connection, er
return nil, fmt.Errorf("transport already connected")
}
t.connection = &streamableServerConn{
- sessionID: t.SessionID,
- stateless: t.Stateless,
- eventStore: t.EventStore,
- jsonResponse: t.jsonResponse,
- logger: ensureLogger(t.logger), // see #556: must be non-nil
- incoming: make(chan jsonrpc.Message, 10),
- done: make(chan struct{}),
- streams: make(map[string]*stream),
- requestStreams: make(map[jsonrpc.ID]string),
+ sessionID: t.SessionID,
+ stateless: t.Stateless,
+ eventStore: t.EventStore,
+ jsonResponse: t.jsonResponse,
+ logger: ensureLogger(t.logger), // see #556: must be non-nil
+ shouldPropagateCancellation: t.shouldPropagateCancellation,
+ incoming: make(chan jsonrpc.Message, 10),
+ done: make(chan struct{}),
+ streams: make(map[string]*stream),
+ requestStreams: make(map[jsonrpc.ID]string),
}
// Stream 0 corresponds to the standalone SSE stream.
//
@@ -666,14 +865,34 @@ func (t *StreamableServerTransport) Connect(ctx context.Context) (Connection, er
return t.connection, nil
}
+// The streamable HTTP transport supports every legacy SDK protocol version,
+// but the SEP-2575 >= 2026-07-28 protocol is only supported when the
+// transport is configured as stateless.
+func (t *StreamableServerTransport) SupportsProtocolVersion(version string) bool {
+ if version >= protocolVersion20260728 {
+ return t.Stateless && slices.Contains(supportedProtocolVersions, version)
+ }
+ return slices.Contains(supportedProtocolVersions, version)
+}
+
type streamableServerConn struct {
sessionID string
stateless bool
jsonResponse bool
eventStore EventStore
+ // shouldPropagateCancellation is true when the underlying HTTP request's
+ // lifetime IS the connection's cancellation signal (e.g., a stateless
+ // POST that owns a long-lived subscriptions/listen stream). It is read
+ // by the [cancellationPropagator] interface so the jsonrpc2 layer wires
+ // handler contexts to observe the carrier's cancellation.
+ shouldPropagateCancellation bool
+
logger *slog.Logger
+ server *Server
+ toolLookup func(name string) (*serverTool, bool)
+
incoming chan jsonrpc.Message // messages from the client to the server
mu sync.Mutex // guards all fields below
@@ -707,6 +926,15 @@ func (c *streamableServerConn) SessionID() string {
return c.sessionID
}
+// propagateCancellation implements [cancellationPropagator]. It returns true
+// when this connection is bound to a single HTTP request whose lifetime
+// should drive request-handler cancellation — for example, a stateless POST
+// carrying a long-lived subscriptions/listen stream that must unwind when
+// the client TCP-disconnects.
+func (c *streamableServerConn) propagateCancellation() bool {
+ return c.shouldPropagateCancellation
+}
+
// A stream is a single logical stream of SSE events within a server session.
// A stream begins with a client request, or with a client GET that has
// no Last-Event-ID header.
@@ -735,6 +963,10 @@ type stream struct {
// Note: if we remove support for batching, this could just be a bool.
pendingJSONMessages []json.RawMessage
+ // isBatch reports whether the request that opened the stream was a JSON-RPC
+ // batch. Batch responses must remain arrays even when they contain one item.
+ isBatch bool
+
// w is the HTTP response writer for this stream. A non-nil w indicates
// that the stream is claimed by an HTTP request (the hanging POST or GET);
// it is set to nil when the request completes.
@@ -761,6 +993,12 @@ type stream struct {
// the spec and earlier there was a concept of batching, in which POST
// payloads could hold multiple requests or responses.
requests map[jsonrpc.ID]struct{}
+
+ // isListen reports whether this stream was opened by a
+ // subscriptions/listen request. Listen streams are always SSE, live for
+ // the duration of the subscription, and act as the target for
+ // out-of-band notifications routed through this connection.
+ isListen bool
}
// close sends a 'close' event to the client (if protocolVersion >= 2025-11-25
@@ -796,6 +1034,36 @@ func (s *stream) release() {
s.done = nil // may already be nil, if the stream is done or closed
}
+// extractErrorStatus reports the HTTP status to send when the given
+// outgoing message is a JSON-RPC error response under the SEP-2575 protocol
+// (>= 2026-07-28).
+//
+// Per SEP-2575:
+// - MethodNotFound (-32601) MUST return HTTP 404.
+// - InvalidParams (-32602), UnsupportedProtocolVersion (-32022) and
+// CodeMissingRequiredClientCapabilities (-32021) MUST
+// return HTTP 400.
+func extractErrorStatus(ctx context.Context, msg jsonrpc.Message) int {
+ if protocolVersionFromContext(ctx) < protocolVersion20260728 {
+ return 0
+ }
+ resp, ok := msg.(*jsonrpc.Response)
+ if !ok || resp.Error == nil {
+ return 0
+ }
+ var jerr *jsonrpc.Error
+ if !errors.As(resp.Error, &jerr) {
+ return 0
+ }
+ switch jerr.Code {
+ case jsonrpc.CodeMethodNotFound:
+ return http.StatusNotFound
+ case jsonrpc.CodeInvalidParams, CodeUnsupportedProtocolVersion, CodeMissingRequiredClientCapabilities:
+ return http.StatusBadRequest
+ }
+ return 0
+}
+
// deliverLocked writes data to the stream (for SSE) or stores it in
// pendingJSONMessages (for JSON mode). The eventID is used for SSE event ID;
// pass "" to omit.
@@ -803,11 +1071,16 @@ func (s *stream) release() {
// If responseTo is valid, it is removed from the requests map. When all
// requests have been responded to, the done channel is closed and set to nil.
//
+// If overrideStatus is non-zero, data is treated as a SEP-2575 protocol-level
+// error response (>= 2026-07-28): it is written as a single raw JSON-RPC
+// response body with Content-Type: application/json and HTTP status
+// overrideStatus.
+//
// Returns true if the stream is now done (all requests have been responded to).
// The done value is always accurate, even if an error is returned.
//
// s.mu must be held when calling this method.
-func (s *stream) deliverLocked(data []byte, eventID string, responseTo jsonrpc.ID) (done bool, err error) {
+func (s *stream) deliverLocked(data []byte, eventID string, responseTo jsonrpc.ID, overrideStatus int) (done bool, err error) {
// First, record the response. We must do this *before* returning an error
// below, as even if the stream is disconnected we want to update our
// accounting.
@@ -822,6 +1095,17 @@ func (s *stream) deliverLocked(data []byte, eventID string, responseTo jsonrpc.I
if done {
defer func() { close(s.done); s.done = nil }()
}
+ // SEP-2575 protocol-level error override: write the error as a raw
+ // JSON-RPC response with the spec-mandated HTTP status, bypassing any
+ // SSE framing.
+ if overrideStatus != 0 {
+ s.w.Header().Set("Content-Type", "application/json")
+ s.w.WriteHeader(overrideStatus)
+ if _, err := s.w.Write(data); err != nil {
+ return done, err
+ }
+ return done, nil
+ }
// Try to write to the response.
//
// If we get here, the request is still hanging (because s.done != nil
@@ -833,7 +1117,7 @@ func (s *stream) deliverLocked(data []byte, eventID string, responseTo jsonrpc.I
if done {
// Flush all pending messages as JSON response.
var toWrite []byte
- if len(s.pendingJSONMessages) == 1 {
+ if len(s.pendingJSONMessages) == 1 && !s.isBatch {
toWrite = s.pendingJSONMessages[0]
} else {
toWrite, err = json.Marshal(s.pendingJSONMessages)
@@ -867,7 +1151,7 @@ func (s *stream) doneLocked() bool {
}
func (c *streamableServerConn) newStream(ctx context.Context, requests map[jsonrpc.ID]struct{}, id string) (*stream, error) {
- if c.eventStore != nil {
+ if c.eventStore != nil && protocolVersionFromContext(ctx) < protocolVersion20260728 {
if err := c.eventStore.Open(ctx, c.sessionID, id); err != nil {
return nil, err
}
@@ -903,6 +1187,18 @@ func (c *streamableServerConn) newStream(ctx context.Context, requests map[jsonr
// ID, we avoid having to make this API decision.
type idContextKey struct{}
+// protocolVersionContextKey stores the protocol version extracted from the
+// MCP-Protocol-Version HTTP header for use by lower layers.
+type protocolVersionContextKey struct{}
+
+// protocolVersionFromContext returns the protocol version from the context, or
+// the empty string if not set. An empty string means the version is unknown
+// (e.g. the header was absent).
+func protocolVersionFromContext(ctx context.Context) string {
+ v, _ := ctx.Value(protocolVersionContextKey{}).(string)
+ return v
+}
+
// ServeHTTP handles a single HTTP request for the session.
func (t *StreamableServerTransport) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if t.connection == nil {
@@ -948,9 +1244,7 @@ func (c *streamableServerConn) serveGET(w http.ResponseWriter, req *http.Request
ctx := req.Context()
- // Read the protocol version from the header. For GET requests, this should
- // always be present since GET only happens after initialization.
- protocolVersion := req.Header.Get(protocolVersionHeader)
+ protocolVersion := protocolVersionFromContext(ctx)
if protocolVersion == "" {
protocolVersion = protocolVersion20250326
}
@@ -1066,7 +1360,23 @@ func (c *streamableServerConn) acquireStream(ctx context.Context, w http.Respons
if s.id == "" {
// Issue #410: the standalone SSE stream is likely not to receive messages
// for a long time. Ensure that headers are flushed.
+ //
+ // On HTTP/2, headers and body travel as separate frames (HEADERS and
+ // DATA). Reverse proxies (e.g. Envoy, Caddy, net/http/httputil)
+ // commonly buffer the HEADERS frame until they have a DATA frame to
+ // coalesce it with — there is no HTTP/2 equivalent of HTTP/1.1's
+ // Transfer-Encoding: chunked signal that says "this is streaming, send
+ // headers now". Calling Flush() alone is not sufficient: it pushes
+ // the kernel buffer to the proxy, but the proxy still holds the
+ // HEADERS frame.
+ //
+ // Write an SSE comment (lines starting with ":" are ignored by
+ // clients per RFC) so a DATA frame is produced, which forces the
+ // proxy to forward both frames. See:
+ // https://github.com/golang/go/issues/31125
+ // https://github.com/caddyserver/caddy/issues/4247
w.WriteHeader(http.StatusOK)
+ fmt.Fprint(w, ": ok\n\n")
rc := http.NewResponseController(w)
// Ignore returned error as flushing is best-effort.
_ = rc.Flush()
@@ -1111,6 +1421,11 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
// Read incoming messages.
body, err := io.ReadAll(req.Body)
if err != nil {
+ var mbe *http.MaxBytesError
+ if errors.As(err, &mbe) {
+ http.Error(w, fmt.Sprintf("request body exceeds %d bytes", mbe.Limit), http.StatusRequestEntityTooLarge)
+ return
+ }
http.Error(w, "failed to read body", http.StatusBadRequest)
return
}
@@ -1127,7 +1442,7 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
return
}
- protocolVersion := req.Header.Get(protocolVersionHeader)
+ protocolVersion := protocolVersionFromContext(req.Context())
if protocolVersion == "" {
protocolVersion = protocolVersion20250326
}
@@ -1147,13 +1462,29 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
calls := make(map[jsonrpc.ID]struct{})
tokenInfo := auth.TokenInfoFromContext(req.Context())
isInitialize := false
+ isSubscriptionsListen := false
var initializeProtocolVersion string
for _, msg := range incoming {
if jreq, ok := msg.(*jsonrpc.Request); ok {
// Preemptively check that this is a valid request, so that we can fail
// the HTTP request. If we didn't do this, a request with a bad method or
// missing ID could be silently swallowed.
- if _, err := checkRequest(jreq, serverMethodInfos); err != nil {
+ // Use the server's receiving method infos (which include any custom
+ // methods registered via AddReceivingCustomMethod) when available;
+ // fall back to the standard methods otherwise, e.g. in tests that
+ // exercise streamableServerConn directly without a server.
+ methodInfos := serverMethodInfos
+ if c.server != nil {
+ methodInfos = c.server.receivingMethodInfos()
+ }
+ if _, err := checkRequest(jreq, methodInfos); err != nil {
+ if protocolVersion >= protocolVersion20260728 && errors.Is(err, jsonrpc2.ErrNotHandled) && jreq.IsCall() {
+ writeJSONRPCError(w, http.StatusNotFound, jreq.ID, &jsonrpc.Error{
+ Code: jsonrpc.CodeMethodNotFound,
+ Message: err.Error(),
+ })
+ return
+ }
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
@@ -1165,6 +1496,91 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
initializeProtocolVersion = params.ProtocolVersion
}
}
+ if jreq.Method == methodSubscriptionsListen {
+ isSubscriptionsListen = true
+ }
+ // SEP-2575: requests carrying `_meta.protocolVersion` require the
+ // Mcp-Protocol-Version HTTP header to be present and to match the
+ // per-request `_meta.protocolVersion` value.
+ // The new (>= 2026-07-28) protocol is supported on the HTTP transport
+ // only when [StreamableHTTPOptions.Stateless] is true.
+ //
+ // The `_meta` triple is defined for calls only, notifications are
+ // excluded.
+ //
+ // TODO: this validation can be moved within validateMcpHeaders.
+ var metaVersion string
+ if meta := extractRequestMeta(jreq.Params); meta != nil {
+ metaVersion, _ = meta[MetaKeyProtocolVersion].(string)
+ }
+ if (jreq.IsCall() && protocolVersion >= protocolVersion20260728) || metaVersion != "" {
+ // Extract again the protocol version from the context to see what the client
+ // is advertising in the Mcp-Protocol-Version HTTP header.
+ headerVersion := protocolVersionFromContext(req.Context())
+ // server/discover is exempt from the stateful
+ // rejection as it should learn about the supported protocols from the
+ // DiscoverResult response.
+ if !c.stateless && jreq.Method != methodDiscover {
+ if plaintextstatefulrejection == "1" {
+ http.Error(w, fmt.Sprintf(
+ "Bad Request: protocol version %q is only supported on stateless HTTP servers (set StreamableHTTPOptions.Stateless = true)",
+ protocolVersion),
+ http.StatusBadRequest)
+ return
+ }
+ // Advertise only the legacy versions this stateful server accepts
+ // (i.e. exclude 2026-07-28, since that's what the request asked for
+ // and what we're rejecting).
+ advertised := supportedProtocolVersions
+ if c.server != nil {
+ advertised = c.server.protocolVersions
+ }
+ legacyVersions := slices.DeleteFunc(slices.Clone(advertised), func(v string) bool {
+ return v >= protocolVersion20260728
+ })
+ data, _ := json.Marshal(UnsupportedProtocolVersionData{
+ Supported: legacyVersions,
+ Requested: protocolVersion,
+ })
+ c.logger.Warn(fmt.Sprintf(
+ "rejecting request with protocol version %q: this server is stateful; set StreamableHTTPOptions.Stateless = true to accept it",
+ protocolVersion))
+ writeJSONRPCError(w, http.StatusBadRequest, jreq.ID, &jsonrpc.Error{
+ Code: CodeUnsupportedProtocolVersion,
+ Message: fmt.Sprintf("protocol version %q is not supported by this server", protocolVersion),
+ Data: data,
+ })
+ return
+ }
+ if headerVersion == "" {
+ writeJSONRPCError(w, http.StatusBadRequest, jreq.ID, &jsonrpc.Error{
+ Code: CodeHeaderMismatch,
+ Message: fmt.Sprintf(
+ "%s header is required for requests carrying %q",
+ protocolVersionHeader, MetaKeyProtocolVersion),
+ })
+ return
+ }
+ if metaVersion == "" {
+ writeJSONRPCError(w, http.StatusBadRequest, jreq.ID, &jsonrpc.Error{
+ Code: jsonrpc.CodeInvalidParams,
+ Message: fmt.Sprintf(
+ "missing or invalid _meta field %q",
+ MetaKeyProtocolVersion),
+ })
+ return
+ }
+ if headerVersion != metaVersion {
+ writeJSONRPCError(w, http.StatusBadRequest, jreq.ID, &jsonrpc.Error{
+ Code: CodeHeaderMismatch,
+ Message: fmt.Sprintf(
+ "%s header %q does not match request %s %q",
+ protocolVersionHeader, headerVersion,
+ MetaKeyProtocolVersion, metaVersion),
+ })
+ return
+ }
+ }
// Include metadata for all requests (including notifications).
jreq.Extra = &RequestExtra{
TokenInfo: tokenInfo,
@@ -1175,6 +1591,12 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
// See the doc for CloseSSEStream: allow the request handler to
// explicitly close the ongoing stream.
jreq.Extra.(*RequestExtra).CloseSSEStream = func(args CloseSSEStreamArgs) {
+ // This mechanism was designed to trigger client reconnection with
+ // Last-Event-ID for server-initiated disconnect scenarios. It is
+ // deprecated in protocol version 2026-07-28.
+ if protocolVersion >= protocolVersion20260728 {
+ return
+ }
c.mu.Lock()
streamID, ok := c.requestStreams[jreq.ID]
var stream *stream
@@ -1191,9 +1613,9 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
}
}
- // Validate MCP standard headers (Mcp-Method, Mcp-Name)
+ // Validate MCP standard headers (Mcp-Method, Mcp-Name, Mcp-Param-*)
if !isBatch && len(incoming) == 1 {
- if err := validateMcpHeaders(req.Header, incoming[0]); err != nil {
+ if err := validateMcpHeaders(req.Header, incoming[0], c.toolLookup); err != nil {
resp := &jsonrpc.Response{
Error: jsonrpc2.NewError(CodeHeaderMismatch, err.Error()),
}
@@ -1250,14 +1672,23 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
http.Error(w, fmt.Sprintf("storing stream: %v", err), http.StatusInternalServerError)
return
}
+ stream.isListen = isSubscriptionsListen
+ stream.isBatch = isBatch
+
+ // subscriptions/listen is inherently a long-lived SSE endpoint (SEP-2575):
+ // it has no synchronous result, the response stream stays open until the
+ // client cancels, and the server pushes notifications on it as they occur.
+ // Force SSE mode (bypassing JSONResponse) so the buffered application/json
+ // path doesn't deadlock waiting for a completion that won't come.
+ useSSE := !c.jsonResponse || isSubscriptionsListen
// Set response headers. Accept was checked in [StreamableHTTPHandler].
w.Header().Set("Cache-Control", "no-cache, no-transform")
- if c.jsonResponse {
- w.Header().Set("Content-Type", "application/json")
- } else {
+ if useSSE {
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Connection", "keep-alive")
+ } else {
+ w.Header().Set("Content-Type", "application/json")
}
if c.sessionID != "" && isInitialize {
w.Header().Set(sessionIDHeader, c.sessionID)
@@ -1268,14 +1699,41 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
done := make(chan struct{})
stream.done = done
stream.protocolVersion = effectiveVersion
- if c.jsonResponse {
+
+ // Reject any call whose ID is already in flight on this session,
+ // atomically and without partial registration.
+ c.mu.Lock()
+ for reqID := range calls {
+ if _, ok := c.requestStreams[reqID]; ok {
+ c.mu.Unlock()
+ writeJSONRPCError(w, http.StatusBadRequest, reqID, &jsonrpc.Error{
+ Code: jsonrpc.CodeInvalidRequest,
+ Message: fmt.Sprintf("duplicate in-flight request ID %v", reqID.Raw()),
+ })
+ return
+ }
+ }
+ c.streams[stream.id] = stream
+ for reqID := range calls {
+ c.requestStreams[reqID] = stream.id
+ }
+ c.mu.Unlock()
+
+ // TODO(rfindley): if we have no event store, we should really cancel all
+ // remaining requests here, since the client will never get the results.
+ defer stream.release()
+
+ if !useSSE {
// JSON mode: collect messages in pendingJSONMessages until done.
// Set pendingJSONMessages to a non-nil value to signal that this is an
// application/json stream.
stream.pendingJSONMessages = []json.RawMessage{}
} else {
// SSE mode: write a priming event if supported.
- if c.eventStore != nil && effectiveVersion >= protocolVersion20251125 {
+ //
+ // SEP-2575 removes Last-Event-ID-based resumable streams for protocol
+ // version >= 2026-07-28.
+ if c.eventStore != nil && effectiveVersion >= protocolVersion20251125 && effectiveVersion < protocolVersion20260728 {
// Write a priming event, as defined by [§2.1.6] of the spec.
//
// [§2.1.6]: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server
@@ -1293,20 +1751,6 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
}
}
- // TODO(rfindley): if we have no event store, we should really cancel all
- // remaining requests here, since the client will never get the results.
- defer stream.release()
-
- // The stream is now set up to deliver messages.
- //
- // Register it before publishing incoming messages.
- c.mu.Lock()
- c.streams[stream.id] = stream
- for reqID := range calls {
- c.requestStreams[reqID] = stream.id
- }
- c.mu.Unlock()
-
// Publish incoming messages.
for _, msg := range incoming {
select {
@@ -1419,7 +1863,18 @@ func (c *streamableServerConn) Write(ctx context.Context, msg jsonrpc.Message) e
s = c.streams[streamID]
}
} else {
- s = c.streams[""] // standalone SSE stream
+ // In stateless mode there will always be only one stream per connection.
+ // If that stream was open to listen for subscription notifications,
+ // automatically select as the one to write the notification to.
+ for _, stream := range c.streams {
+ if stream.isListen {
+ s = stream
+ break
+ }
+ }
+ if s == nil {
+ s = c.streams[""] // standalone SSE stream
+ }
}
if responseTo.IsValid() {
// Once we've responded to a request, disallow related messages by removing
@@ -1449,7 +1904,8 @@ func (c *streamableServerConn) Write(ctx context.Context, msg jsonrpc.Message) e
// pushing down into the delivery layer.
delivered := false
var errs []error
- if c.eventStore != nil {
+ protocolVersion := protocolVersionFromContext(ctx)
+ if c.eventStore != nil && protocolVersion < protocolVersion20260728 {
if err := c.eventStore.Append(ctx, c.sessionID, s.id, data); err != nil {
errs = append(errs, err)
} else {
@@ -1460,11 +1916,16 @@ func (c *streamableServerConn) Write(ctx context.Context, msg jsonrpc.Message) e
// Compute eventID for SSE streams with event store.
// Use s.lastIdx + 1 because deliverLocked increments before writing.
var eventID string
- if c.eventStore != nil {
+ if c.eventStore != nil && protocolVersion < protocolVersion20260728 {
eventID = formatEventID(s.id, s.lastIdx+1)
}
- done, err := s.deliverLocked(data, eventID, responseTo)
+ // SEP-2575: map protocol-level JSON-RPC error codes to HTTP status codes
+ // on the new protocol (>= 2026-07-28). When non-zero, deliverLocked will
+ // write the body as raw application/json with the override status.
+ overrideStatus := extractErrorStatus(ctx, msg)
+
+ done, err := s.deliverLocked(data, eventID, responseTo, overrideStatus)
if err != nil {
errs = append(errs, err)
} else {
@@ -1532,6 +1993,11 @@ type StreamableClientTransport struct {
// OAuthHandler is an optional field that, if provided, will be used to authorize the requests.
OAuthHandler auth.OAuthHandler
+ // MaxEventSize bounds the number of bytes buffered while reading a single
+ // server-sent event. A value of 0 selects [DefaultMaxEventSize], a negative
+ // value disables the cap.
+ MaxEventSize int
+
// TODO(rfindley): propose exporting these.
// If strict is set, the transport is in 'strict mode', where any violation
// of the MCP spec causes a failure.
@@ -1550,6 +2016,11 @@ const (
reconnectGrowFactor = 1.5
// reconnectMaxDelay caps the backoff delay, preventing it from growing indefinitely.
reconnectMaxDelay = 30 * time.Second
+ // closeDeleteTimeout bounds the session-termination DELETE sent by Close.
+ // That request is best-effort: a peer that accepts the connection but never
+ // answers must not be able to hold teardown open until the TCP timeout.
+ // See issue #1183.
+ closeDeleteTimeout = 5 * time.Second
)
var (
@@ -1566,11 +2037,13 @@ func init() {
// Connect implements the [Transport] interface.
//
// The resulting [Connection] writes messages via POST requests to the
-// transport URL with the Mcp-Session-Id header set, and reads messages from
-// hanging requests.
+// transport URL, and reads messages from hanging requests. If the server
+// provides a session ID via the Mcp-Session-Id response header, subsequent
+// requests include it; sessionless servers that omit the header are fully
+// supported.
//
-// When closed, the connection issues a DELETE request to terminate the logical
-// session.
+// When closed, the connection issues a DELETE request to terminate the
+// session, unless no session was established.
func (t *StreamableClientTransport) Connect(ctx context.Context) (Connection, error) {
client := t.HTTPClient
if client == nil {
@@ -1612,6 +2085,7 @@ func (t *StreamableClientTransport) Connect(ctx context.Context) (Connection, er
failed: make(chan struct{}),
disableStandaloneSSE: t.DisableStandaloneSSE,
oauthHandler: t.OAuthHandler,
+ maxEventSize: t.MaxEventSize,
}
return conn, nil
}
@@ -1633,6 +2107,10 @@ type streamableClientConn struct {
// oauthHandler is the OAuth handler for the connection.
oauthHandler auth.OAuthHandler // from [StreamableClientTransport.OAuthHandler]
+ // maxEventSize bounds the number of bytes buffered while reading a single
+ // server-sent event. Resolved from [StreamableClientTransport.MaxEventSize].
+ maxEventSize int
+
// Guard calls to Close, as it may be called multiple times.
closeOnce sync.Once
closeErr error
@@ -1662,6 +2140,13 @@ func (c *streamableClientConn) sessionUpdated(state clientSessionState) {
c.initializedResult = state.InitializeResult
c.mu.Unlock()
+ // Under SEP-2575 (protocol version >= 2026-07-28) the standalone HTTP GET
+ // SSE stream is removed.
+ if state.InitializeResult == nil ||
+ state.InitializeResult.ProtocolVersion >= protocolVersion20260728 {
+ return
+ }
+
// Start the standalone SSE stream as soon as we have the initialized
// result, if continuous listening is enabled.
//
@@ -1721,7 +2206,7 @@ func (c *streamableClientConn) connectStandaloneSSE() {
return
}
summary := "standalone SSE stream"
- if err := c.checkResponse(summary, resp); err != nil {
+ if err := c.checkResponse(c.ctx, summary, resp); err != nil {
c.fail(err)
return
}
@@ -1784,12 +2269,14 @@ func (c *streamableClientConn) Write(ctx context.Context, msg jsonrpc.Message) e
}
var requestSummary string
+ var requestMethod string
var forCall *jsonrpc.Request
switch msg := msg.(type) {
case *jsonrpc.Request:
requestSummary = fmt.Sprintf("sending %q", msg.Method)
if msg.IsCall() {
forCall = msg
+ requestMethod = msg.Method
}
case *jsonrpc.Response:
requestSummary = fmt.Sprintf("sending jsonrpc response #%d", msg.ID)
@@ -1809,7 +2296,8 @@ func (c *streamableClientConn) Write(ctx context.Context, msg jsonrpc.Message) e
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json, text/event-stream")
- if err := c.setMCPHeaders(req); err != nil {
+
+ if err := c.setMCPHeaders(req, msg); err != nil {
// Failure to set headers means that the request was not sent.
// Wrap with ErrRejected so the jsonrpc2 connection doesn't set writeErr
// and permanently break the connection.
@@ -1817,7 +2305,7 @@ func (c *streamableClientConn) Write(ctx context.Context, msg jsonrpc.Message) e
}
// Keep this after the setMCPHeaders call to ensure that the
// protocol version header is set.
- setStandardHeaders(req.Header, msg)
+ setStandardHeaders(ctx, req.Header, msg)
resp, err := c.client.Do(req)
if err != nil {
// Any error from client.Do means the request didn't reach the server.
@@ -1863,10 +2351,19 @@ func (c *streamableClientConn) Write(ctx context.Context, msg jsonrpc.Message) e
}
}
- if err := c.checkResponse(requestSummary, resp); err != nil {
- // Only fail the connection for non-transient errors.
- // Transient errors (wrapped with ErrRejected) should not break the connection.
- if !errors.Is(err, jsonrpc2.ErrRejected) {
+ if err := c.checkResponse(ctx, requestSummary, resp); err != nil {
+ if (requestMethod == methodDiscover || requestMethod == methodSubscriptionsListen) && !errors.Is(err, jsonrpc2.ErrRejected) {
+ // Wrap the discover or subscriptions/listen failure with ErrRejected so
+ // the jsonrpc2 layer doesn't set writeErr, which would break the connection
+ // (preventing the legacy initialize fallback from succeeding, or breaking
+ // subsequent RPCs if subscriptions/listen fails). This covers the case
+ // where a server rejects these requests with a non-JSON-RPC body (e.g.
+ // plain text 404 or 400), which checkResponse cannot classify as a
+ // per-call rejection on its own.
+ err = fmt.Errorf("%w: %w", err, jsonrpc2.ErrRejected)
+ } else if !errors.Is(err, jsonrpc2.ErrRejected) {
+ // Only fail the connection for non-transient errors.
+ // Transient errors (wrapped with ErrRejected) should not break the connection.
c.fail(err)
}
return err
@@ -1928,7 +2425,7 @@ func (c *streamableClientConn) Write(ctx context.Context, msg jsonrpc.Message) e
return nil
}
-func (c *streamableClientConn) setMCPHeaders(req *http.Request) error {
+func (c *streamableClientConn) setMCPHeaders(req *http.Request, msg jsonrpc.Message) error {
c.mu.Lock()
defer c.mu.Unlock()
@@ -1940,15 +2437,30 @@ func (c *streamableClientConn) setMCPHeaders(req *http.Request) error {
if ts != nil {
token, err := ts.Token()
if err != nil {
- return err
- }
- if token != nil {
+ // If the error is an invalid_grant oauth2.RetrieveError it indicates
+ // that the token source doesn't have valid authorization for the token
+ // endpoint, per RFC 6749 section 5.2. For example, the refresh token
+ // may be expired or invalid.
+ //
+ // In that case, ignore the error, skip setting the Authorization
+ // header, and proceed with the request. Callers that support
+ // authorization flows get a 401/403 response and trigger the
+ // Authorize() flow to refresh their token.
+ var retrieveErr *oauth2.RetrieveError
+ if !errors.As(err, &retrieveErr) || retrieveErr.ErrorCode != "invalid_grant" {
+ return err
+ }
+ } else if token != nil {
req.Header.Set("Authorization", "Bearer "+token.AccessToken)
}
}
}
- if c.initializedResult != nil {
+ if pv := protocolVersionFromMessage(msg); pv != "" {
+ req.Header.Set(protocolVersionHeader, pv)
+ } else if c.initializedResult != nil {
req.Header.Set(protocolVersionHeader, c.initializedResult.ProtocolVersion)
+ } else if pv := protocolVersionFromContext(req.Context()); pv != "" {
+ req.Header.Set(protocolVersionHeader, pv)
}
if c.sessionID != "" {
req.Header.Set(sessionIDHeader, c.sessionID)
@@ -1957,6 +2469,23 @@ func (c *streamableClientConn) setMCPHeaders(req *http.Request) error {
return nil
}
+// protocolVersionFromMessage recovers the SEP-2575 `_meta.protocolVersion`
+// value from an outgoing JSON-RPC request, if present. It returns "" for
+// notifications, responses, requests without a `_meta.protocolVersion`, or a
+// nil msg.
+func protocolVersionFromMessage(msg jsonrpc.Message) string {
+ req, ok := msg.(*jsonrpc.Request)
+ if !ok || req == nil {
+ return ""
+ }
+ meta := extractRequestMeta(req.Params)
+ if meta == nil {
+ return ""
+ }
+ v, _ := meta[MetaKeyProtocolVersion].(string)
+ return v
+}
+
func (c *streamableClientConn) handleJSON(requestSummary string, resp *http.Response) {
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
@@ -2034,7 +2563,7 @@ func (c *streamableClientConn) handleSSE(ctx context.Context, requestSummary str
}
resp = newResp
- if err := c.checkResponse(requestSummary, resp); err != nil {
+ if err := c.checkResponse(ctx, requestSummary, resp); err != nil {
c.fail(err)
return
}
@@ -2045,24 +2574,35 @@ func (c *streamableClientConn) handleSSE(ctx context.Context, requestSummary str
// translates it into an error if the request was unsuccessful.
//
// The response body is close if a non-nil error is returned.
-func (c *streamableClientConn) checkResponse(requestSummary string, resp *http.Response) (err error) {
+func (c *streamableClientConn) checkResponse(ctx context.Context, requestSummary string, resp *http.Response) (err error) {
defer func() {
if err != nil {
resp.Body.Close()
}
}()
+ // Transient server errors (502, 503, 504, 429) should not break the connection.
+ // Wrap them with ErrRejected so the jsonrpc2 layer doesn't set writeErr.
+ if isTransientHTTPStatus(resp.StatusCode) {
+ return fmt.Errorf("%w: %s: %v", jsonrpc2.ErrRejected, requestSummary, http.StatusText(resp.StatusCode))
+ }
+ // By default, always try to decode the body and surface the underlying
+ // JSON-RPC error, wrapping it with ErrRejected to prevent the connection from closing.
+ // Setting MCPGODEBUG=noprotocolerrorbody=1 restores the previous behavior.
+ if noprotocolerrorbody != "1" && (resp.StatusCode < 200 || resp.StatusCode >= 300) {
+ body, _ := io.ReadAll(resp.Body)
+ msg, _ := jsonrpc.DecodeMessage(body)
+ if response, ok := msg.(*jsonrpc.Response); ok && response.Error != nil {
+ return fmt.Errorf("%s: %w: %w: %v", requestSummary, response.Error, jsonrpc2.ErrRejected, http.StatusText(resp.StatusCode))
+ }
+ }
// §2.5.3: "The server MAY terminate the session at any time, after
// which it MUST respond to requests containing that session ID with HTTP
// 404 Not Found."
- if resp.StatusCode == http.StatusNotFound {
+ // Only a stateful connection with a known session ID can experience ErrSessionMissing.
+ if sessionID := c.SessionID(); resp.StatusCode == http.StatusNotFound && sessionID != "" {
// Return an ErrSessionMissing to avoid sending a redundant DELETE when the
// session is already gone.
- return fmt.Errorf("%s: failed to connect (session ID: %v): %w", requestSummary, c.sessionID, ErrSessionMissing)
- }
- // Transient server errors (502, 503, 504, 429) should not break the connection.
- // Wrap them with ErrRejected so the jsonrpc2 layer doesn't set writeErr.
- if isTransientHTTPStatus(resp.StatusCode) {
- return fmt.Errorf("%w: %s: %v", jsonrpc2.ErrRejected, requestSummary, http.StatusText(resp.StatusCode))
+ return fmt.Errorf("%s: failed to connect (session ID: %v): %w", requestSummary, sessionID, ErrSessionMissing)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("%s: %v", requestSummary, http.StatusText(resp.StatusCode))
@@ -2080,7 +2620,7 @@ func (c *streamableClientConn) processStream(ctx context.Context, requestSummary
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}()
- for evt, err := range scanEvents(resp.Body) {
+ for evt, err := range scanEventsLimited(resp.Body, c.maxEventSize) {
if err != nil {
if ctx.Err() != nil {
return "", 0, true // don't reconnect: client cancelled
@@ -2207,7 +2747,7 @@ func (c *streamableClientConn) connectSSE(ctx context.Context, lastEventID strin
if err != nil {
return nil, err
}
- if err := c.setMCPHeaders(req); err != nil {
+ if err := c.setMCPHeaders(req, nil); err != nil {
return nil, err
}
if lastEventID != "" {
@@ -2235,15 +2775,22 @@ func (c *streamableClientConn) Close() error {
c.closeOnce.Do(func() {
if errors.Is(c.failure(), ErrSessionMissing) {
// If the session is missing, no need to delete it.
+ } else if c.SessionID() == "" {
+ // No session was established (e.g. the server is stateless),
+ // so there is nothing to delete.
} else {
- req, err := http.NewRequestWithContext(c.ctx, http.MethodDelete, c.url, nil)
+ reqCtx, stop := context.WithTimeout(c.ctx, closeDeleteTimeout)
+ defer stop()
+ req, err := http.NewRequestWithContext(reqCtx, http.MethodDelete, c.url, nil)
if err != nil {
c.closeErr = err
} else {
- if err := c.setMCPHeaders(req); err != nil {
+ if err := c.setMCPHeaders(req, nil); err != nil {
c.closeErr = err
- } else if _, err := c.client.Do(req); err != nil {
+ } else if resp, err := c.client.Do(req); err != nil {
c.closeErr = err
+ } else {
+ resp.Body.Close()
}
}
}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_client.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_client.go
index c2cc25b..74940b3 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_client.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_client.go
@@ -40,8 +40,12 @@ components:
# Sessions
-The client maintains a session with the server, identified by a session ID
-(Mcp-Session-Id header):
+The client optionally maintains a session with the server, identified by a
+session ID (Mcp-Session-Id header). Sessionless servers (those that never
+send Mcp-Session-Id) are fully supported; the client simply omits the
+header from subsequent requests and skips the DELETE on close.
+
+When a session is present:
- Session ID is received from the server after initialization
- Client includes the session ID in all subsequent requests
@@ -162,6 +166,7 @@ The client must handle two response formats from POST requests:
- DELETE: Terminate the session
- Used by [streamableClientConn.Close]
- Skipped if session is already known to be gone ([ErrSessionMissing])
+ or if no session was established (sessionless server)
# Error Handling
@@ -176,7 +181,7 @@ Errors are categorized and handled differently:
- 404 Not Found: Session terminated by server ([ErrSessionMissing])
- Message decode errors: Protocol violation
- Context cancellation: Client closed connection
- - Mismatched session IDs: Protocol error
+ - Mismatched session IDs: Protocol error (only relevant for servers that use sessions)
- See issue #683: our terminal errors are too strict.
Terminal errors are stored via [streamableClientConn.fail] and returned by
@@ -211,7 +216,7 @@ This header (set by [streamableClientConn.setMCPHeaders]):
State management:
- [streamableClientConn.incoming]: Buffered channel for received messages
- - [streamableClientConn.sessionID]: Server-assigned session identifier
+ - [streamableClientConn.sessionID]: Server-assigned session identifier (empty for sessionless servers)
- [streamableClientConn.initializedResult]: Cached for protocol version header
- [streamableClientConn.failed]: Channel closed on terminal error
- [streamableClientConn.done]: Channel closed on graceful shutdown
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_headers.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_headers.go
index ac9a412..7d06399 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_headers.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/streamable_headers.go
@@ -5,10 +5,16 @@
package mcp
import (
+ "context"
+ "encoding/base64"
"encoding/json"
"errors"
"fmt"
+ "log/slog"
+ "math"
"net/http"
+ "strconv"
+ "strings"
internaljson "github.com/modelcontextprotocol/go-sdk/internal/json"
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
@@ -20,7 +26,10 @@ const (
lastEventIDHeader = "Last-Event-ID"
methodHeader = "Mcp-Method"
nameHeader = "Mcp-Name"
- minVersionForStandardHeaders = protocolVersion20260630
+ paramHeaderPrefix = "Mcp-Param-"
+ minVersionForStandardHeaders = protocolVersion20260728
+ base64Prefix = "=?base64?"
+ base64Suffix = "?="
)
func extractName(method string, params json.RawMessage) (string, bool) {
@@ -45,9 +54,148 @@ func extractName(method string, params json.RawMessage) (string, bool) {
return "", false
}
+// headerSchemaProperty captures the fields needed for x-mcp-header processing.
+type headerSchemaProperty struct {
+ Type string `json:"type"`
+ XMCPHeader json.RawMessage `json:"x-mcp-header,omitempty"`
+ Properties map[string]headerSchemaProperty `json:"properties,omitempty"`
+}
+
+// unmarshalSchemaProperties normalizes any InputSchema type
+// (*jsonschema.Schema, map[string]any, or json.RawMessage) into a common
+// representation by marshaling to JSON and unmarshaling only the fields we need.
+func unmarshalSchemaProperties(schema any) map[string]headerSchemaProperty {
+ var s headerSchemaProperty
+ if err := remarshal(schema, &s); err != nil {
+ return nil
+ }
+ return s.Properties
+}
+
+// paramHeaderBinding maps a (possibly nested) input-schema property to the
+// HTTP header it carries.
+type paramHeaderBinding struct {
+ Path []string
+ Header string
+}
+
+// extractParamHeaderAnnotations returns the bindings for every property in
+// the tool's InputSchema that has an x-mcp-header annotation
+func extractParamHeaderAnnotations(tool *Tool) []paramHeaderBinding {
+ props := unmarshalSchemaProperties(tool.InputSchema)
+ if len(props) == 0 {
+ return nil
+ }
+ var result []paramHeaderBinding
+ result = collectParamHeaderAnnotations(props, nil, result)
+ if len(result) == 0 {
+ return nil
+ }
+ return result
+}
+
+// collectParamHeaderAnnotations walks the schema properties and records every
+// x-mcp-header annotation it finds, keyed by the property-name path.
+func collectParamHeaderAnnotations(props map[string]headerSchemaProperty, prefix []string, out []paramHeaderBinding) []paramHeaderBinding {
+ for propName, prop := range props {
+ path := make([]string, len(prefix)+1)
+ copy(path, prefix)
+ path[len(prefix)] = propName
+
+ var headerName string
+ if err := json.Unmarshal(prop.XMCPHeader, &headerName); err == nil && headerName != "" {
+ out = append(out, paramHeaderBinding{Path: path, Header: headerName})
+ }
+ if len(prop.Properties) > 0 {
+ out = collectParamHeaderAnnotations(prop.Properties, path, out)
+ }
+ }
+ return out
+}
+
+// lookupArgument navigates the arguments object using the given property-name
+// path and returns the raw JSON value at that location. It reports whether
+// the value was found.
+func lookupArgument(args map[string]json.RawMessage, path []string) (json.RawMessage, bool) {
+ if len(path) == 0 {
+ return nil, false
+ }
+ cur, ok := args[path[0]]
+ if !ok {
+ return nil, false
+ }
+ for _, part := range path[1:] {
+ var obj map[string]json.RawMessage
+ if err := internaljson.Unmarshal(cur, &obj); err != nil {
+ return nil, false
+ }
+ cur, ok = obj[part]
+ if !ok {
+ return nil, false
+ }
+ }
+ return cur, true
+}
+
+// maxSafeInteger and minSafeInteger bound the integer values that can be
+// faithfully represented as IEEE-754 double-precision floats.
+const (
+ maxSafeInteger = 1<<53 - 1 // 2^53 - 1 = 9007199254740991
+ minSafeInteger = -(1<<53 - 1) // -(2^53 - 1) = -9007199254740991
+)
+
+// unmarshalPrimitive unmarshals a JSON value into the Go representation used
+// for x-mcp-header processing per SEP-2243:
+//
+// - JSON string -> string
+// - JSON boolean -> bool
+// - JSON integer (within the JavaScript safe-integer range) -> int64
+//
+// JSON numbers that are non-integers (have a fractional part, NaN, or ±Inf)
+// or integers outside the safe range are rejected because the `number` type
+// is not permitted for x-mcp-header parameters; only integer, string, boolean
+// are allowed.
+func unmarshalPrimitive(raw json.RawMessage) any {
+ var val any
+ if err := internaljson.Unmarshal(raw, &val); err != nil {
+ return nil
+ }
+ switch v := val.(type) {
+ case string, bool:
+ return v
+ case float64:
+ if math.IsNaN(v) || math.IsInf(v, 0) || v != math.Trunc(v) {
+ return nil
+ }
+ if v < minSafeInteger || v > maxSafeInteger {
+ return nil
+ }
+ return int64(v)
+ default:
+ return nil
+ }
+}
+
+// primitiveToString formats an x-mcp-header value (as produced by
+// [unmarshalPrimitive]) to its canonical header string representation per
+// SEP-2243. Returns false if value is not one of the permitted primitive
+// types (string, bool, int64).
+func primitiveToString(value any) (string, bool) {
+ switch v := value.(type) {
+ case string:
+ return v, true
+ case bool:
+ return fmt.Sprintf("%t", v), true
+ case int64:
+ return strconv.FormatInt(v, 10), true
+ default:
+ return "", false
+ }
+}
+
// setStandardHeaders populates standard MCP headers.
// It requires the protocol version header to be set.
-func setStandardHeaders(header http.Header, msg jsonrpc.Message) {
+func setStandardHeaders(ctx context.Context, header http.Header, msg jsonrpc.Message) {
if msg == nil {
return
}
@@ -61,10 +209,154 @@ func setStandardHeaders(header http.Header, msg jsonrpc.Message) {
if name, ok := extractName(msg.Method, msg.Params); ok {
header.Set(nameHeader, name)
}
+ if msg.Method == "tools/call" {
+ if tool, ok := ctx.Value(toolContextKey).(*Tool); ok && tool != nil {
+ for k, v := range generateParamHeaders(tool, msg.Params) {
+ header.Set(k, v)
+ }
+ }
+ }
+ }
+}
+
+// generateParamHeaders reads x-mcp-header annotations from the tool's InputSchema
+// and returns the Mcp-Param-{Name} headers to be set on the HTTP request.
+func generateParamHeaders(tool *Tool, params json.RawMessage) map[string]string {
+ paramHeaders := extractParamHeaderAnnotations(tool)
+ if len(paramHeaders) == 0 {
+ return nil
+ }
+
+ var raw struct {
+ Arguments map[string]json.RawMessage `json:"arguments"`
+ }
+ if err := internaljson.Unmarshal(params, &raw); err != nil || raw.Arguments == nil {
+ return nil
+ }
+
+ res := make(map[string]string)
+ for _, b := range paramHeaders {
+ argRaw, ok := lookupArgument(raw.Arguments, b.Path)
+ if !ok {
+ continue
+ }
+ if string(argRaw) == "null" {
+ continue
+ }
+ val := unmarshalPrimitive(argRaw)
+ if val == nil {
+ continue
+ }
+ encoded, ok := encodeHeaderValue(val)
+ if !ok {
+ continue
+ }
+ res[paramHeaderPrefix+b.Header] = encoded
+ }
+ return res
+}
+
+// filterValidTools returns only tools that have valid
+// x-mcp-header annotations. Invalid tools are logged and excluded.
+func filterValidTools(logger *slog.Logger, tools []*Tool) []*Tool {
+ logger = ensureLogger(logger)
+ result := make([]*Tool, 0, len(tools))
+ for _, tool := range tools {
+ // A nil tool (e.g. from a malformed "tools":[null] response) is
+ // invalid; exclude it instead of dereferencing it.
+ if tool == nil {
+ logger.Error("excluding nil tool from tools/list")
+ continue
+ }
+ if err := validateParamHeaderAnnotations(tool); err != nil {
+ logger.Error("excluding tool from tools/list", "tool", tool.Name, "error", err)
+ continue
+ }
+ result = append(result, tool)
+ }
+ return result
+}
+
+// validateParamHeaderAnnotations checks that a tool's x-mcp-header annotations
+// are valid. Annotations may appear on properties at any nesting
+// depth within the inputSchema and must be unique across all of them.
+func validateParamHeaderAnnotations(tool *Tool) error {
+ props := unmarshalSchemaProperties(tool.InputSchema)
+ if len(props) == 0 {
+ return nil
+ }
+ seen := make(map[string]bool)
+ return validateParamHeadersIn(props, "", seen)
+}
+
+func validateParamHeadersIn(props map[string]headerSchemaProperty, prefix string, seen map[string]bool) error {
+ for propName, prop := range props {
+ path := propName
+ if prefix != "" {
+ path = prefix + "." + propName
+ }
+ if prop.XMCPHeader != nil {
+ if prop.Type != "string" && prop.Type != "integer" && prop.Type != "boolean" {
+ return fmt.Errorf("property %q: x-mcp-header can only be applied to primitive types (integer, string, boolean), got %q", path, prop.Type)
+ }
+ var headerName string
+ if err := json.Unmarshal(prop.XMCPHeader, &headerName); err != nil || headerName == "" {
+ return fmt.Errorf("property %q: x-mcp-header must be a non-empty string", path)
+ }
+ if err := validateHeaderName(headerName); err != nil {
+ return fmt.Errorf("property %q: %w", path, err)
+ }
+ lower := strings.ToLower(headerName)
+ if seen[lower] {
+ return fmt.Errorf("property %q: duplicate x-mcp-header value %q (case-insensitive)", path, headerName)
+ }
+ seen[lower] = true
+ }
+ if len(prop.Properties) > 0 {
+ if err := validateParamHeadersIn(prop.Properties, path, seen); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// validateHeaderName checks that a header name matches the HTTP field-name
+// token syntax (1*tchar).
+func validateHeaderName(name string) error {
+ if name == "" {
+ return fmt.Errorf("x-mcp-header value must be a non-empty string")
+ }
+ for _, c := range name {
+ if !isTChar(c) {
+ return fmt.Errorf("x-mcp-header value %q contains invalid character %q", name, c)
+ }
+ }
+ return nil
+}
+
+// isTChar reports whether c is a valid HTTP token character (tchar)
+//
+// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+func isTChar(c rune) bool {
+ switch {
+ case c >= '0' && c <= '9':
+ return true
+ case c >= 'A' && c <= 'Z':
+ return true
+ case c >= 'a' && c <= 'z':
+ return true
+ }
+ switch c {
+ case '!', '#', '$', '%', '&', '\'', '*', '+', '-', '.',
+ '^', '_', '`', '|', '~':
+ return true
}
+ return false
}
-func validateMcpHeaders(header http.Header, msg jsonrpc.Message) error {
+func validateMcpHeaders(header http.Header, msg jsonrpc.Message, toolLookup func(string) (*serverTool, bool)) error {
protocolVersion := header.Get(protocolVersionHeader)
if protocolVersion == "" || protocolVersion < minVersionForStandardHeaders {
return nil
@@ -80,12 +372,14 @@ func validateMcpHeaders(header http.Header, msg jsonrpc.Message) error {
return fmt.Errorf("header mismatch: Mcp-Method header value '%s' does not match body value '%s'", methodInHeader, msg.Method)
}
+ var nameInBody string
if msg.Method == "tools/call" || msg.Method == "resources/read" || msg.Method == "prompts/get" {
nameInHeader := header.Get(nameHeader)
if nameInHeader == "" {
return fmt.Errorf("missing required Mcp-Name header for method %q", msg.Method)
}
- nameInBody, ok := extractName(msg.Method, msg.Params)
+ var ok bool
+ nameInBody, ok = extractName(msg.Method, msg.Params)
if !ok {
return fmt.Errorf("failed to extract name from parameters for method %q", msg.Method)
}
@@ -93,6 +387,149 @@ func validateMcpHeaders(header http.Header, msg jsonrpc.Message) error {
return fmt.Errorf("header mismatch: Mcp-Name header value '%s' does not match body value '%s'", nameInHeader, nameInBody)
}
}
+
+ if msg.Method == "tools/call" && toolLookup != nil {
+ if st, ok := toolLookup(nameInBody); ok && st != nil {
+ if err := validateParamHeaders(header, msg, st.tool); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func validateParamHeaders(header http.Header, msg *jsonrpc.Request, tool *Tool) error {
+ paramHeaders := extractParamHeaderAnnotations(tool)
+ if len(paramHeaders) == 0 {
+ return nil
+ }
+
+ var raw struct {
+ Arguments map[string]json.RawMessage `json:"arguments"`
+ }
+ if err := internaljson.Unmarshal(msg.Params, &raw); err != nil {
+ return nil
+ }
+
+ for _, b := range paramHeaders {
+ fullHeader := paramHeaderPrefix + b.Header
+ headerVal := header.Get(fullHeader)
+ argRaw, argExists := lookupArgument(raw.Arguments, b.Path)
+
+ if !argExists || string(argRaw) == "null" {
+ if headerVal != "" {
+ return fmt.Errorf("header mismatch: unexpected %s header for absent or null parameter %q", fullHeader, strings.Join(b.Path, "."))
+ }
+ continue
+ }
+
+ if headerVal == "" {
+ return fmt.Errorf("header mismatch: missing %s header for parameter %q", fullHeader, strings.Join(b.Path, "."))
+ }
+
+ decoded, ok := decodeHeaderValue(headerVal)
+ if !ok {
+ return fmt.Errorf("header mismatch: %s header contains invalid Base64 encoding", fullHeader)
+ }
+
+ bodyVal := unmarshalPrimitive(argRaw)
+ if bodyVal == nil {
+ return fmt.Errorf("header mismatch: %s header present but body parameter %q is not a primitive type", fullHeader, strings.Join(b.Path, "."))
+ }
+
+ if !primitiveEqual(decoded, bodyVal) {
+ return fmt.Errorf("header mismatch: %s header value '%s' does not match body value", fullHeader, headerVal)
+ }
}
return nil
}
+
+// primitiveEqual reports whether the (decoded) header string equals the
+// JSON-derived body value.
+func primitiveEqual(headerStr string, bodyVal any) bool {
+ if bodyInt, ok := bodyVal.(int64); ok {
+ headerNum, err := strconv.ParseFloat(headerStr, 64)
+ if err != nil {
+ return false
+ }
+ if math.IsNaN(headerNum) || math.IsInf(headerNum, 0) || headerNum != math.Trunc(headerNum) {
+ return false
+ }
+ if headerNum < minSafeInteger || headerNum > maxSafeInteger {
+ return false
+ }
+ return int64(headerNum) == bodyInt
+ }
+ expected, ok := primitiveToString(bodyVal)
+ if !ok {
+ return false
+ }
+ return headerStr == expected
+}
+
+// encodeHeaderValue converts a parameter value to an HTTP header-safe string
+// per the SEP-2243 encoding rules:
+// - string: used as-is if safe ASCII, otherwise Base64 encoded
+// - int64: decimal string representation
+// - bool: lowercase "true" or "false"
+//
+// Values that contain non-ASCII characters, control characters, or
+// leading/trailing whitespace are Base64-encoded with the =?base64?...?= wrapper.
+//
+// The second return value is false if the value is not a supported primitive type.
+func encodeHeaderValue(value any) (string, bool) {
+ s, ok := primitiveToString(value)
+ if !ok {
+ return "", false
+ }
+ if requiresBase64Encoding(s) {
+ return encodeBase64(s), true
+ }
+ return s, true
+}
+
+// decodeHeaderValue decodes a header value that may be Base64-encoded
+// with the =?base64?...?= wrapper.
+//
+// The second return value is false if the header value is not a valid Base64 encoded value.
+func decodeHeaderValue(headerValue string) (string, bool) {
+ if len(headerValue) == 0 {
+ return headerValue, true
+ }
+
+ if encoded, ok := strings.CutPrefix(headerValue, base64Prefix); ok {
+ if encoded, ok = strings.CutSuffix(encoded, base64Suffix); ok {
+ decoded, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return "", false
+ }
+ return string(decoded), true
+ }
+ }
+ return headerValue, true
+}
+
+func requiresBase64Encoding(s string) bool {
+ if len(s) == 0 {
+ return false
+ }
+ if s[0] == ' ' || s[0] == '\t' || s[len(s)-1] == ' ' || s[len(s)-1] == '\t' {
+ return true
+ }
+ for _, c := range s {
+ if c < 0x20 || c > 0x7E {
+ return true
+ }
+ }
+ // Per SEP-2243, plain-ASCII values that match the base64 sentinel pattern
+ // must also be base64-encoded to avoid ambiguity with already-encoded values.
+ if strings.HasPrefix(s, base64Prefix) && strings.HasSuffix(s, base64Suffix) {
+ return true
+ }
+ return false
+}
+
+func encodeBase64(s string) string {
+ return base64Prefix + base64.StdEncoding.EncodeToString([]byte(s)) + base64Suffix
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/tool.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/tool.go
index 3ecb59d..11ad100 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/tool.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/tool.go
@@ -43,7 +43,7 @@ type ToolHandler func(context.Context, *CallToolRequest) (*CallToolResult, error
// - If the Out type is not the empty interface [any], it provides the
// default output schema for the tool (which again may be overridden in
// [AddTool]).
-// - The Out value is used to populate result.StructuredOutput.
+// - The Out value is used to populate result.StructuredContent.
// - If [CallToolResult.Content] is unset, it is populated with the JSON
// content of the output.
// - An error result is treated as a tool error, rather than a protocol
@@ -65,8 +65,14 @@ type serverTool struct {
// applySchema validates whether data is valid JSON according to the provided
// schema, after applying schema defaults.
//
-// Returns the JSON value augmented with defaults.
-func applySchema(data json.RawMessage, resolved *jsonschema.Resolved) (json.RawMessage, error) {
+// If forOutput is false, the data is treated as tool input: the schema's root
+// type must be "object" and the value is unmarshaled into a map.
+//
+// If forOutput is true, the data is treated as tool output: the schema's root
+// may be of any type (object, array, primitive, composition).
+//
+// Returns the JSON value, augmented with defaults where applicable.
+func applySchema(data json.RawMessage, resolved *jsonschema.Resolved, forOutput bool) (json.RawMessage, error) {
// TODO: use reflection to create the struct type to unmarshal into.
// Separate validation from assignment.
@@ -75,33 +81,81 @@ func applySchema(data json.RawMessage, resolved *jsonschema.Resolved) (json.RawM
// This avoids inconsistent representation due to custom marshallers, such as
// time.Time (issue #449).
//
- // Additionally, unmarshalling into a map ensures that the resulting JSON is
+ // For input, unmarshalling into a map ensures that the resulting JSON is
// at least {}, even if data is empty. For example, arguments is technically
// an optional property of callToolParams, and we still want to apply the
// defaults in this case.
//
// TODO(rfindley): in which cases can resolved be nil?
- if resolved != nil {
+ if resolved == nil {
+ return data, nil
+ }
+
+ var unmarshaled any
+ if !forOutput {
v := make(map[string]any)
if len(data) > 0 {
if err := internaljson.Unmarshal(data, &v); err != nil {
return nil, fmt.Errorf("unmarshaling arguments: %w", err)
}
}
- if err := resolved.ApplyDefaults(&v); err != nil {
+ unmarshaled = v
+ } else {
+ if len(data) > 0 {
+ if err := internaljson.Unmarshal(data, &unmarshaled); err != nil {
+ return nil, fmt.Errorf("unmarshaling output: %w", err)
+ }
+ }
+ }
+
+ // Apply defaults only when the value is a map: jsonschema.Resolved.ApplyDefaults
+ // only operates on object properties. For object-rooted output schemas,
+ // coerce a nil result (from "null" or empty data) into {} so handlers that
+ // return a typed-nil map still validate.
+ appliedDefaults := false
+ if _, ok := unmarshaled.(map[string]any); ok {
+ if err := resolved.ApplyDefaults(&unmarshaled); err != nil {
return nil, fmt.Errorf("applying schema defaults:\n%w", err)
}
- if err := resolved.Validate(&v); err != nil {
- return nil, err
+ appliedDefaults = true
+ } else if forOutput && unmarshaled == nil && resolved.Schema().Type == "object" {
+ unmarshaled = make(map[string]any)
+ if err := resolved.ApplyDefaults(&unmarshaled); err != nil {
+ return nil, fmt.Errorf("applying schema defaults:\n%w", err)
}
- // We must re-marshal with the default values applied.
- var err error
- data, err = json.Marshal(v)
- if err != nil {
- return nil, fmt.Errorf("marshalling with defaults: %v", err)
+ appliedDefaults = true
+ }
+
+ if err := resolved.Validate(&unmarshaled); err != nil {
+ return nil, err
+ }
+
+ // Re-marshal only when defaults may have changed the value.
+ if !appliedDefaults {
+ return data, nil
+ }
+ out, err := json.Marshal(unmarshaled)
+ if err != nil {
+ return nil, fmt.Errorf("marshalling with defaults: %v", err)
+ }
+ return out, nil
+}
+
+// isObjectJSON reports whether data is a JSON object (i.e., starts with '{'
+// after any leading whitespace). Returns false for arrays, primitives, null,
+// or empty input.
+func isObjectJSON(data json.RawMessage) bool {
+ for _, b := range data {
+ switch b {
+ case ' ', '\t', '\n', '\r':
+ continue
+ case '{':
+ return true
+ default:
+ return false
}
}
- return data, nil
+ return false
}
// validateToolName checks whether name is a valid tool name, reporting a
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/transport.go b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/transport.go
index ea44747..8b6cd14 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/mcp/transport.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/mcp/transport.go
@@ -18,6 +18,7 @@ import (
internaljson "github.com/modelcontextprotocol/go-sdk/internal/json"
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
+ "github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug"
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
)
@@ -28,6 +29,13 @@ import (
// re-trigger expensive recovery on its behalf. See issue #882.
const notifyCancellationTimeout = 5 * time.Second
+// blockingcancelnotify, when set to "1" via MCPGODEBUG, restores the previous
+// behavior of blocking the caller's return on delivery of the best-effort
+// notifications/cancelled message (up to notifyCancellationTimeout). By
+// default, the call is retired immediately and the notification is sent
+// asynchronously so the caller returns as soon as its context is cancelled.
+var blockingcancelnotify = mcpgodebug.Value("blockingcancelnotify")
+
// ErrConnectionClosed is returned when sending a message to a connection that
// is closed or in the process of closing.
var ErrConnectionClosed = errors.New("connection closed")
@@ -48,6 +56,19 @@ type Transport interface {
Connect(ctx context.Context) (Connection, error)
}
+// ProtocolVersionSupporter is an optional capability that a [Transport] may
+// implement to declare which MCP protocol versions it can serve.
+//
+// [Server.Connect] consults this interface to filter the
+// list of versions advertised in server/discover responses. Transports that
+// do not implement this interface are assumed to support every protocol
+// version known to the SDK.
+type ProtocolVersionSupporter interface {
+ // SupportsProtocolVersion reports whether the transport can serve
+ // requests using the given protocol version.
+ SupportsProtocolVersion(version string) bool
+}
+
// A Connection is a logical bidirectional JSON-RPC connection.
type Connection interface {
// Read reads the next message to process off the connection.
@@ -93,16 +114,27 @@ type clientConnection interface {
// TODO: should this interface be exported?
type serverConnection interface {
Connection
+
+ // sessionUpdated is called whenever the server session state changes.
sessionUpdated(ServerSessionState)
}
+// DefaultMaxLineLength is the default maximum number of bytes buffered while
+// decoding a single inbound JSON-RPC frame.
+const DefaultMaxLineLength = 16 * 1024 * 1024
+
// A StdioTransport is a [Transport] that communicates over stdin/stdout using
// newline-delimited JSON.
-type StdioTransport struct{}
+type StdioTransport struct {
+ // MaxLineLength bounds the number of bytes that may be buffered while
+ // decoding a single inbound JSON-RPC frame. A value of 0 selects [DefaultMaxLineLength],
+ // a negative value disables the cap.
+ MaxLineLength int
+}
// Connect implements the [Transport] interface.
-func (*StdioTransport) Connect(context.Context) (Connection, error) {
- return newIOConn(rwc{os.Stdin, nopCloserWriter{os.Stdout}}), nil
+func (t *StdioTransport) Connect(context.Context) (Connection, error) {
+ return newIOConnLimited(rwc{os.Stdin, nopCloserWriter{os.Stdout}}, t.MaxLineLength), nil
}
// nopCloserWriter is an io.WriteCloser with a trivial Close method.
@@ -117,11 +149,15 @@ func (nopCloserWriter) Close() error { return nil }
type IOTransport struct {
Reader io.ReadCloser
Writer io.WriteCloser
+ // MaxLineLength bounds the number of bytes that may be buffered while
+ // decoding a single inbound JSON-RPC frame. A value of 0 selects [DefaultMaxLineLength],
+ // a negative value disables the cap.
+ MaxLineLength int
}
// Connect implements the [Transport] interface.
func (t *IOTransport) Connect(context.Context) (Connection, error) {
- return newIOConn(rwc{t.Reader, t.Writer}), nil
+ return newIOConnLimited(rwc{t.Reader, t.Writer}, t.MaxLineLength), nil
}
// An InMemoryTransport is a [Transport] that communicates over an in-memory
@@ -178,6 +214,13 @@ func connect[H handler, State any](ctx context.Context, t Transport, b binder[H,
preempter.conn = conn
return jsonrpc2.HandlerFunc(h.handle)
}
+ // Transports may opt in to propagating cancellation of ctx into request
+ // handler contexts when their own lifecycle IS the cancellation signal
+ // (e.g., a connection bound to a single HTTP request).
+ var propagateCancellation bool
+ if cp, ok := mcpConn.(cancellationPropagator); ok {
+ propagateCancellation = cp.propagateCancellation()
+ }
_ = jsonrpc2.NewConnection(ctx, jsonrpc2.ConnectionConfig{
Reader: reader,
Writer: writer,
@@ -190,11 +233,22 @@ func connect[H handler, State any](ctx context.Context, t Transport, b binder[H,
OnInternalError: func(err error) {
logger.Error("jsonrpc2 internal error", "error", err)
},
+ PropagateCancellation: propagateCancellation,
})
assert(preempter.conn != nil, "unbound preempter")
return h, nil
}
+// cancellationPropagator is an optional interface implemented by a
+// [Connection] whose own lifecycle should propagate cancellation into request
+// handler contexts. The default jsonrpc2 behavior is to suppress propagation;
+// transports that bind a connection to a single short-lived carrier (such as
+// a one-shot HTTP request) should return true here so that handlers unwind
+// when the carrier observes the peer going away.
+type cancellationPropagator interface {
+ propagateCancellation() bool
+}
+
// A canceller is a jsonrpc2.Preempter that cancels in-flight requests on MCP
// cancelled notifications.
type canceller struct {
@@ -217,6 +271,24 @@ func (c *canceller) Preempt(ctx context.Context, req *jsonrpc.Request) (result a
return nil, jsonrpc2.ErrNotHandled
}
+// callSubscriptionsListen issues a "subscriptions/listen" call (SEP-2575)
+// without awaiting its JSON-RPC response. The call's logical lifetime is the
+// stream of notifications that follow on the same channel — the empty
+// response, if ever delivered, only marks subscription teardown — so the
+// caller has nothing useful to block on.
+//
+// Cancellation is driven by ctx: when it is cancelled, a background goroutine
+// sends a "notifications/cancelled" notification referencing the listen's
+// request ID and retires the call from the connection's outgoing-calls map.
+func callSubscriptionsListen(ctx context.Context, conn *jsonrpc2.Connection, method string, params Params) {
+ call := conn.Call(ctx, method, params)
+
+ go func() {
+ <-ctx.Done()
+ _ = cancelCall(ctx, conn, call)
+ }()
+}
+
// call executes and awaits a jsonrpc2 call on the given connection,
// translating errors into the mcp domain.
func call(ctx context.Context, conn *jsonrpc2.Connection, method string, params Params, result Result) error {
@@ -227,31 +299,58 @@ func call(ctx context.Context, conn *jsonrpc2.Connection, method string, params
case errors.Is(err, jsonrpc2.ErrClientClosing), errors.Is(err, jsonrpc2.ErrServerClosing):
return fmt.Errorf("%w: calling %q: %v", ErrConnectionClosed, method, err)
case ctx.Err() != nil:
- notifyCtx, cancelNotify := context.WithTimeout(context.WithoutCancel(ctx), notifyCancellationTimeout)
- defer cancelNotify()
- err := conn.Notify(notifyCtx, notificationCancelled, &CancelledParams{
- Reason: ctx.Err().Error(),
- RequestID: call.ID().Raw(),
- })
- // By default, the jsonrpc2 library waits for graceful shutdown when the
- // connection is closed, meaning it expects all outgoing and incoming
- // requests to complete. However, for MCP this expectation is unrealistic,
- // and can lead to hanging shutdown. For example, if a streamable client is
- // killed, the server will not be able to detect this event, except via
- // keepalive pings (if they are configured), and so outgoing calls may hang
- // indefinitely.
+ // The notifications/cancelled message is best-effort. Retire the call
+ // immediately (so an unresponsive peer cannot delay the eager
+ // retirement that cancelCall's docstring promises) and send the
+ // notification off the caller's return path so a slow or unresponsive
+ // peer cannot delay the caller past its own deadline. See issue #1150.
//
- // Therefore, we choose to eagerly retire calls, removing them from the
- // outgoingCalls map, when the caller context is cancelled: if the caller
- // will never receive the response, there's no need to track it.
+ // Setting MCPGODEBUG=blockingcancelnotify=1 restores the previous
+ // behavior of waiting synchronously for delivery inside cancelCall.
+ if blockingcancelnotify == "1" {
+ err := cancelCall(ctx, conn, call)
+ return errors.Join(ctx.Err(), err)
+ }
conn.Retire(call, ctx.Err())
- return errors.Join(ctx.Err(), err)
+ go func() {
+ notifyCtx, stop := context.WithTimeout(context.WithoutCancel(ctx), notifyCancellationTimeout)
+ defer stop()
+ _ = conn.Notify(notifyCtx, notificationCancelled, &CancelledParams{
+ Reason: ctx.Err().Error(),
+ RequestID: call.ID().Raw(),
+ })
+ }()
+ return ctx.Err()
case err != nil:
return fmt.Errorf("calling %q: %w", method, err)
}
return nil
}
+// cancelCall sends a "notifications/cancelled" notification for call and eagerly
+// retires it from conn.
+//
+// By default, the jsonrpc2 library waits for graceful shutdown when the
+// connection is closed, meaning it expects all outgoing and incoming requests
+// to complete. However, for MCP this expectation is unrealistic, and can lead
+// to hanging shutdown. For example, if a streamable client is killed, the
+// server will not be able to detect this event, except via keepalive pings (if
+// they are configured), and so outgoing calls may hang indefinitely.
+//
+// Therefore, we choose to eagerly retire calls, removing them from the
+// outgoingCalls map, when the caller context is cancelled: if the caller will
+// never receive the response, there's no need to track it.
+func cancelCall(ctx context.Context, conn *jsonrpc2.Connection, call *jsonrpc2.AsyncCall) error {
+ notifyCtx, cancelNotify := context.WithTimeout(context.WithoutCancel(ctx), notifyCancellationTimeout)
+ defer cancelNotify()
+ err := conn.Notify(notifyCtx, notificationCancelled, &CancelledParams{
+ Reason: ctx.Err().Error(),
+ RequestID: call.ID().Raw(),
+ })
+ conn.Retire(call, ctx.Err())
+ return err
+}
+
// A LoggingTransport is a [Transport] that delegates to another transport,
// writing RPC logs to an io.Writer.
type LoggingTransport struct {
@@ -392,6 +491,17 @@ type msgOrErr struct {
}
func newIOConn(rwc io.ReadWriteCloser) *ioConn {
+ return newIOConnLimited(rwc, DefaultMaxLineLength)
+}
+
+// newIOConnLimited builds an [ioConn] over rwc that bounds the number of bytes
+// buffered while decoding a single inbound JSON-RPC frame to maxLineLength.
+// maxLineLength == 0 selects [DefaultMaxLineLength], a negative value means no cap.
+func newIOConnLimited(rwc io.ReadWriteCloser, maxLineLength int) *ioConn {
+ limit := maxLineLength
+ if limit == 0 {
+ limit = DefaultMaxLineLength
+ }
var (
incoming = make(chan msgOrErr)
closed = make(chan struct{})
@@ -403,7 +513,15 @@ func newIOConn(rwc io.ReadWriteCloser) *ioConn {
// but that is unavoidable since AFAIK there is no (easy and portable) way to
// guarantee that reads of stdin are unblocked when closed.
go func() {
- dec := json.NewDecoder(rwc)
+ var (
+ reader io.Reader = rwc
+ limiter *frameLimitReader
+ )
+ if limit > 0 {
+ limiter = &frameLimitReader{r: rwc, limit: limit}
+ reader = limiter
+ }
+ dec := json.NewDecoder(reader)
for {
var raw json.RawMessage
err := dec.Decode(&raw)
@@ -429,6 +547,9 @@ func newIOConn(rwc io.ReadWriteCloser) *ioConn {
if err != nil {
return
}
+ if limiter != nil {
+ limiter.resetFrame()
+ }
}
}()
return &ioConn{
@@ -438,20 +559,42 @@ func newIOConn(rwc io.ReadWriteCloser) *ioConn {
}
}
+// errFrameTooLarge means that a single inbound JSON-RPC frame exceeded the configured byte
+// limit before the value was completely received.
+var errFrameTooLarge = errors.New("inbound JSON-RPC frame exceeded the configured maximum line length")
+
+// frameLimitReader bounds the number of bytes [json.Decoder] may buffer while
+// decoding a single JSON value. Read returns [errFrameTooLarge] once the budget is exhausted.
+type frameLimitReader struct {
+ r io.Reader
+ limit int
+ count int
+}
+
+func (r *frameLimitReader) Read(p []byte) (int, error) {
+ if r.count >= r.limit {
+ return 0, errFrameTooLarge
+ }
+ if len(p) > r.limit-r.count {
+ p = p[:r.limit-r.count]
+ }
+ n, err := r.r.Read(p)
+ r.count += n
+ return n, err
+}
+
+func (r *frameLimitReader) resetFrame() { r.count = 0 }
+
func (c *ioConn) SessionID() string { return "" }
func (c *ioConn) sessionUpdated(state ServerSessionState) {
- protocolVersion := ""
- if state.InitializeParams != nil {
- protocolVersion = state.InitializeParams.ProtocolVersion
- }
+ protocolVersion := state.NegotiatedProtocolVersion
if protocolVersion == "" {
// 2025-03-26 is used, because it's the last spec version
// where specifying the protocol version in the HTTP header
// was not required.
protocolVersion = protocolVersion20250326
}
- protocolVersion = negotiatedVersion(protocolVersion)
c.sessionMu.Lock()
c.protocolVersion = protocolVersion
c.sessionMu.Unlock()
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/audience.go b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/audience.go
new file mode 100644
index 0000000..cad1303
--- /dev/null
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/audience.go
@@ -0,0 +1,44 @@
+// Copyright 2026 The Go MCP SDK Authors. All rights reserved.
+// Use of this source code is governed by an MIT-style
+// license that can be found in the LICENSE file.
+
+package oauthex
+
+import "strings"
+
+// MatchesResource reports whether any of claims matches resource under
+// RFC 3986 §6.2.3 scheme-based normalization, narrowed to the empty-path
+// case: a URI with an empty path is treated as equivalent to one with a
+// path of "/". All other URI components (scheme, host case, port, query,
+// fragment) must match exactly — this is intentionally narrower than the
+// full §6.2.3 rung, which would also fold scheme/host case and default
+// ports.
+//
+// RFC 9728 §3.3 normatively requires "simple string comparison" per
+// RFC 3986 §6.2.1 (byte-equal). Callers that need strict byte-equal
+// semantics should compare claims to resource directly:
+//
+// for _, c := range claims { if c == resource { return true } }
+//
+// Background: RFC 9728 §3.3 canonicalises the protected-resource
+// identifier with a trailing slash, but RFC 8707 resource indicators
+// sometimes omit it, and upstream IdPs vary in which form they emit in
+// `aud` claims (Google trims, Auth0 retains, claude.ai round-trips
+// whichever it received). Strict byte equality therefore fails routinely
+// on legitimate setups; this helper is the most common pragmatic relaxation
+// while keeping path/scheme/host strict so token confusion across distinct
+// resources still fails closed.
+//
+// Returns false when claims is empty.
+func MatchesResource(claims []string, resource string) bool {
+ expected := strings.TrimSuffix(resource, "/")
+ for _, c := range claims {
+ if c == resource {
+ return true
+ }
+ if strings.TrimSuffix(c, "/") == expected {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/auth_meta.go b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/auth_meta.go
index df1a0aa..711b17a 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/auth_meta.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/auth_meta.go
@@ -12,6 +12,8 @@ import (
"errors"
"fmt"
"net/http"
+
+ "github.com/modelcontextprotocol/go-sdk/internal/authutil"
)
// AuthServerMeta represents the metadata for an OAuth 2.0 authorization server,
@@ -113,6 +115,13 @@ type AuthServerMeta struct {
// ClientIDMetadataDocumentSupported is a boolean indicating whether the authorization server
// supports client ID metadata documents.
ClientIDMetadataDocumentSupported bool `json:"client_id_metadata_document_supported,omitempty"`
+
+ // AuthorizationResponseIssParameterSupported indicates whether the authorization server
+ // provides the "iss" parameter in authorization responses per [RFC 9207].
+ // When true, clients must verify the "iss" parameter is present and matches the Issuer field.
+ //
+ // [RFC 9207]: https://www.rfc-editor.org/rfc/rfc9207
+ AuthorizationResponseIssParameterSupported bool `json:"authorization_response_iss_parameter_supported,omitempty"`
}
// GetAuthServerMeta issues a GET request to retrieve authorization server metadata
@@ -145,8 +154,7 @@ func GetAuthServerMeta(ctx context.Context, metadataURL, issuer string, c *http.
}
return nil, fmt.Errorf("%v", err) // Do not expose error types.
}
- if asm.Issuer != issuer {
- // Validate the Issuer field (see RFC 8414, section 3.3).
+ if !authutil.IssuersEqual(asm.Issuer, issuer) {
return nil, fmt.Errorf("metadata issuer %q does not match issuer URL %q", asm.Issuer, issuer)
}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/client.go b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/client.go
index e8f9918..1b19eed 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/client.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/client.go
@@ -18,6 +18,15 @@ type ClientCredentials struct {
// This is the most common authentication method for confidential clients.
// OPTIONAL. If not provided, the client is treated as a public client.
ClientSecretAuth *ClientSecretAuth
+
+ // Issuer is the issuer identifier of the authorization server these
+ // credentials are registered with. Pre-registered credentials are bound
+ // to a specific authorization server; when set, an error is returned if
+ // the discovered authorization server does not match, per SEP-2352.
+ // The comparison ignores a single trailing slash, matching the
+ // tolerance applied during RFC 8414 Section 3.3 metadata validation.
+ // OPTIONAL.
+ Issuer string
}
// ClientSecretAuth holds client secret authentication credentials.
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/dcr.go b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/dcr.go
index f46d0e8..f95c55b 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/dcr.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/dcr.go
@@ -175,6 +175,10 @@ func (e *ClientRegistrationError) Error() string {
return fmt.Sprintf("registration failed: %s (%s)", e.ErrorCode, e.ErrorDescription)
}
+// maxRegistrationResponseBytes bounds the dynamic client registration response
+// body read from the authorization server.
+const maxRegistrationResponseBytes = 1 << 20 // 1 MiB
+
// RegisterClient performs Dynamic Client Registration according to RFC 7591.
func RegisterClient(ctx context.Context, registrationEndpoint string, clientMeta *ClientRegistrationMetadata, c *http.Client) (*ClientRegistrationResponse, error) {
if registrationEndpoint == "" {
@@ -204,7 +208,7 @@ func RegisterClient(ctx context.Context, registrationEndpoint string, clientMeta
}
defer resp.Body.Close()
- body, err := io.ReadAll(resp.Body)
+ body, err := io.ReadAll(io.LimitReader(resp.Body, maxRegistrationResponseBytes))
if err != nil {
return nil, fmt.Errorf("failed to read registration response body: %w", err)
}
diff --git a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/oauth2.go b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/oauth2.go
index 689f17a..caed92f 100644
--- a/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/oauth2.go
+++ b/vendor/github.com/modelcontextprotocol/go-sdk/oauthex/oauth2.go
@@ -11,14 +11,22 @@ import (
"fmt"
"io"
"mime"
+ "net"
"net/http"
+ "net/netip"
"net/url"
"strings"
+ "syscall"
+ "time"
"github.com/modelcontextprotocol/go-sdk/internal/json"
"github.com/modelcontextprotocol/go-sdk/internal/util"
)
+const maxDiscoveryRedirects = 10
+
+var defaultDiscoveryTransport = newDiscoveryTransport(http.DefaultTransport)
+
type httpStatusError struct {
StatusCode int
}
@@ -35,10 +43,7 @@ func getJSON[T any](ctx context.Context, c *http.Client, url string, limit int64
if err != nil {
return nil, err
}
- if c == nil {
- c = http.DefaultClient
- }
- res, err := c.Do(req)
+ res, err := newDiscoveryClient(c).Do(req)
if err != nil {
return nil, err
}
@@ -91,5 +96,112 @@ func checkHTTPSOrLoopback(addr string) error {
if !util.IsLoopback(u.Host) && u.Scheme != "https" {
return fmt.Errorf("URL %q does not use HTTPS or is not a loopback address", addr)
}
+ if ip, err := netip.ParseAddr(u.Hostname()); err == nil && util.IsPrivateOrReserved(ip) {
+ return fmt.Errorf("URL %q refers to a non-public address", addr)
+ }
+ return nil
+}
+
+func newDiscoveryClient(c *http.Client) *http.Client {
+ transport := defaultDiscoveryTransport
+ if c != nil && c.Transport != nil {
+ // a caller that has taken over dialing or TLS opts out of the checks
+ if t, ok := c.Transport.(*http.Transport); ok && t.DialContext == nil && t.DialTLSContext == nil {
+ transport = newDiscoveryTransport(t)
+ } else {
+ transport = c.Transport
+ }
+ }
+ discoveryClient := &http.Client{
+ Transport: transport,
+
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ if c != nil && c.CheckRedirect != nil {
+ return c.CheckRedirect(req, via)
+ }
+ if len(via) >= maxDiscoveryRedirects {
+ return fmt.Errorf("max redirects exceeded (%d)", maxDiscoveryRedirects)
+ }
+ if prev := via[len(via)-1]; prev.URL.Scheme == "https" && req.URL.Scheme != "https" {
+ return fmt.Errorf("redirect to non-HTTPS scheme %q is a security downgrade", req.URL.Scheme)
+ }
+ return checkLoopbackRedirect(req.Context(), req.URL.Hostname())
+ },
+ }
+ if c != nil {
+ discoveryClient.Timeout = c.Timeout
+ discoveryClient.Jar = c.Jar
+ }
+ return discoveryClient
+}
+
+// newDiscoveryTransport creates an http.RoundTripper with extra protections enabled,
+// unless the provided RoundTripper is not *http.Transport.
+func newDiscoveryTransport(rt http.RoundTripper) http.RoundTripper {
+ base, ok := rt.(*http.Transport)
+ if !ok {
+ return rt
+ }
+ // If a proxy is configured Control checks should be disabled, because they will
+ // basically be running for proxy dials.
+ if proxyConfigured(base) {
+ return rt
+ }
+ result := base.Clone()
+ result.DialContext = (&net.Dialer{
+ Timeout: 30 * time.Second,
+ KeepAlive: 30 * time.Second,
+ Control: func(_, address string, _ syscall.RawConn) error {
+ host, _, err := net.SplitHostPort(address)
+ if err != nil {
+ host = address
+ }
+ ip, err := netip.ParseAddr(host)
+ if err != nil {
+ return fmt.Errorf("non-ip address: %w", err)
+ }
+ if util.IsPrivateOrReserved(ip) {
+ return fmt.Errorf("non-public ip address: %q", ip)
+ }
+ return nil
+ },
+ }).DialContext
+ return result
+}
+
+func proxyConfigured(t *http.Transport) bool {
+ if t.Proxy == nil {
+ return false
+ }
+ req, err := http.NewRequest(http.MethodGet, "https://check-proxy-existence.com", nil)
+ if err != nil {
+ return false
+ }
+ u, err := t.Proxy(req)
+ return err == nil && u != nil
+}
+
+func checkLoopbackRedirect(ctx context.Context, host string) error {
+ doCheck := func(ip netip.Addr) error {
+ if ip.Unmap().IsLoopback() {
+ return fmt.Errorf("redirect into loopback address %q", host)
+ }
+ if util.IsPrivateOrReserved(ip) {
+ return fmt.Errorf("redirect into non-public address %q", host)
+ }
+ return nil
+ }
+ if ip, err := netip.ParseAddr(host); err == nil {
+ return doCheck(ip)
+ }
+ ips, err := net.DefaultResolver.LookupNetIP(ctx, "ip", host)
+ if err != nil {
+ return fmt.Errorf("cannot resolve redirect host %q: %w", host, err)
+ }
+ for _, ip := range ips {
+ if err := doCheck(ip); err != nil {
+ return err
+ }
+ }
return nil
}
diff --git a/vendor/github.com/urfave/cli/v3/args.go b/vendor/github.com/urfave/cli/v3/args.go
index b3acfd5..0dad209 100644
--- a/vendor/github.com/urfave/cli/v3/args.go
+++ b/vendor/github.com/urfave/cli/v3/args.go
@@ -77,6 +77,11 @@ type Argument interface {
Get() any
}
+type requiredArgument interface {
+ name() string
+ required() bool
+}
+
// AnyArguments to differentiate between no arguments(nil) vs aleast one
var AnyArguments = []Argument{
&StringArgs{
@@ -89,6 +94,7 @@ type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct {
Value T `json:"value"` // the default value of this argument
Destination *T `json:"-"` // the destination point for this argument
UsageText string `json:"usageText"` // the usage text to show
+ Required bool `json:"required"` // whether the argument is required or not
Config C `json:"config"` // config for this argument similar to Flag Config
value *T
@@ -98,18 +104,33 @@ func (a *ArgumentBase[T, C, VC]) HasName(s string) bool {
return s == a.Name
}
+func (a *ArgumentBase[T, C, VC]) name() string {
+ return a.Name
+}
+
+func (a *ArgumentBase[T, C, VC]) required() bool {
+ return a.Required
+}
+
func (a *ArgumentBase[T, C, VC]) Usage() string {
if a.UsageText != "" {
return a.UsageText
}
- usageFormat := "%[1]s"
+ usageFormat := "[%[1]s]"
+ if a.Required {
+ usageFormat = "%[1]s"
+ }
return fmt.Sprintf(usageFormat, a.Name)
}
func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {
tracef("calling arg%[1] parse with args %[2]", a.Name, s)
+ if a.Required && len(s) == 0 {
+ return s, &errRequiredArguments{missingArguments: []string{a.Name}}
+ }
+
var vc VC
var t T
value := vc.Create(a.Value, &t, a.Config)
diff --git a/vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete b/vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete
index fd08201..42eb17b 100644
--- a/vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete
+++ b/vendor/github.com/urfave/cli/v3/autocomplete/bash_autocomplete
@@ -66,7 +66,7 @@ __%[1]s_bash_autocomplete() {
local description=""
if [[ "${line}" == *:* ]]; then
- token="${line%%:*}"
+ token="${line%%%%:*}"
description="${line#*:}"
fi
@@ -104,4 +104,4 @@ __%[1]s_bash_autocomplete() {
fi
}
-complete -o bashdefault -o default -o nospace -F __%[1]s_bash_autocomplete %[1]s
+complete -o bashdefault -o default -F __%[1]s_bash_autocomplete %[1]s
diff --git a/vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete b/vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete
index 6714f75..5f2fcd7 100644
--- a/vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete
+++ b/vendor/github.com/urfave/cli/v3/autocomplete/fish_autocomplete
@@ -6,7 +6,11 @@ function __%[1]s_perform_completion
# Extract the last arg (partial input)
set -l lastArg (commandline -ct)
- set -l results ($args[1] $args[2..-1] $lastArg --generate-shell-completion 2> /dev/null)
+ if string match -q -- "-*" $lastArg
+ set results ($args[1] $args[2..-1] $lastArg --generate-shell-completion 2> /dev/null)
+ else
+ set results ($args[1] $args[2..-1] --generate-shell-completion 2> /dev/null)
+ end
# Remove trailing empty lines
for line in $results[-1..1]
@@ -32,4 +36,4 @@ end
# Clear existing completions for %[1]s
complete -c %[1]s -e
# Register completion function
-complete -c %[1]s -f -a '(__%[1]s_perform_completion)'
\ No newline at end of file
+complete -c %[1]s -f -a '(__%[1]s_perform_completion)'
diff --git a/vendor/github.com/urfave/cli/v3/command.go b/vendor/github.com/urfave/cli/v3/command.go
index d1a9d05..21faf18 100644
--- a/vendor/github.com/urfave/cli/v3/command.go
+++ b/vendor/github.com/urfave/cli/v3/command.go
@@ -46,6 +46,9 @@ type Command struct {
Flags []Flag `json:"flags"`
// Boolean to hide built-in help command and help flag
HideHelp bool `json:"hideHelp"`
+ // Boolean to hide the built-in help command. Applies to this command and
+ // all of its subcommands: as with HideHelp, a true value is inherited and
+ // a subcommand cannot turn it back off.
// Ignored if HideHelp is true.
HideHelpCommand bool `json:"hideHelpCommand"`
// Boolean to hide built-in version flag and the VERSION section of help
@@ -64,6 +67,11 @@ type Command struct {
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After AfterFunc `json:"-"`
+ // An action to validate arguments before the command is run. If non-nil, it
+ // is called before Before and Action. If the current command does not set
+ // ArgValidator, the nearest ancestor that does is used instead.
+ // Returning a non-nil error short-circuits the command.
+ ArgValidator ArgValidatorFunc `json:"-"`
// The function to call when this command is invoked
Action ActionFunc `json:"-"`
// Execute this function if the proper command cannot be found
@@ -74,6 +82,10 @@ type Command struct {
InvalidFlagAccessHandler InvalidFlagAccessFunc `json:"-"`
// Boolean to hide this command from help or completion
Hidden bool `json:"hidden"`
+ // Deprecation message for this command. If non-empty, a warning is
+ // printed to ErrWriter when the command is invoked. Setting it does not
+ // hide the command; set Hidden as well for that.
+ Deprecated string `json:"deprecated"`
// List of all authors who contributed (string or fmt.Stringer)
// TODO: ~string | fmt.Stringer when interface unions are available
Authors []any `json:"authors"`
@@ -157,25 +169,20 @@ type Command struct {
didSetupDefaults bool
// whether in shell completion mode
shellCompletion bool
+ // whether the shell completion request came after a "--" separator,
+ // after which only positional arguments are accepted and nothing is
+ // suggested. The request is still a completion, never a command run.
+ shellCompletionPastDoubleDash bool
// whether global help flag was added
globaHelpFlagAdded bool
// whether global version flag was added
globaVersionFlagAdded bool
+ // generated root version flag
+ versionFlag Flag
// whether this is a completion command
isCompletionCommand bool
-}
-
-// FullName returns the full name of the command.
-// For commands with parents this ensures that the parent commands
-// are part of the command path.
-func (cmd *Command) FullName() string {
- namePath := []string{}
-
- if cmd.parent != nil {
- namePath = append(namePath, cmd.parent.FullName())
- }
-
- return strings.Join(append(namePath, cmd.Name), " ")
+ // whether this is the built-in help command
+ builtInHelp bool
}
func (cmd *Command) Command(name string) *Command {
@@ -303,13 +310,29 @@ func (cmd *Command) appendFlag(fl Flag) {
// VisiblePersistentFlags returns a slice of [LocalFlag] with Persistent=true and Hidden=false.
func (cmd *Command) VisiblePersistentFlags() []Flag {
+ if cmd.isCompletionCommand {
+ return nil
+ }
var flags []Flag
- for _, fl := range cmd.Root().Flags {
- pfl, ok := fl.(LocalFlag)
- if !ok || pfl.IsLocal() {
- continue
+ lineage := cmd.Lineage()
+ for i := len(lineage) - 1; i > 0; i-- {
+ for _, fl := range lineage[i].allFlags() {
+ pfl, ok := fl.(LocalFlag)
+ if !ok || pfl.IsLocal() {
+ continue
+ }
+ applies := true
+ for _, name := range fl.Names() {
+ if cmd.lookupFlag(name) != fl {
+ applies = false
+ break
+ }
+ }
+ if !applies {
+ continue
+ }
+ flags = append(flags, fl)
}
- flags = append(flags, fl)
}
return visibleFlags(flags)
}
@@ -370,6 +393,22 @@ func (cmd *Command) lFlag(name string) Flag {
return nil
}
+func (cmd *Command) hasPersistentFlagOnAncestor(fl Flag) bool {
+ for pCmd := cmd.parent; pCmd != nil; pCmd = pCmd.parent {
+ for _, pFl := range pCmd.allFlags() {
+ if pFl != fl {
+ continue
+ }
+
+ pfl, ok := pFl.(LocalFlag)
+ if ok && !pfl.IsLocal() {
+ return true
+ }
+ }
+ }
+ return false
+}
+
func (cmd *Command) lookupFlag(name string) Flag {
for _, pCmd := range cmd.Lineage() {
if f := pCmd.lFlag(name); f != nil {
@@ -411,7 +450,7 @@ func (cmd *Command) checkAllRequiredFlags() requiredFlagsErr {
// The help and completion commands are allowed to run without
// enforcement of required flags, since they do not invoke user
// actions that depend on those flag values.
- if cmd.Name == helpName || cmd.isCompletionCommand {
+ if cmd.builtInHelp || cmd.isCompletionCommand {
return nil
}
for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent {
@@ -444,6 +483,40 @@ func (cmd *Command) checkRequiredFlags() requiredFlagsErr {
return nil
}
+func (cmd *Command) checkRequiredArguments() requiredArgumentsErr {
+ // The help and completion commands are allowed to run without
+ // enforcement of required arguments, since they do not invoke user
+ // actions that depend on those argument values.
+ if cmd.builtInHelp || cmd.isCompletionCommand {
+ return nil
+ }
+
+ tracef("checking for required arguments (cmd=%[1]q)", cmd.Name)
+
+ missingArguments := []string{}
+ // This count-based precheck relies on required single-value arguments
+ // being declared before optional or multi-value arguments, as documented.
+ // Argument.Parse remains the backstop for unsupported orderings.
+ providedArguments := cmd.Args().Len()
+
+ for index, arg := range cmd.Arguments {
+ requiredArg, ok := arg.(requiredArgument)
+ if ok && requiredArg.required() && index >= providedArguments {
+ missingArguments = append(missingArguments, requiredArg.name())
+ }
+ }
+
+ if len(missingArguments) != 0 {
+ tracef("found missing required arguments %[1]q (cmd=%[2]q)", missingArguments, cmd.Name)
+
+ return &errRequiredArguments{missingArguments: missingArguments}
+ }
+
+ tracef("all required arguments set (cmd=%[1]q)", cmd.Name)
+
+ return nil
+}
+
func (cmd *Command) onInvalidFlag(ctx context.Context, name string) {
for cmd != nil {
if cmd.InvalidFlagAccessHandler != nil {
@@ -556,6 +629,39 @@ func (cmd *Command) Lineage() []*Command {
return lineage
}
+// FullName returns the full name of the command.
+// Includes parent commands separated by space.
+func (cmd *Command) FullName() string {
+ return strings.Join(cmd.Path(), " ")
+}
+
+// Path returns the path of command names from the root to cmd, inclusive.
+// Each element is a Command.Name. Path traverses upward via parent pointers
+// similar to Lineage. FullName() is equivalent to strings.Join(cmd.Path(), " ").
+func (cmd *Command) Path() []string {
+ if cmd.parent != nil {
+ return append(cmd.parent.Path(), cmd.Name)
+ }
+ return []string{cmd.Name}
+}
+
+// Walk visits cmd and every descendant. If fn returns a non-nil error, the
+// walk terminates and the error is returned to the caller.
+func (cmd *Command) Walk(fn func(*Command) error) error {
+ if fn == nil {
+ return nil
+ }
+ if err := fn(cmd); err != nil {
+ return err
+ }
+ for _, sub := range cmd.Commands {
+ if err := sub.Walk(fn); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
// Count returns the num of occurrences of this flag
func (cmd *Command) Count(name string) int {
if cf, ok := cmd.lookupFlag(name).(Countable); ok {
@@ -576,7 +682,9 @@ func (cmd *Command) Value(name string) any {
}
// Args returns the command line arguments associated with the
-// command.
+// command. If the command declares named Arguments, the arguments
+// consumed by them are not included in the returned Args and should
+// be retrieved via the command.{Type}Arg(name) functions instead.
func (cmd *Command) Args() Args {
return cmd.parsedArgs
}
diff --git a/vendor/github.com/urfave/cli/v3/command_parse.go b/vendor/github.com/urfave/cli/v3/command_parse.go
index 2b9a481..74a7db0 100644
--- a/vendor/github.com/urfave/cli/v3/command_parse.go
+++ b/vendor/github.com/urfave/cli/v3/command_parse.go
@@ -4,6 +4,7 @@ import (
"fmt"
"strings"
"unicode"
+ "unicode/utf8"
)
const (
@@ -114,7 +115,9 @@ func (cmd *Command) parseFlags(args Args) (Args, error) {
return &stringSliceArgs{posArgs}, nil
}
- posArgs = append(posArgs, firstArg)
+ // firstArg is a trimmed copy that classifies the argument; the
+ // argument itself is what the action receives, byte for byte.
+ posArgs = append(posArgs, rargs[0])
continue
}
@@ -131,7 +134,7 @@ func (cmd *Command) parseFlags(args Args) (Args, error) {
if firstArg[1] == '-' {
numMinuses++
shortOptionHandling = false
- } else if !unicode.IsLetter(rune(firstArg[1])) {
+ } else if firstRune, _ := utf8.DecodeRuneInString(firstArg[1:]); !unicode.IsLetter(firstRune) {
// this is not a flag
tracef("parseFlags not a unicode letter. Stop parsing")
posArgs = append(posArgs, rargs...)
@@ -145,7 +148,9 @@ func (cmd *Command) parseFlags(args Args) (Args, error) {
valFromEqual := false
tracef("flagName:1 (fName=%[1]q)", flagName)
if index := strings.Index(flagName, "="); index != -1 {
- flagVal = flagName[index+1:]
+ // Classify the flag using the trimmed token, but leave value
+ // whitespace handling to the flag's value parser.
+ _, flagVal, _ = strings.Cut(rargs[0], "=")
flagName = flagName[:index]
valFromEqual = true
}
@@ -199,6 +204,12 @@ func (cmd *Command) parseFlags(args Args) (Args, error) {
posArgs = append(posArgs, rargs...)
return &stringSliceArgs{posArgs}, nil
}
+ // When DefaultCommand is set, pass unknown flags through as positional args
+ // so the default command can handle them (fixes #2249)
+ if cmd.DefaultCommand != "" {
+ posArgs = append(posArgs, rargs...)
+ return &stringSliceArgs{posArgs}, nil
+ }
return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName)
}
@@ -206,6 +217,10 @@ func (cmd *Command) parseFlags(args Args) (Args, error) {
for index, c := range flagName {
tracef("processing flag (fName=%[1]q)", string(c))
if sf := cmd.lookupFlag(string(c)); sf == nil {
+ if index == 0 && cmd.DefaultCommand != "" {
+ posArgs = append(posArgs, rargs...)
+ return &stringSliceArgs{posArgs}, nil
+ }
return &stringSliceArgs{posArgs}, fmt.Errorf("%s%s", providedButNotDefinedErrMsg, flagName)
} else if fb, ok := sf.(boolFlag); ok && fb.IsBoolFlag() {
fv := flagVal
diff --git a/vendor/github.com/urfave/cli/v3/command_run.go b/vendor/github.com/urfave/cli/v3/command_run.go
index 269dd85..8e9da80 100644
--- a/vendor/github.com/urfave/cli/v3/command_run.go
+++ b/vendor/github.com/urfave/cli/v3/command_run.go
@@ -9,6 +9,8 @@ import (
"unicode"
)
+type helpShownKey struct{}
+
func (cmd *Command) parseArgsFromStdin() ([]string, error) {
type state int
const (
@@ -123,6 +125,11 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
// note that we can only do this because the shell autocomplete function
// always appends the completion flag at the end of the command
tracef("checking osArgs %v (cmd=%[2]q)", osArgs, cmd.Name)
+ // completion request state is per-run: a Command answering several
+ // requests (tests, REPL, embedded use) must not carry one request
+ // into the next
+ cmd.shellCompletion = false
+ cmd.shellCompletionPastDoubleDash = false
cmd.shellCompletion, osArgs = checkShellCompleteFlag(cmd, osArgs)
tracef("setting cmd.shellCompletion=%[1]v from checkShellCompleteFlag (cmd=%[2]q)", cmd.shellCompletion && cmd.EnableShellCompletion, cmd.Name)
@@ -141,13 +148,10 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
var rargs Args = &stringSliceArgs{v: osArgs}
var args Args = &stringSliceArgs{rargs.Tail()}
- if cmd.isCompletionCommand {
- tracef("completion command detected, skipping pre-parse (cmd=%[1]q)", cmd.Name)
- cmd.parsedArgs = args
- return ctx, cmd.Action(ctx, cmd)
- }
-
for _, f := range cmd.allFlags() {
+ if cmd.hasPersistentFlagOnAncestor(f) {
+ continue
+ }
if err := f.PreParse(); err != nil {
return ctx, err
}
@@ -164,7 +168,12 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
tracef("using post-parse arguments %[1]q (cmd=%[2]q)", args, cmd.Name)
- if checkCompletions(ctx, cmd) {
+ if shouldRunCompletion(cmd) {
+ var beforeErr error
+ if ctx, beforeErr = runBefore(ctx, commandChain(cmd)); beforeErr != nil {
+ return ctx, beforeErr
+ }
+ runCompletion(ctx, cmd)
return ctx, nil
}
@@ -173,6 +182,15 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
deferErr = err
cmd.isInError = true
+ if cmd.checkHelp() {
+ ctx = context.WithValue(ctx, helpShownKey{}, true)
+ if cmd.parent == nil {
+ _ = ShowRootCommandHelp(cmd)
+ } else {
+ _ = ShowSubcommandHelp(cmd)
+ }
+ return ctx, nil
+ }
if cmd.OnUsageError != nil {
err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
err = cmd.handleExitCoder(ctx, err)
@@ -191,10 +209,8 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
tracef("SILENTLY IGNORING ERROR running ShowRootCommandHelp %[1]v (cmd=%[2]q)", err, cmd.Name)
}
} else {
- tracef("running ShowCommandHelp with %[1]q", cmd.Name)
- if err := ShowCommandHelp(ctx, cmd, cmd.Name); err != nil {
- tracef("SILENTLY IGNORING ERROR running ShowCommandHelp with %[1]q %[2]v", cmd.Name, err)
- }
+ tracef("running ShowSubcommandHelp for %[1]q", cmd.Name)
+ _ = ShowSubcommandHelp(cmd)
}
}
@@ -202,6 +218,7 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
}
if cmd.checkHelp() {
+ ctx = context.WithValue(ctx, helpShownKey{}, true)
return ctx, helpCommandAction(ctx, cmd)
} else {
tracef("no help is wanted (cmd=%[1]q)", cmd.Name)
@@ -226,6 +243,9 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
if cmd.After != nil && !cmd.Root().shellCompletion {
defer func() {
+ if ctx.Value(helpShownKey{}) != nil {
+ return
+ }
if err := cmd.After(ctx, cmd); err != nil {
err = cmd.handleExitCoder(ctx, err)
@@ -246,7 +266,14 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
if cmd.OnUsageError != nil {
err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
} else {
- _ = ShowSubcommandHelp(cmd)
+ fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n\n", err.Error())
+ if cmd.parent == nil {
+ _ = ShowRootCommandHelp(cmd)
+ } else {
+ if err := ShowCommandHelp(ctx, cmd.parent, cmd.Name); err != nil {
+ _ = ShowSubcommandHelp(cmd)
+ }
+ }
}
return ctx, err
}
@@ -268,13 +295,12 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
subCmd = cmd.Command(name)
if subCmd == nil {
hasDefault := cmd.DefaultCommand != ""
- isFlagName := slices.Contains(cmd.FlagNames(), name)
if hasDefault {
tracef("using default command=%[1]q (cmd=%[2]q)", cmd.DefaultCommand, cmd.Name)
}
- if isFlagName || hasDefault {
+ if hasDefault {
argsWithDefault := cmd.argsWithDefaultCommand(cmd.parsedArgs)
tracef("using default command args=%[1]q (cmd=%[2]q)", argsWithDefault, cmd.Name)
subCmd = cmd.Command(argsWithDefault.First())
@@ -304,25 +330,24 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
// perform the command action.
//
// First, resolve the chain of nested commands up to the parent.
- var cmdChain []*Command
- for p := cmd; p != nil; p = p.parent {
- cmdChain = append(cmdChain, p)
- }
- slices.Reverse(cmdChain)
+ cmdChain := commandChain(cmd)
- // Run Before actions in order.
- for _, cmd := range cmdChain {
- if cmd.Before == nil {
- continue
- }
- if bctx, err := cmd.Before(ctx, cmd); err != nil {
+ printDeprecationWarnings(cmdChain)
+
+ // Run ArgValidator from the nearest ancestor that sets one.
+ if validator := findArgValidator(cmd); validator != nil {
+ if err := validator(ctx, cmd); err != nil {
deferErr = cmd.handleExitCoder(ctx, err)
return ctx, deferErr
- } else if bctx != nil {
- ctx = bctx
}
}
+ // Run Before actions in order.
+ if ctx, err = runBefore(ctx, cmdChain); err != nil {
+ deferErr = err
+ return ctx, deferErr
+ }
+
// Run flag actions in order.
// These take a context, so this has to happen after Before actions.
for _, cmd := range cmdChain {
@@ -333,14 +358,14 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
}
}
+ var requiredErr error
if err := cmd.checkAllRequiredFlags(); err != nil {
- cmd.isInError = true
- if cmd.OnUsageError != nil {
- err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
- } else {
- _ = ShowSubcommandHelp(cmd)
- }
- return ctx, err
+ requiredErr = err
+ } else if err := cmd.checkRequiredArguments(); err != nil {
+ requiredErr = err
+ }
+ if requiredErr != nil {
+ return cmd.handleRequiredError(ctx, requiredErr)
}
// Run the command action.
@@ -352,6 +377,9 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
rargs, err = arg.Parse(rargs)
if err != nil {
tracef("calling with %[1]v (cmd=%[2]q)", err, cmd.Name)
+ if _, ok := err.(*errRequiredArguments); ok {
+ return cmd.handleRequiredError(ctx, err)
+ }
if cmd.OnUsageError != nil {
err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
}
@@ -370,3 +398,76 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
tracef("returning deferErr (cmd=%[1]q) %[2]q", cmd.Name, deferErr)
return ctx, deferErr
}
+
+func (cmd *Command) handleRequiredError(ctx context.Context, err error) (context.Context, error) {
+ cmd.isInError = true
+ if cmd.OnUsageError != nil {
+ err = cmd.OnUsageError(ctx, cmd, err, cmd.parent != nil)
+ } else {
+ fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n\n", err.Error())
+ if cmd.parent == nil {
+ _ = ShowRootCommandHelp(cmd)
+ } else if helpErr := ShowCommandHelp(ctx, cmd.parent, cmd.Name); helpErr != nil {
+ _ = ShowSubcommandHelp(cmd)
+ }
+ }
+ return ctx, err
+}
+
+func commandChain(cmd *Command) []*Command {
+ var cmdChain []*Command
+ for p := cmd; p != nil; p = p.parent {
+ cmdChain = append(cmdChain, p)
+ }
+ slices.Reverse(cmdChain)
+ return cmdChain
+}
+
+// printDeprecationWarnings writes a warning to the root ErrWriter for each
+// deprecated command in the chain and for each deprecated flag that has been
+// set, whether on the command line or from one of its Sources.
+func printDeprecationWarnings(cmdChain []*Command) {
+ w := cmdChain[0].ErrWriter
+ warned := map[Flag]struct{}{}
+ for _, cmd := range cmdChain {
+ if cmd.Deprecated != "" {
+ fmt.Fprintf(w, "Command %q is deprecated, %s\n", cmd.Name, cmd.Deprecated)
+ }
+ for _, fl := range cmd.appliedFlags {
+ if _, inSet := cmd.setFlags[fl]; !inSet {
+ continue
+ }
+ if _, done := warned[fl]; done {
+ continue
+ }
+ if df, ok := fl.(DeprecatedFlag); ok && df.GetDeprecated() != "" {
+ warned[fl] = struct{}{}
+ name := fl.Names()[0]
+ fmt.Fprintf(w, "Flag %s%s has been deprecated, %s\n", prefixFor(name), name, df.GetDeprecated())
+ }
+ }
+ }
+}
+
+func findArgValidator(cmd *Command) ArgValidatorFunc {
+ for c := cmd; c != nil; c = c.parent {
+ if c.ArgValidator != nil {
+ return c.ArgValidator
+ }
+ }
+ return nil
+}
+
+func runBefore(ctx context.Context, cmdChain []*Command) (context.Context, error) {
+ for _, cmd := range cmdChain {
+ if cmd.Before == nil {
+ continue
+ }
+ if bctx, err := cmd.Before(ctx, cmd); err != nil {
+ return ctx, cmd.handleExitCoder(ctx, err)
+ } else if bctx != nil {
+ ctx = bctx
+ }
+ }
+ return ctx, nil
+}
diff --git a/vendor/github.com/urfave/cli/v3/command_setup.go b/vendor/github.com/urfave/cli/v3/command_setup.go
index cac4a30..3ea2fa8 100644
--- a/vendor/github.com/urfave/cli/v3/command_setup.go
+++ b/vendor/github.com/urfave/cli/v3/command_setup.go
@@ -24,7 +24,7 @@ func (cmd *Command) setupDefaults(osArgs []string) {
cmd.ShellComplete = DefaultCompleteWithFlags
}
- if cmd.Name == "" && isRoot {
+ if cmd.Name == "" && isRoot && len(osArgs) > 0 {
name := filepath.Base(osArgs[0])
tracef("setting cmd.Name from first arg basename (cmd=%[1]q)", name)
cmd.Name = name
@@ -46,18 +46,33 @@ func (cmd *Command) setupDefaults(osArgs []string) {
}
if cmd.Reader == nil {
- tracef("setting default Reader as os.Stdin (cmd=%[1]q)", cmd.Name)
- cmd.Reader = os.Stdin
+ if cmd.parent != nil && cmd.parent.Reader != nil {
+ tracef("inheriting Reader from parent (cmd=%[1]q)", cmd.Name)
+ cmd.Reader = cmd.parent.Reader
+ } else {
+ tracef("setting default Reader as os.Stdin (cmd=%[1]q)", cmd.Name)
+ cmd.Reader = os.Stdin
+ }
}
if cmd.Writer == nil {
- tracef("setting default Writer as os.Stdout (cmd=%[1]q)", cmd.Name)
- cmd.Writer = os.Stdout
+ if cmd.parent != nil && cmd.parent.Writer != nil {
+ tracef("inheriting Writer from parent (cmd=%[1]q)", cmd.Name)
+ cmd.Writer = cmd.parent.Writer
+ } else {
+ tracef("setting default Writer as os.Stdout (cmd=%[1]q)", cmd.Name)
+ cmd.Writer = os.Stdout
+ }
}
if cmd.ErrWriter == nil {
- tracef("setting default ErrWriter as os.Stderr (cmd=%[1]q)", cmd.Name)
- cmd.ErrWriter = os.Stderr
+ if cmd.parent != nil && cmd.parent.ErrWriter != nil {
+ tracef("inheriting ErrWriter from parent (cmd=%[1]q)", cmd.Name)
+ cmd.ErrWriter = cmd.parent.ErrWriter
+ } else {
+ tracef("setting default ErrWriter as os.Stderr (cmd=%[1]q)", cmd.Name)
+ cmd.ErrWriter = os.Stderr
+ }
}
if cmd.AllowExtFlags {
@@ -84,13 +99,20 @@ func (cmd *Command) setupDefaults(osArgs []string) {
var localVersionFlag Flag
if globalVersionFlag, ok := VersionFlag.(*BoolFlag); ok {
flag := *globalVersionFlag
+ // Drop any alias a user flag already claims (e.g. -v
+ // for --verbose) so the user flag wins but --version
+ // still works. See #2229.
+ flag.Aliases = dropClashingAliases(flag.Aliases, cmd.allFlags(), flag.Name)
localVersionFlag = &flag
} else {
localVersionFlag = VersionFlag
}
- cmd.appendFlag(localVersionFlag)
- cmd.globaVersionFlagAdded = true
+ if !flagNamesInUse(cmd.allFlags(), localVersionFlag.Names()) {
+ cmd.appendFlag(localVersionFlag)
+ cmd.versionFlag = localVersionFlag
+ cmd.globaVersionFlagAdded = true
+ }
}
}
@@ -131,6 +153,7 @@ func (cmd *Command) setupDefaults(osArgs []string) {
tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name)
for _, grp := range cmd.MutuallyExclusiveFlags {
grp.propagateCategory()
+ grp.propagateStringer()
}
tracef("setting flag categories (cmd=%[1]q)", cmd.Name)
@@ -147,11 +170,13 @@ func (cmd *Command) setupDefaults(osArgs []string) {
func (cmd *Command) setupCommandGraph() {
tracef("setting up command graph (cmd=%[1]q)", cmd.Name)
- for _, subCmd := range cmd.Commands {
- subCmd.parent = cmd
- subCmd.setupSubcommand()
- subCmd.setupCommandGraph()
- }
+ _ = cmd.Walk(func(sub *Command) error {
+ for _, subCmd := range sub.Commands {
+ subCmd.parent = sub
+ subCmd.setupSubcommand()
+ }
+ return nil
+ })
}
func (cmd *Command) setupSubcommand() {
@@ -172,12 +197,27 @@ func (cmd *Command) setupSubcommand() {
tracef("setting category on mutually exclusive flags (cmd=%[1]q)", cmd.Name)
for _, grp := range cmd.MutuallyExclusiveFlags {
grp.propagateCategory()
+ grp.propagateStringer()
}
tracef("setting flag categories (cmd=%[1]q)", cmd.Name)
cmd.flagCategories = newFlagCategoriesFromFlags(cmd.allFlags())
}
+func flagNamesInUse(flags []Flag, names []string) bool {
+ for _, name := range names {
+ for _, fl := range flags {
+ for _, flagName := range fl.Names() {
+ if flagName == name {
+ return true
+ }
+ }
+ }
+ }
+
+ return false
+}
+
func (cmd *Command) hideHelp() bool {
tracef("hide help (cmd=%[1]q)", cmd.Name)
for c := cmd; c != nil; c = c.parent {
@@ -189,6 +229,17 @@ func (cmd *Command) hideHelp() bool {
return false
}
+func (cmd *Command) hideHelpCommand() bool {
+ tracef("hide help command (cmd=%[1]q)", cmd.Name)
+ for c := cmd; c != nil; c = c.parent {
+ if c.HideHelpCommand {
+ return true
+ }
+ }
+
+ return false
+}
+
func (cmd *Command) ensureHelp() {
tracef("ensuring help (cmd=%[1]q)", cmd.Name)
@@ -196,7 +247,7 @@ func (cmd *Command) ensureHelp() {
if !cmd.hideHelp() {
if cmd.Command(helpCommand.Name) == nil {
- if !cmd.HideHelpCommand {
+ if !cmd.hideHelpCommand() {
tracef("appending helpCommand (cmd=%[1]q)", cmd.Name)
cmd.appendCommand(helpCommand)
}
@@ -221,3 +272,31 @@ func (cmd *Command) ensureHelp() {
}
}
}
+
+// dropClashingAliases removes aliases from `aliases` that are already
+// claimed by a flag in `userFlags` (either as a primary name or as one
+// of its own aliases). Aliases equal to `selfName` are kept so the
+// flag's primary name doesn't accidentally remove itself.
+func dropClashingAliases(aliases []string, userFlags []Flag, selfName string) []string {
+ if len(aliases) == 0 || len(userFlags) == 0 {
+ return aliases
+ }
+ taken := map[string]struct{}{}
+ for _, f := range userFlags {
+ for _, n := range f.Names() {
+ taken[n] = struct{}{}
+ }
+ }
+ kept := aliases[:0:0]
+ for _, a := range aliases {
+ if a == selfName {
+ kept = append(kept, a)
+ continue
+ }
+ if _, ok := taken[a]; ok {
+ continue
+ }
+ kept = append(kept, a)
+ }
+ return kept
+}
diff --git a/vendor/github.com/urfave/cli/v3/completion.go b/vendor/github.com/urfave/cli/v3/completion.go
index de11edb..b78dc38 100644
--- a/vendor/github.com/urfave/cli/v3/completion.go
+++ b/vendor/github.com/urfave/cli/v3/completion.go
@@ -4,7 +4,6 @@ import (
"context"
"embed"
"fmt"
- "sort"
"strings"
)
@@ -21,6 +20,12 @@ var (
//go:embed autocomplete
autoCompleteFS embed.FS
+ // completionShells defines the order in which the shell completion
+ // subcommands appear in help output. Iterating shellCompletions directly
+ // would use Go's randomized map order, making the listing nondeterministic.
+ // Keep this in sync with shellCompletions.
+ completionShells = []string{"bash", "zsh", "fish", "pwsh"}
+
shellCompletions = map[string]renderCompletion{
"bash": func(c *Command, appName string) (string, error) {
b, err := autoCompleteFS.ReadFile("autocomplete/bash_autocomplete")
@@ -54,49 +59,40 @@ source <($COMMAND completion zsh)
$COMMAND completion fish > ~/.config/fish/completions/$COMMAND.fish
# Powershell
-Output the script to path/to/autocomplete/$COMMAND.ps1 an run it.
+Output the script to path/to/autocomplete/$COMMAND.ps1 and run it.
`
func buildCompletionCommand(appName string) *Command {
- return &Command{
- Name: completionCommandName,
- Hidden: true,
- Usage: "Output shell completion script for bash, zsh, fish, or Powershell",
- Description: strings.ReplaceAll(completionDescription, "$COMMAND", appName),
- Action: func(ctx context.Context, cmd *Command) error {
- return printShellCompletion(ctx, cmd, appName)
- },
+ cmd := &Command{
+ Name: completionCommandName,
+ Hidden: true,
+ Usage: "Output shell completion script for bash, zsh, fish, or Powershell",
+ Description: strings.ReplaceAll(completionDescription, "$COMMAND", appName),
isCompletionCommand: true,
}
-}
-func printShellCompletion(_ context.Context, cmd *Command, appName string) error {
- var shells []string
- for k := range shellCompletions {
- shells = append(shells, k)
+ for _, shell := range completionShells {
+ cmd.Commands = append(cmd.Commands, buildShellCompletionSubcommand(shell, shellCompletions[shell], appName))
}
- sort.Strings(shells)
-
- if cmd.Args().Len() == 0 {
- return Exit(fmt.Sprintf("no shell provided for completion command. available shells are %+v", shells), 1)
- }
- s := cmd.Args().First()
-
- renderCompletion, ok := shellCompletions[s]
- if !ok {
- return Exit(fmt.Sprintf("unknown shell %s, available shells are %+v", s, shells), 1)
- }
-
- completionScript, err := renderCompletion(cmd, appName)
- if err != nil {
- return Exit(err, 1)
- }
+ return cmd
+}
- _, err = cmd.Writer.Write([]byte(completionScript))
- if err != nil {
- return Exit(err, 1)
+func buildShellCompletionSubcommand(shell string, render renderCompletion, appName string) *Command {
+ return &Command{
+ Name: shell,
+ Usage: fmt.Sprintf("Output %s completion script", shell),
+ isCompletionCommand: true,
+ Action: func(ctx context.Context, cmd *Command) error {
+ completionScript, err := render(cmd, appName)
+ if err != nil {
+ return Exit(err, 1)
+ }
+ _, err = cmd.Root().Writer.Write([]byte(completionScript))
+ if err != nil {
+ return Exit(err, 1)
+ }
+ return nil
+ },
}
-
- return nil
}
diff --git a/vendor/github.com/urfave/cli/v3/docs.go b/vendor/github.com/urfave/cli/v3/docs.go
index 8846138..30c053c 100644
--- a/vendor/github.com/urfave/cli/v3/docs.go
+++ b/vendor/github.com/urfave/cli/v3/docs.go
@@ -5,10 +5,11 @@ import (
"os"
"runtime"
"strings"
+ "unicode/utf8"
)
func prefixFor(name string) (prefix string) {
- if len(name) == 1 {
+ if utf8.RuneCountInString(name) == 1 {
prefix = "-"
} else {
prefix = "--"
diff --git a/vendor/github.com/urfave/cli/v3/errors.go b/vendor/github.com/urfave/cli/v3/errors.go
index ffd6471..ff0dfa5 100644
--- a/vendor/github.com/urfave/cli/v3/errors.go
+++ b/vendor/github.com/urfave/cli/v3/errors.go
@@ -61,6 +61,22 @@ func (e *errRequiredFlags) Error() string {
return fmt.Sprintf("Required flags %q not set", joinedMissingFlags)
}
+type requiredArgumentsErr interface {
+ error
+}
+
+type errRequiredArguments struct {
+ missingArguments []string
+}
+
+func (e *errRequiredArguments) Error() string {
+ if len(e.missingArguments) == 1 {
+ return fmt.Sprintf("Required argument %q not set", e.missingArguments[0])
+ }
+ joinedMissingArguments := strings.Join(e.missingArguments, ", ")
+ return fmt.Sprintf("Required arguments %q not set", joinedMissingArguments)
+}
+
type mutuallyExclusiveGroup struct {
flag1Name string
flag2Name string
diff --git a/vendor/github.com/urfave/cli/v3/fish.go b/vendor/github.com/urfave/cli/v3/fish.go
index 8002a33..1fac34a 100644
--- a/vendor/github.com/urfave/cli/v3/fish.go
+++ b/vendor/github.com/urfave/cli/v3/fish.go
@@ -216,6 +216,15 @@ func commandAncestry(command *Command) string {
return strings.Join(ancestry, "; and ")
}
+// escapeSingleQuotes escapes a string for use inside a fish single-quoted
+// string, such as a `-d '...'` description. Within single quotes fish only
+// recognizes the escape sequences \\ and \', so the backslash must be escaped
+// as well as the single quote. Escaping the quote without escaping the
+// backslash corrupts any description that contains a backslash, and a trailing
+// backslash even leaves the single-quoted string unterminated.
+// See https://fishshell.com/docs/current/language.html
func escapeSingleQuotes(input string) string {
- return strings.ReplaceAll(input, `'`, `\'`)
+ return fishSingleQuoteReplacer.Replace(input)
}
+
+var fishSingleQuoteReplacer = strings.NewReplacer(`\`, `\\`, `'`, `\'`)
diff --git a/vendor/github.com/urfave/cli/v3/flag.go b/vendor/github.com/urfave/cli/v3/flag.go
index 1b849f1..f3a9fb5 100644
--- a/vendor/github.com/urfave/cli/v3/flag.go
+++ b/vendor/github.com/urfave/cli/v3/flag.go
@@ -118,6 +118,13 @@ type RequiredFlag interface {
IsRequired() bool
}
+// DeprecatedFlag is an interface that allows us to mark flags as deprecated
+type DeprecatedFlag interface {
+ // GetDeprecated returns the deprecation message, or an empty string
+ // if the flag is not deprecated
+ GetDeprecated() string
+}
+
// DocGenerationFlag is an interface that allows documentation generation for the flag
type DocGenerationFlag interface {
// TakesValue returns true if the flag takes a value, otherwise false
@@ -151,6 +158,23 @@ type DocGenerationMultiValueFlag interface {
IsMultiValueFlag() bool
}
+// SchemaTyper is an optional interface for flags that can report their
+// JSON Schema type for programmatic introspection.
+type SchemaTyper interface {
+ // SchemaType returns the JSON Schema type name for the value this
+ // flag accepts: "boolean", "integer", "number", "string", "array",
+ // "object". Returns "" if the flag does not map cleanly.
+ SchemaType() string
+}
+
+// SchemaItemsTyper is an optional interface for multi-value flags that
+// can report the JSON Schema type of their elements.
+type SchemaItemsTyper interface {
+ // SchemaItemsType returns the JSON Schema type of elements for
+ // array-type flags. Returns "" for single-value or object flags.
+ SchemaItemsType() string
+}
+
// Countable is an interface to enable detection of flag values which support
// repetitive flags
type Countable interface {
@@ -173,6 +197,18 @@ type CategorizableFlag interface {
SetCategory(string)
}
+// StringerSetter is an optional interface that allows an individual
+// flag to be given a per-flag override of [FlagStringer]. FlagBase and
+// BoolWithInverseFlag implement this. It's used by
+// [MutuallyExclusiveFlags.Stringer] to customize how flags within a
+// mutually exclusive group are displayed in help output.
+type StringerSetter interface {
+ // SetStringer overrides the [FlagStringFunc] used by this flag's
+ // String method. Passing nil restores the default behavior of using
+ // the package-level [FlagStringer].
+ SetStringer(FlagStringFunc)
+}
+
// LocalFlag is an interface to enable detection of flags which are local
// to current command
type LocalFlag interface {
diff --git a/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go b/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go
index 8666e2d..c58770e 100644
--- a/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go
+++ b/vendor/github.com/urfave/cli/v3/flag_bool_with_inverse.go
@@ -18,6 +18,7 @@ type BoolWithInverseFlag struct {
Sources ValueSourceChain `json:"-"` // sources to load flag value from
Required bool `json:"required"` // whether the flag is required or not
Hidden bool `json:"hidden"` // whether to hide the flag in help output
+ Deprecated string `json:"deprecated"` // deprecation message, if set a warning is printed when the flag is set
Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well
Value bool `json:"defaultValue"` // default value for this flag if not set by from any source
Destination *bool `json:"-"` // destination pointer for value when set
@@ -37,6 +38,21 @@ type BoolWithInverseFlag struct {
value Value // value representing this flag's value
pset bool
nset bool
+ stringer FlagStringFunc // optional per-flag override of FlagStringer
+}
+
+// SetStringer overrides the [FlagStringFunc] used by this flag's String
+// method. Passing nil restores the default behavior of using the
+// package-level [FlagStringer]. This is used e.g. by
+// [MutuallyExclusiveFlags.Stringer].
+//
+// Note: unlike [FlagBase], BoolWithInverseFlag.String only honors the
+// stringer partially. The names segment (the part before the first tab,
+// e.g. "--[no-]env, -e") is always recomputed from Name/Aliases/InversePrefix
+// and cannot be overridden; only the tab-delimited details after it come
+// from the stringer's output.
+func (bif *BoolWithInverseFlag) SetStringer(s FlagStringFunc) {
+ bif.stringer = s
}
func (bif *BoolWithInverseFlag) IsSet() bool {
@@ -68,10 +84,6 @@ func (bif *BoolWithInverseFlag) inversePrefix() string {
}
func (bif *BoolWithInverseFlag) PreParse() error {
- count := bif.Config.Count
- if count == nil {
- count = &bif.count
- }
dest := bif.Destination
if dest == nil {
dest = new(bool)
@@ -79,7 +91,7 @@ func (bif *BoolWithInverseFlag) PreParse() error {
*dest = bif.Value
bif.value = &boolValue{
destination: dest,
- count: count,
+ count: bif.Config.Count,
}
// Validate the given default or values set from external sources as well
@@ -116,7 +128,7 @@ func (bif *BoolWithInverseFlag) PostParse() error {
func (bif *BoolWithInverseFlag) Set(name, val string) error {
if bif.count > 0 && bif.OnlyOnce {
- return fmt.Errorf("cant duplicate this flag")
+ return fmt.Errorf("can't duplicate this flag")
}
bif.hasBeenSet = true
@@ -138,6 +150,7 @@ func (bif *BoolWithInverseFlag) Set(name, val string) error {
}
bif.nset = true
}
+ bif.count++
if bif.Validator != nil {
return bif.Validator(bif.value.Get().(bool))
@@ -171,7 +184,11 @@ func (bif *BoolWithInverseFlag) IsVisible() bool {
// Example for BoolFlag{Name: "env", Aliases: []string{"e"}}
// --[no-]env, -e (default: false)
func (bif *BoolWithInverseFlag) String() string {
- out := FlagStringer(bif)
+ fs := FlagStringer
+ if bif.stringer != nil {
+ fs = bif.stringer
+ }
+ out := fs(bif)
i := strings.Index(out, "\t")
@@ -207,7 +224,7 @@ func (bif *BoolWithInverseFlag) String() string {
return fmt.Sprintf("%s%s", names, out[i:])
}
-// IsBoolFlag returns whether the flag doesnt need to accept args
+// IsBoolFlag returns whether the flag doesn't need to accept args
func (bif *BoolWithInverseFlag) IsBoolFlag() bool {
return true
}
@@ -219,12 +236,17 @@ func (bif *BoolWithInverseFlag) Count() int {
// GetDefaultText returns the default text for this flag
func (bif *BoolWithInverseFlag) GetDefaultText() string {
- if bif.Required {
+ if bif.DefaultText != "" {
return bif.DefaultText
}
return boolValue{}.ToString(bif.Value)
}
+// GetDeprecated returns the deprecation message of the flag
+func (bif *BoolWithInverseFlag) GetDeprecated() string {
+ return bif.Deprecated
+}
+
// GetCategory returns the category of the flag
func (bif *BoolWithInverseFlag) GetCategory() string {
return bif.Category
@@ -263,3 +285,11 @@ func (bif *BoolWithInverseFlag) IsDefaultVisible() bool {
func (bif *BoolWithInverseFlag) TypeName() string {
return "bool"
}
+
+func (bif *BoolWithInverseFlag) SchemaType() string {
+ return "boolean"
+}
+
+func (bif *BoolWithInverseFlag) SchemaItemsType() string {
+ return ""
+}
diff --git a/vendor/github.com/urfave/cli/v3/flag_ext.go b/vendor/github.com/urfave/cli/v3/flag_ext.go
index 9972af7..3fb01f2 100644
--- a/vendor/github.com/urfave/cli/v3/flag_ext.go
+++ b/vendor/github.com/urfave/cli/v3/flag_ext.go
@@ -1,6 +1,9 @@
package cli
-import "flag"
+import (
+ "flag"
+ "time"
+)
type extFlag struct {
f *flag.Flag
@@ -61,3 +64,26 @@ func (e *extFlag) GetDefaultText() string {
func (e *extFlag) GetEnvVars() []string {
return nil
}
+
+func (e *extFlag) SchemaType() string {
+ switch e.Get().(type) {
+ case bool:
+ return "boolean"
+ case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+ return "integer"
+ case float32, float64:
+ return "number"
+ case string:
+ return "string"
+ case time.Duration:
+ return "duration"
+ case time.Time:
+ return "date-time"
+ default:
+ return ""
+ }
+}
+
+func (e *extFlag) SchemaItemsType() string {
+ return ""
+}
diff --git a/vendor/github.com/urfave/cli/v3/flag_impl.go b/vendor/github.com/urfave/cli/v3/flag_impl.go
index 1ca295a..beea601 100644
--- a/vendor/github.com/urfave/cli/v3/flag_impl.go
+++ b/vendor/github.com/urfave/cli/v3/flag_impl.go
@@ -6,6 +6,7 @@ import (
"fmt"
"reflect"
"strings"
+ "time"
)
// Value represents a value as used by cli.
@@ -62,6 +63,7 @@ type FlagBase[T any, C any, VC ValueCreator[T, C]] struct {
Sources ValueSourceChain `json:"-"` // sources to load flag value from
Required bool `json:"required"` // whether the flag is required or not
Hidden bool `json:"hidden"` // whether to hide the flag in help output
+ Deprecated string `json:"deprecated"` // deprecation message, if set a warning is printed when the flag is set
Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well
Value T `json:"defaultValue"` // default value for this flag if not set by from any source
Destination *T `json:"-"` // destination pointer for value when set
@@ -74,11 +76,12 @@ type FlagBase[T any, C any, VC ValueCreator[T, C]] struct {
ValidateDefaults bool `json:"validateDefaults"` // whether to validate defaults or not
// unexported fields for internal use
- count int // number of times the flag has been set
- hasBeenSet bool // whether the flag has been set from env or file
- applied bool // whether the flag has been applied to a flag set already
- creator VC // value creator for this flag type
- value Value // value representing this flag's value
+ count int // number of times the flag has been set
+ hasBeenSet bool // whether the flag has been set from env or file
+ applied bool // whether the flag has been applied to a flag set already
+ creator VC // value creator for this flag type
+ value Value // value representing this flag's value
+ stringer FlagStringFunc // optional per-flag override of FlagStringer
}
// GetValue returns the flags value as string representation and an empty
@@ -130,14 +133,22 @@ func (f *FlagBase[T, C, V]) PostParse() error {
if !f.hasBeenSet {
if val, source, found := f.Sources.LookupWithSource(); found {
- if val != "" || reflect.TypeOf(f.Value).Kind() == reflect.String {
+ // reflect.TypeOf yields nil when T is an interface type (e.g.
+ // GenericFlag) and the value is nil, so the kind has to be
+ // derived defensively.
+ kind := reflect.Invalid
+ if ty := reflect.TypeOf(f.Value); ty != nil {
+ kind = ty.Kind()
+ }
+
+ if val != "" || kind == reflect.String {
if err := f.Set(f.Name, val); err != nil {
return fmt.Errorf(
"could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s",
val, f.Value, source, f.Name, err,
)
}
- } else if val == "" && reflect.TypeOf(f.Value).Kind() == reflect.Bool {
+ } else if val == "" && kind == reflect.Bool {
_ = f.Set(f.Name, "false")
}
@@ -193,7 +204,7 @@ func (f *FlagBase[T, C, V]) Set(_ string, val string) error {
}
if f.count == 1 && f.OnlyOnce {
- return fmt.Errorf("cant duplicate this flag")
+ return fmt.Errorf("can't duplicate this flag")
}
f.count++
@@ -223,9 +234,20 @@ func (f *FlagBase[T, C, V]) IsDefaultVisible() bool {
// String returns a readable representation of this value (for usage defaults)
func (f *FlagBase[T, C, V]) String() string {
+ if f.stringer != nil {
+ return f.stringer(f)
+ }
return FlagStringer(f)
}
+// SetStringer overrides the [FlagStringFunc] used by this flag's String
+// method. Passing nil restores the default behavior of using the
+// package-level [FlagStringer]. This is used e.g. by
+// [MutuallyExclusiveFlags.Stringer].
+func (f *FlagBase[T, C, V]) SetStringer(s FlagStringFunc) {
+ f.stringer = s
+}
+
// IsSet returns whether or not the flag has been set through env or file
func (f *FlagBase[T, C, V]) IsSet() bool {
return f.hasBeenSet
@@ -246,6 +268,11 @@ func (f *FlagBase[T, C, V]) IsVisible() bool {
return !f.Hidden
}
+// GetDeprecated returns the deprecation message of the flag
+func (f *FlagBase[T, C, V]) GetDeprecated() string {
+ return f.Deprecated
+}
+
// GetCategory returns the category of the flag
func (f *FlagBase[T, C, V]) GetCategory() string {
return f.Category
@@ -285,6 +312,53 @@ func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error {
return nil
}
+// SchemaType returns the JSON Schema type for the flag's value type.
+func (f *FlagBase[T, C, V]) SchemaType() string {
+ var zero T
+ switch any(zero).(type) {
+ case bool:
+ return "boolean"
+ case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+ return "integer"
+ case float32, float64:
+ return "number"
+ case string:
+ return "string"
+ case time.Duration:
+ return "duration"
+ case time.Time:
+ return "date-time"
+ case []string, []int, []int8, []int16, []int32, []int64,
+ []uint, []uint8, []uint16, []uint32, []uint64,
+ []float32, []float64:
+ return "array"
+ case map[string]string:
+ return "object"
+ default:
+ return ""
+ }
+}
+
+// SchemaItemsType returns the JSON Schema element type for slice flags.
+func (f *FlagBase[T, C, V]) SchemaItemsType() string {
+ var zero T
+ // reflect.TypeOf yields nil when T is an interface type (e.g. GenericFlag),
+ // in which case there are no slice elements to describe.
+ t := reflect.TypeOf(zero)
+ if t != nil && t.Kind() == reflect.Slice {
+ switch t.Elem().Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return "integer"
+ case reflect.Float32, reflect.Float64:
+ return "number"
+ case reflect.String:
+ return "string"
+ }
+ }
+ return ""
+}
+
// IsMultiValueFlag returns true if the value type T can take multiple
// values from cmd line. This is true for slice and map type flags
func (f *FlagBase[T, C, VC]) IsMultiValueFlag() bool {
@@ -301,7 +375,7 @@ func (f *FlagBase[T, C, VC]) IsLocal() bool {
return f.Local
}
-// IsBoolFlag returns whether the flag doesnt need to accept args
+// IsBoolFlag returns whether the flag doesn't need to accept args
func (f *FlagBase[T, C, VC]) IsBoolFlag() bool {
bf, ok := f.value.(boolFlag)
return ok && bf.IsBoolFlag()
diff --git a/vendor/github.com/urfave/cli/v3/flag_map_impl.go b/vendor/github.com/urfave/cli/v3/flag_map_impl.go
index cb65903..dfe8f09 100644
--- a/vendor/github.com/urfave/cli/v3/flag_map_impl.go
+++ b/vendor/github.com/urfave/cli/v3/flag_map_impl.go
@@ -13,6 +13,7 @@ type MapBase[T any, C any, VC ValueCreator[T, C]] struct {
dict *map[string]T
hasBeenSet bool
value Value
+ trimKeySpace bool
multiValueConfig multiValueParsingConfig
}
@@ -24,9 +25,16 @@ func (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C) Value
var t T
np := new(T)
var vc VC
+ // The key is always a string, so it answers to StringConfig.TrimSpace just
+ // like the value does.
+ trimKeySpace := false
+ if sc, ok := any(c).(StringConfig); ok {
+ trimKeySpace = sc.TrimSpace
+ }
return &MapBase[T, C, VC]{
- dict: p,
- value: vc.Create(t, np, c),
+ dict: p,
+ value: vc.Create(t, np, c),
+ trimKeySpace: trimKeySpace,
}
}
@@ -81,6 +89,9 @@ func (i *MapBase[T, C, VC]) Set(value string) error {
if !ok {
return fmt.Errorf("item %q is missing separator %q", item, keyValueSeparator)
}
+ if i.trimKeySpace {
+ key = strings.TrimSpace(key)
+ }
if err := i.value.Set(value); err != nil {
return err
}
diff --git a/vendor/github.com/urfave/cli/v3/flag_mutex.go b/vendor/github.com/urfave/cli/v3/flag_mutex.go
index 247bcb5..bd01698 100644
--- a/vendor/github.com/urfave/cli/v3/flag_mutex.go
+++ b/vendor/github.com/urfave/cli/v3/flag_mutex.go
@@ -14,35 +14,63 @@ type MutuallyExclusiveFlags struct {
// Category to apply to all flags within group
Category string
+
+ // Stringer overrides how each flag within this group is displayed in
+ // help output. If nil, flags use [FlagStringer] as usual.
+ //
+ // The returned string must be unique per flag within the group (the
+ // default [stringifyFlag] guarantees this by embedding the flag's
+ // name). Help rendering keys flags by their String() output
+ // (flagCategories.AddFlag), so a Stringer that returns identical text
+ // for two or more flags in the same category will cause the later
+ // flag to silently overwrite the earlier one in help output.
+ Stringer FlagStringFunc `json:"-"`
}
func (grp MutuallyExclusiveFlags) check(_ *Command) error {
- oneSet := false
e := &mutuallyExclusiveGroup{}
- for _, grpf := range grp.Flags {
- for _, f := range grpf {
- if f.IsSet() {
- if oneSet {
- e.flag2Name = f.Names()[0]
- return e
- }
- e.flag1Name = f.Names()[0]
- oneSet = true
- break
- }
- if oneSet {
- break
- }
+ // Check for the use of a mutually-exclusive flag, starting at
+ // the first group.
+ name, i, ok := grp.findSetFlag(0)
+ if ok {
+ e.flag1Name = name
+ i++
+
+ // Check for the use of a flag in a mutually exclusive
+ // relationship with the one we just found.
+ if name2, _, ok := grp.findSetFlag(i); ok {
+ e.flag2Name = name2
+ return e
}
}
- if !oneSet && grp.Required {
+ if !ok && grp.Required {
return &mutuallyExclusiveGroupRequiredFlag{flags: &grp}
}
+
return nil
}
+// findSetFlag is used in [MutuallyExclusiveFlags.check] to find
+// whether at least one flag inside a mutually exclusive flag group is
+// set. If so, return the flag name, position at which it's set, and
+// Boolean true (indicating that a flag was found.) Else, return all
+// zero values.
+func (grp MutuallyExclusiveFlags) findSetFlag(startIdx int) (string, int, bool) {
+ for i := startIdx; i < len(grp.Flags); i++ {
+ flags := grp.Flags[i]
+
+ for _, flg := range flags {
+ if flg.IsSet() {
+ return flg.Names()[0], i, true
+ }
+ }
+ }
+
+ return "", 0, false
+}
+
func (grp MutuallyExclusiveFlags) propagateCategory() {
for _, grpf := range grp.Flags {
for _, f := range grpf {
@@ -52,3 +80,22 @@ func (grp MutuallyExclusiveFlags) propagateCategory() {
}
}
}
+
+// propagateStringer applies [MutuallyExclusiveFlags.Stringer], if set, to
+// every flag within the group that supports a [StringerSetter]. Like
+// [MutuallyExclusiveFlags.propagateCategory], this only runs during command
+// setup, so mutating Stringer between runs of a reused [Command] will not
+// re-propagate the change.
+func (grp MutuallyExclusiveFlags) propagateStringer() {
+ if grp.Stringer == nil {
+ return
+ }
+
+ for _, grpf := range grp.Flags {
+ for _, f := range grpf {
+ if sf, ok := f.(StringerSetter); ok {
+ sf.SetStringer(grp.Stringer)
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/urfave/cli/v3/flag_text.go b/vendor/github.com/urfave/cli/v3/flag_text.go
new file mode 100644
index 0000000..a1cc2c3
--- /dev/null
+++ b/vendor/github.com/urfave/cli/v3/flag_text.go
@@ -0,0 +1,86 @@
+package cli
+
+import (
+ "encoding"
+ "strings"
+)
+
+// TextMarshalUnmarshaler is the interface implemented by types that can marshal
+// themselves to and from a textual form. It is the value type used by TextFlag,
+// mirroring the standard library's flag.TextVar, and is satisfied by types such
+// as *slog.LevelVar, *net/netip.Addr, and *time.Time.
+type TextMarshalUnmarshaler interface {
+ encoding.TextMarshaler
+ encoding.TextUnmarshaler
+}
+
+type TextFlag = FlagBase[TextMarshalUnmarshaler, StringConfig, textValue]
+
+// -- TextMarshalUnmarshaler Value
+type textValue struct {
+ destination TextMarshalUnmarshaler
+ trimSpace bool
+}
+
+// Below functions are to satisfy the ValueCreator interface
+
+func (t textValue) Create(val TextMarshalUnmarshaler, p *TextMarshalUnmarshaler, c StringConfig) Value {
+ // Only overwrite the target when a non-nil default value is given, so that
+ // a Destination pointing at an existing target is preserved (unlike the
+ // concrete flag types, T here is an interface whose nil default would
+ // otherwise clobber the destination).
+ if val != nil {
+ *p = val
+ }
+ return &textValue{
+ destination: *p,
+ trimSpace: c.TrimSpace,
+ }
+}
+
+func (t textValue) ToString(val TextMarshalUnmarshaler) string {
+ if val == nil {
+ return ""
+ }
+ text, err := val.MarshalText()
+ if err != nil {
+ return ""
+ }
+ return string(text)
+}
+
+// Below functions are to satisfy the flag.Value interface
+
+func (t *textValue) Set(val string) error {
+ if t.destination == nil {
+ return nil
+ }
+ if t.trimSpace {
+ val = strings.TrimSpace(val)
+ }
+ return t.destination.UnmarshalText([]byte(val))
+}
+
+func (t *textValue) Get() any { return t.destination }
+
+func (t *textValue) String() string {
+ if t.destination == nil {
+ return ""
+ }
+ text, err := t.destination.MarshalText()
+ if err != nil {
+ return ""
+ }
+ return string(text)
+}
+
+// Text looks up the value of a local TextFlag, returns nil if not found
+func (cmd *Command) Text(name string) TextMarshalUnmarshaler {
+ if v, ok := cmd.Value(name).(TextMarshalUnmarshaler); ok {
+ tracef("text available for flag name %[1]q with value=%[2]v (cmd=%[3]q)", name, v, cmd.Name)
+ return v
+ }
+
+ tracef("text NOT available for flag name %[1]q (cmd=%[2]q)", name, cmd.Name)
+ return nil
+}
diff --git a/vendor/github.com/urfave/cli/v3/flag_timestamp.go b/vendor/github.com/urfave/cli/v3/flag_timestamp.go
index 82b1cb5..83723e6 100644
--- a/vendor/github.com/urfave/cli/v3/flag_timestamp.go
+++ b/vendor/github.com/urfave/cli/v3/flag_timestamp.go
@@ -63,6 +63,7 @@ func (t *timestampValue) Set(value string) error {
return errors.New("got nil/empty layouts slice")
}
+ matchedLayout := ""
for _, layout := range t.layouts {
var locErr error
@@ -78,6 +79,7 @@ func (t *timestampValue) Set(value string) error {
}
err = nil
+ matchedLayout = layout
break
}
@@ -90,7 +92,8 @@ func (t *timestampValue) Set(value string) error {
n := time.Now().In(timestamp.Location())
// If format is missing date (or year only), set it explicitly to current
- if timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() {
+ // A layout that carries a date parses "January 1" to the same instant a date-less layout does, so ask the layout.
+ if !layoutHasDate(matchedLayout) && timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() {
timestamp = time.Date(
n.Year(),
n.Month(),
@@ -121,6 +124,14 @@ func (t *timestampValue) Set(value string) error {
return nil
}
+// layoutHasDate reports whether layout carries month/day components, probed by
+// round-tripping a reference date that is not January 1.
+func layoutHasDate(layout string) bool {
+ ref := time.Date(2, time.March, 4, 5, 6, 7, 0, time.UTC)
+ p, err := time.Parse(layout, ref.Format(layout))
+ return err == nil && (p.Month() != time.January || p.Day() != 1)
+}
+
// String returns a readable representation of this value (for usage defaults)
func (t *timestampValue) String() string {
return fmt.Sprintf("%v", t.timestamp)
diff --git a/vendor/github.com/urfave/cli/v3/funcs.go b/vendor/github.com/urfave/cli/v3/funcs.go
index fe1224c..17a73ec 100644
--- a/vendor/github.com/urfave/cli/v3/funcs.go
+++ b/vendor/github.com/urfave/cli/v3/funcs.go
@@ -17,6 +17,13 @@ type AfterFunc func(context.Context, *Command) error
// ActionFunc is the action to execute when no subcommands are specified
type ActionFunc func(context.Context, *Command) error
+// ArgValidatorFunc is an action to validate arguments before the command is run.
+// If non-nil, it is called before the command's After and Action functions.
+// Returning a non-nil error short-circuits the command and propagates as
+// the exit error. If the current command does not set ArgValidator, the
+// nearest ancestor that does is used instead.
+type ArgValidatorFunc func(context.Context, *Command) error
+
// CommandNotFoundFunc is executed if the proper command cannot be found
type CommandNotFoundFunc func(context.Context, *Command, string)
diff --git a/vendor/github.com/urfave/cli/v3/godoc-current.txt b/vendor/github.com/urfave/cli/v3/godoc-current.txt
index 1e163a0..ce70dbc 100644
--- a/vendor/github.com/urfave/cli/v3/godoc-current.txt
+++ b/vendor/github.com/urfave/cli/v3/godoc-current.txt
@@ -170,7 +170,9 @@ COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategori
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
-OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}
+OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .VisiblePersistentFlags}}
+
+GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}}
`
SubcommandHelpTemplate is the text template for the subcommand help topic.
cli.go uses text/template to render templates. You can render custom help
@@ -256,6 +258,13 @@ type AfterFunc func(context.Context, *Command) error
AfterFunc is an action that executes after any subcommands are run and have
finished. The AfterFunc is run even if Action() panics.
+type ArgValidatorFunc func(context.Context, *Command) error
+ ArgValidatorFunc is an action to validate arguments before the command
+ is run. If non-nil, it is called before the command's After and Action
+ functions. Returning a non-nil error short-circuits the command and
+ propagates as the exit error. If the current command does not set
+ ArgValidator, the nearest ancestor that does is used instead.
+
type Args interface {
// Get returns the nth argument, or else a blank string
Get(n int) string
@@ -292,6 +301,7 @@ type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct {
Value T `json:"value"` // the default value of this argument
Destination *T `json:"-"` // the destination point for this argument
UsageText string `json:"usageText"` // the usage text to show
+ Required bool `json:"required"` // whether the argument is required or not
Config C `json:"config"` // config for this argument similar to Flag Config
// Has unexported fields.
@@ -347,6 +357,7 @@ type BoolWithInverseFlag struct {
Sources ValueSourceChain `json:"-"` // sources to load flag value from
Required bool `json:"required"` // whether the flag is required or not
Hidden bool `json:"hidden"` // whether to hide the flag in help output
+ Deprecated string `json:"deprecated"` // deprecation message, if set a warning is printed when the flag is set
Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well
Value bool `json:"defaultValue"` // default value for this flag if not set by from any source
Destination *bool `json:"-"` // destination pointer for value when set
@@ -373,6 +384,9 @@ func (bif *BoolWithInverseFlag) GetCategory() string
func (bif *BoolWithInverseFlag) GetDefaultText() string
GetDefaultText returns the default text for this flag
+func (bif *BoolWithInverseFlag) GetDeprecated() string
+ GetDeprecated returns the deprecation message of the flag
+
func (bif *BoolWithInverseFlag) GetEnvVars() []string
GetEnvVars returns the env vars for this flag
@@ -384,7 +398,7 @@ func (bif *BoolWithInverseFlag) GetValue() string
string if the flag takes no value at all.
func (bif *BoolWithInverseFlag) IsBoolFlag() bool
- IsBoolFlag returns whether the flag doesnt need to accept args
+ IsBoolFlag returns whether the flag doesn't need to accept args
func (bif *BoolWithInverseFlag) IsDefaultVisible() bool
IsDefaultVisible returns true if the flag is not hidden, otherwise false
@@ -405,10 +419,25 @@ func (bif *BoolWithInverseFlag) PreParse() error
func (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error
+func (bif *BoolWithInverseFlag) SchemaItemsType() string
+
+func (bif *BoolWithInverseFlag) SchemaType() string
+
func (bif *BoolWithInverseFlag) Set(name, val string) error
func (bif *BoolWithInverseFlag) SetCategory(c string)
+func (bif *BoolWithInverseFlag) SetStringer(s FlagStringFunc)
+ SetStringer overrides the FlagStringFunc used by this flag's String method.
+ Passing nil restores the default behavior of using the package-level
+ FlagStringer. This is used e.g. by MutuallyExclusiveFlags.Stringer.
+
+ Note: unlike FlagBase, BoolWithInverseFlag.String only honors the
+ stringer partially. The names segment (the part before the first tab, e.g.
+ "--[no-]env, -e") is always recomputed from Name/Aliases/InversePrefix and
+ cannot be overridden; only the tab-delimited details after it come from the
+ stringer's output.
+
func (bif *BoolWithInverseFlag) String() string
String implements the standard Stringer interface.
@@ -458,6 +487,9 @@ type Command struct {
Flags []Flag `json:"flags"`
// Boolean to hide built-in help command and help flag
HideHelp bool `json:"hideHelp"`
+ // Boolean to hide the built-in help command. Applies to this command and
+ // all of its subcommands: as with HideHelp, a true value is inherited and
+ // a subcommand cannot turn it back off.
// Ignored if HideHelp is true.
HideHelpCommand bool `json:"hideHelpCommand"`
// Boolean to hide built-in version flag and the VERSION section of help
@@ -476,6 +508,11 @@ type Command struct {
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After AfterFunc `json:"-"`
+ // An action to validate arguments before the command is run. If non-nil, it
+ // is called before Before and Action. If the current command does not set
+ // ArgValidator, the nearest ancestor that does is used instead.
+ // Returning a non-nil error short-circuits the command.
+ ArgValidator ArgValidatorFunc `json:"-"`
// The function to call when this command is invoked
Action ActionFunc `json:"-"`
// Execute this function if the proper command cannot be found
@@ -486,6 +523,10 @@ type Command struct {
InvalidFlagAccessHandler InvalidFlagAccessFunc `json:"-"`
// Boolean to hide this command from help or completion
Hidden bool `json:"hidden"`
+ // Deprecation message for this command. If non-empty, a warning is
+ // printed to ErrWriter when the command is invoked. Setting it does not
+ // hide the command; set Hidden as well for that.
+ Deprecated string `json:"deprecated"`
// List of all authors who contributed (string or fmt.Stringer)
// TODO: ~string | fmt.Stringer when interface unions are available
Authors []any `json:"authors"`
@@ -558,6 +599,9 @@ type Command struct {
func (cmd *Command) Args() Args
Args returns the command line arguments associated with the command.
+ If the command declares named Arguments, the arguments consumed by them
+ are not included in the returned Args and should be retrieved via the
+ command.{Type}Arg(name) functions instead.
func (cmd *Command) Bool(name string) bool
@@ -606,8 +650,8 @@ func (cmd *Command) FloatSlice(name string) []float64
found
func (cmd *Command) FullName() string
- FullName returns the full name of the command. For commands with parents
- this ensures that the parent commands are part of the command path.
+ FullName returns the full name of the command. Includes parent commands
+ separated by space.
func (cmd *Command) Generic(name string) Value
Generic looks up the value of a local GenericFlag, returns nil if not found
@@ -689,6 +733,12 @@ func (cmd *Command) Names() []string
func (cmd *Command) NumFlags() int
NumFlags returns the number of flags set
+func (cmd *Command) Path() []string
+ Path returns the path of command names from the root to cmd, inclusive.
+ Each element is a Command.Name. Path traverses upward via parent pointers
+ similar to Lineage. FullName() is equivalent to strings.Join(cmd.Path(),
+ " ").
+
func (cmd *Command) Root() *Command
Root returns the Command at the root of the graph
@@ -714,6 +764,9 @@ func (cmd *Command) StringSlice(name string) []string
StringSlice looks up the value of a local StringSliceFlag, returns nil if
not found
+func (cmd *Command) Text(name string) TextMarshalUnmarshaler
+ Text looks up the value of a local TextFlag, returns nil if not found
+
func (cmd *Command) Timestamp(name string) time.Time
Timestamp gets the timestamp from a flag name
@@ -801,6 +854,10 @@ func (cmd *Command) VisiblePersistentFlags() []Flag
VisiblePersistentFlags returns a slice of LocalFlag with Persistent=true and
Hidden=false.
+func (cmd *Command) Walk(fn func(*Command) error) error
+ Walk visits cmd and every descendant. If fn returns a non-nil error,
+ the walk terminates and the error is returned to the caller.
+
type CommandCategories interface {
// AddCommand adds a command to a category, creating a new category if necessary.
AddCommand(category string, command *Command)
@@ -830,6 +887,13 @@ type Countable interface {
Countable is an interface to enable detection of flag values which support
repetitive flags
+type DeprecatedFlag interface {
+ // GetDeprecated returns the deprecation message, or an empty string
+ // if the flag is not deprecated
+ GetDeprecated() string
+}
+ DeprecatedFlag is an interface that allows us to mark flags as deprecated
+
type DocGenerationFlag interface {
// TakesValue returns true if the flag takes a value, otherwise false
TakesValue() bool
@@ -958,6 +1022,7 @@ type FlagBase[T any, C any, VC ValueCreator[T, C]] struct {
Sources ValueSourceChain `json:"-"` // sources to load flag value from
Required bool `json:"required"` // whether the flag is required or not
Hidden bool `json:"hidden"` // whether to hide the flag in help output
+ Deprecated string `json:"deprecated"` // deprecation message, if set a warning is printed when the flag is set
Local bool `json:"local"` // whether the flag needs to be applied to subcommands as well
Value T `json:"defaultValue"` // default value for this flag if not set by from any source
Destination *T `json:"-"` // destination pointer for value when set
@@ -989,6 +1054,9 @@ func (f *FlagBase[T, C, V]) GetCategory() string
func (f *FlagBase[T, C, V]) GetDefaultText() string
GetDefaultText returns the default text for this flag
+func (f *FlagBase[T, C, V]) GetDeprecated() string
+ GetDeprecated returns the deprecation message of the flag
+
func (f *FlagBase[T, C, V]) GetEnvVars() []string
GetEnvVars returns the env vars for this flag
@@ -1000,7 +1068,7 @@ func (f *FlagBase[T, C, V]) GetValue() string
string if the flag takes no value at all.
func (f *FlagBase[T, C, VC]) IsBoolFlag() bool
- IsBoolFlag returns whether the flag doesnt need to accept args
+ IsBoolFlag returns whether the flag doesn't need to accept args
func (f *FlagBase[T, C, V]) IsDefaultVisible() bool
IsDefaultVisible returns true if the flag is not hidden, otherwise false
@@ -1032,11 +1100,22 @@ func (f *FlagBase[T, C, V]) PreParse() error
func (f *FlagBase[T, C, V]) RunAction(ctx context.Context, cmd *Command) error
RunAction executes flag action if set
+func (f *FlagBase[T, C, V]) SchemaItemsType() string
+ SchemaItemsType returns the JSON Schema element type for slice flags.
+
+func (f *FlagBase[T, C, V]) SchemaType() string
+ SchemaType returns the JSON Schema type for the flag's value type.
+
func (f *FlagBase[T, C, V]) Set(_ string, val string) error
Set applies given value from string
func (f *FlagBase[T, C, V]) SetCategory(c string)
+func (f *FlagBase[T, C, V]) SetStringer(s FlagStringFunc)
+ SetStringer overrides the FlagStringFunc used by this flag's String method.
+ Passing nil restores the default behavior of using the package-level
+ FlagStringer. This is used e.g. by MutuallyExclusiveFlags.Stringer.
+
func (f *FlagBase[T, C, V]) String() string
String returns a readable representation of this value (for usage defaults)
@@ -1274,6 +1353,17 @@ type MutuallyExclusiveFlags struct {
// Category to apply to all flags within group
Category string
+
+ // Stringer overrides how each flag within this group is displayed in
+ // help output. If nil, flags use [FlagStringer] as usual.
+ //
+ // The returned string must be unique per flag within the group (the
+ // default [stringifyFlag] guarantees this by embedding the flag's
+ // name). Help rendering keys flags by their String() output
+ // (flagCategories.AddFlag), so a Stringer that returns identical text
+ // for two or more flags in the same category will cause the later
+ // flag to silently overwrite the earlier one in help output.
+ Stringer FlagStringFunc `json:"-"`
}
MutuallyExclusiveFlags defines a mutually exclusive flag group Multiple
option paths can be provided out of which only one can be defined on cmdline
@@ -1296,6 +1386,23 @@ type RequiredFlag interface {
it allows flags required flags to be backwards compatible with the Flag
interface
+type SchemaItemsTyper interface {
+ // SchemaItemsType returns the JSON Schema type of elements for
+ // array-type flags. Returns "" for single-value or object flags.
+ SchemaItemsType() string
+}
+ SchemaItemsTyper is an optional interface for multi-value flags that can
+ report the JSON Schema type of their elements.
+
+type SchemaTyper interface {
+ // SchemaType returns the JSON Schema type name for the value this
+ // flag accepts: "boolean", "integer", "number", "string", "array",
+ // "object". Returns "" if the flag does not map cleanly.
+ SchemaType() string
+}
+ SchemaTyper is an optional interface for flags that can report their JSON
+ Schema type for programmatic introspection.
+
type Serializer interface {
Serialize() string
}
@@ -1354,10 +1461,32 @@ type StringSlice = SliceBase[string, StringConfig, stringValue]
type StringSliceFlag = FlagBase[[]string, StringConfig, StringSlice]
+type StringerSetter interface {
+ // SetStringer overrides the [FlagStringFunc] used by this flag's
+ // String method. Passing nil restores the default behavior of using
+ // the package-level [FlagStringer].
+ SetStringer(FlagStringFunc)
+}
+ StringerSetter is an optional interface that allows an individual flag to be
+ given a per-flag override of FlagStringer. FlagBase and BoolWithInverseFlag
+ implement this. It's used by MutuallyExclusiveFlags.Stringer to customize
+ how flags within a mutually exclusive group are displayed in help output.
+
type SuggestCommandFunc func(commands []*Command, provided string) string
type SuggestFlagFunc func(flags []Flag, provided string, hideHelp bool) string
+type TextFlag = FlagBase[TextMarshalUnmarshaler, StringConfig, textValue]
+
+type TextMarshalUnmarshaler interface {
+ encoding.TextMarshaler
+ encoding.TextUnmarshaler
+}
+ TextMarshalUnmarshaler is the interface implemented by types that can
+ marshal themselves to and from a textual form. It is the value type used by
+ TextFlag, mirroring the standard library's flag.TextVar, and is satisfied by
+ types such as *slog.LevelVar, *net/netip.Addr, and *time.Time.
+
type TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue]
type TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue]
diff --git a/vendor/github.com/urfave/cli/v3/help.go b/vendor/github.com/urfave/cli/v3/help.go
index 1fba6ed..7a2480e 100644
--- a/vendor/github.com/urfave/cli/v3/help.go
+++ b/vendor/github.com/urfave/cli/v3/help.go
@@ -65,11 +65,12 @@ var ArgsUsageCommandHelp = "[command]"
func buildHelpCommand(withAction bool) *Command {
cmd := &Command{
- Name: helpName,
- Aliases: []string{helpAlias},
- Usage: UsageCommandHelp,
- ArgsUsage: ArgsUsageCommandHelp,
- HideHelp: true,
+ Name: helpName,
+ Aliases: []string{helpAlias},
+ Usage: UsageCommandHelp,
+ ArgsUsage: ArgsUsageCommandHelp,
+ HideHelp: true,
+ builtInHelp: true,
}
if withAction {
@@ -85,14 +86,22 @@ func helpCommandAction(ctx context.Context, cmd *Command) error {
tracef("doing help for cmd %[1]q with args %[2]q", cmd, args)
- // This action can be triggered by a "default" action of a command
- // or via cmd.Run when cmd == helpCmd. So we have following possibilities
+ // helpCommandAction is triggered in several ways:
//
- // 1 $ app
- // 2 $ app help
- // 3 $ app foo
- // 4 $ app help foo
- // 5 $ app foo help
+ // * the command has no user-defined Action (default action fallback)
+ // * the --help / -h flag was parsed (via cmd.checkHelp())
+ // * the "help" subcommand (or "h" alias) was dispatched
+ //
+ // Possible invocations:
+ //
+ // $ app # default action; show root help
+ // $ app --help / -h # flag; show root help (ignores subsequent args)
+ // $ app help / h # subcommand; show root help
+ // $ app help / h foo # subcommand; show help for subcommand "foo"
+ // $ app --help / -h foo # flag; show help for subcommand "foo"
+ // $ app foo --help / -h # flag on subcommand; show help for "foo"
+ // $ app foo help / h # subcommand on subcommand; show help for "foo"
+ // $ app foo (no action) # default action on subcommand; show help for "foo"
// Case 4. when executing a help command set the context to parent
// to allow resolution of subsequent args. This will transform
@@ -100,7 +109,7 @@ func helpCommandAction(ctx context.Context, cmd *Command) error {
// to
// $ app foo
// which will then be handled as case 3
- if cmd.parent != nil && (cmd.HasName(helpName) || cmd.HasName(helpAlias)) {
+ if cmd.parent != nil && cmd.builtInHelp {
tracef("setting cmd to cmd.parent")
cmd = cmd.parent
}
@@ -207,7 +216,7 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
// Trim to handle both "-short" and "--long" flags.
cur := strings.TrimLeft(lastArg, "-")
for _, flag := range flags {
- if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden {
+ if vf, ok := flag.(VisibleFlag); ok && !vf.IsVisible() {
continue
}
@@ -248,12 +257,13 @@ func DefaultCompleteWithFlags(ctx context.Context, cmd *Command) {
}
argsLen := len(args)
lastArg := ""
- // parent command will have --generate-shell-completion so we need
- // to account for that
- if argsLen > 1 {
- lastArg = args[argsLen-2]
- } else if argsLen > 0 {
+ // os.Args retains the completion marker, but a child's parsed arguments
+ // have already had it removed.
+ if argsLen > 0 {
lastArg = args[argsLen-1]
+ if lastArg == completionFlag && argsLen > 1 {
+ lastArg = args[argsLen-2]
+ }
}
if lastArg == completionFlag {
@@ -459,13 +469,7 @@ func DefaultPrintHelp(out io.Writer, templ string, data any) {
}
func checkVersion(cmd *Command) bool {
- found := false
- for _, name := range VersionFlag.Names() {
- if cmd.Bool(name) {
- found = true
- }
- }
- return found
+ return cmd.versionFlag != nil && cmd.versionFlag.IsSet()
}
func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) {
@@ -473,6 +477,10 @@ func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) {
return false, arguments
}
+ if len(arguments) == 0 {
+ return false, arguments
+ }
+
pos := len(arguments) - 1
lastArg := arguments[pos]
@@ -480,19 +488,22 @@ func checkShellCompleteFlag(c *Command, arguments []string) (bool, []string) {
return false, arguments
}
- // If arguments include "--" before the token being completed, shell completion
- // is disabled because after "--" only positional arguments are accepted.
+ // If the token being completed is preceded by a "--", only positional
+ // arguments are accepted after it, so nothing will be suggested.
// https://unix.stackexchange.com/a/11382
// Note: The token being completed is at position pos-1 (immediately before completionFlag).
- // We only check arguments before that position, so completing "--" itself still works.
+ // A "--" at exactly that position is the token being completed, not a
+ // separator, so completing "--" itself still suggests flags.
+ // The request is still recognized as a completion so that the command
+ // action is never executed (https://github.com/urfave/cli/issues/1993).
if pos >= 1 && slices.Contains(arguments[:pos-1], "--") {
- return false, arguments[:pos]
+ c.shellCompletionPastDoubleDash = true
}
return true, arguments[:pos]
}
-func checkCompletions(ctx context.Context, cmd *Command) bool {
+func shouldRunCompletion(cmd *Command) bool {
tracef("checking completions on command %[1]q", cmd.Name)
if !cmd.Root().shellCompletion {
@@ -509,13 +520,21 @@ func checkCompletions(ctx context.Context, cmd *Command) bool {
}
tracef("no subcommand found for completion %[1]q", cmd.Name)
+ return true
+}
+func runCompletion(ctx context.Context, cmd *Command) {
+ // Nothing is suggested past a "--": after it, only positional arguments
+ // are accepted. The request is still treated as a completion so that the
+ // command action is never executed (https://github.com/urfave/cli/issues/1993).
+ if cmd.Root().shellCompletionPastDoubleDash {
+ tracef("completion requested past double dash; suggesting nothing (cmd=%[1]q)", cmd.Name)
+ return
+ }
if cmd.ShellComplete != nil {
tracef("running shell completion func for command %[1]q", cmd.Name)
cmd.ShellComplete(ctx, cmd)
}
-
- return true
}
func subtract(a, b int) int {
diff --git a/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt b/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt
index d7f1b2c..9091cb7 100644
--- a/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt
+++ b/vendor/github.com/urfave/cli/v3/mkdocs-requirements.txt
@@ -1,5 +1,5 @@
-mkdocs-git-revision-date-localized-plugin==1.5.1
-mkdocs-material==9.7.6
+mkdocs-git-revision-date-localized-plugin==1.5.4
+mkdocs-material==9.7.7
mkdocs==1.6.1
mkdocs-redirects==1.2.3
-pygments==2.20.0
+pygments==2.21.0
diff --git a/vendor/github.com/urfave/cli/v3/mkdocs.yml b/vendor/github.com/urfave/cli/v3/mkdocs.yml
index e1eac95..4539a73 100644
--- a/vendor/github.com/urfave/cli/v3/mkdocs.yml
+++ b/vendor/github.com/urfave/cli/v3/mkdocs.yml
@@ -20,6 +20,8 @@ nav:
- v3 Manual:
- Getting Started: v3/getting-started.md
- Migrating From Older Releases: v3/migrating-from-older-releases.md
+ - Path and Walk: v3/path-and-walk.md
+ - Binary Size: v3/binary-size.md
- Examples:
- Greet: v3/examples/greet.md
- Flags:
diff --git a/vendor/github.com/urfave/cli/v3/template.go b/vendor/github.com/urfave/cli/v3/template.go
index dd144e7..92030cc 100644
--- a/vendor/github.com/urfave/cli/v3/template.go
+++ b/vendor/github.com/urfave/cli/v3/template.go
@@ -107,7 +107,9 @@ COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategori
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
-OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}
+OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .VisiblePersistentFlags}}
+
+GLOBAL OPTIONS:{{template "visiblePersistentFlagTemplate" .}}{{end}}
`
var FishCompletionTemplate = `# {{ .Command.Name }} fish shell completion
diff --git a/vendor/github.com/urfave/cli/v3/value_source.go b/vendor/github.com/urfave/cli/v3/value_source.go
index 44b0173..2dcee75 100644
--- a/vendor/github.com/urfave/cli/v3/value_source.go
+++ b/vendor/github.com/urfave/cli/v3/value_source.go
@@ -119,6 +119,7 @@ func (e *envVarValueSource) Key() string {
}
func (e *envVarValueSource) String() string { return fmt.Sprintf("environment variable %[1]q", e.key) }
+
func (e *envVarValueSource) GoString() string {
return fmt.Sprintf("&envVarValueSource{Key:%[1]q}", e.key)
}
diff --git a/vendor/golang.org/x/net/http2/ascii.go b/vendor/golang.org/x/net/http2/ascii.go
index 17caa20..3a7aed1 100644
--- a/vendor/golang.org/x/net/http2/ascii.go
+++ b/vendor/golang.org/x/net/http2/ascii.go
@@ -4,7 +4,9 @@
package http2
-import "strings"
+import (
+ "strings"
+)
// The HTTP protocols are defined in terms of ASCII, not Unicode. This file
// contains helper functions which may use Unicode-aware functions which would
@@ -43,6 +45,16 @@ func isASCIIPrint(s string) bool {
return true
}
+// isASCII returns whether s is ASCII.
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] > 0x7f {
+ return false
+ }
+ }
+ return true
+}
+
// asciiToLower returns the lowercase version of s if s is ASCII and printable,
// and whether or not it was.
func asciiToLower(s string) (lower string, ok bool) {
diff --git a/vendor/golang.org/x/net/http2/databuffer.go b/vendor/golang.org/x/net/http2/databuffer.go
index e6f55cb..9763ab1 100644
--- a/vendor/golang.org/x/net/http2/databuffer.go
+++ b/vendor/golang.org/x/net/http2/databuffer.go
@@ -121,10 +121,7 @@ func (b *dataBuffer) Write(p []byte) (int, error) {
// If the last chunk is empty, allocate a new chunk. Try to allocate
// enough to fully copy p plus any additional bytes we expect to
// receive. However, this may allocate less than len(p).
- want := int64(len(p))
- if b.expected > want {
- want = b.expected
- }
+ want := max(int64(len(p)), b.expected)
chunk := b.lastChunkOrAlloc(want)
n := copy(chunk[b.w:], p)
p = p[n:]
diff --git a/vendor/golang.org/x/net/http2/hpack/encode.go b/vendor/golang.org/x/net/http2/hpack/encode.go
index 46219da..e6d0c26 100644
--- a/vendor/golang.org/x/net/http2/hpack/encode.go
+++ b/vendor/golang.org/x/net/http2/hpack/encode.go
@@ -39,7 +39,6 @@ func NewEncoder(w io.Writer) *Encoder {
tableSizeUpdate: false,
w: w,
}
- e.dynTab.table.init()
e.dynTab.setMaxSize(initialHeaderTableSize)
return e
}
diff --git a/vendor/golang.org/x/net/http2/hpack/hpack.go b/vendor/golang.org/x/net/http2/hpack/hpack.go
index 7a1d976..ecd3eec 100644
--- a/vendor/golang.org/x/net/http2/hpack/hpack.go
+++ b/vendor/golang.org/x/net/http2/hpack/hpack.go
@@ -105,7 +105,6 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod
emitEnabled: true,
firstField: true,
}
- d.dynTab.table.init()
d.dynTab.allowedMaxSize = maxDynamicTableSize
d.dynTab.setMaxSize(maxDynamicTableSize)
return d
diff --git a/vendor/golang.org/x/net/http2/hpack/tables.go b/vendor/golang.org/x/net/http2/hpack/tables.go
index 8cbdf3f..3bd7eb7 100644
--- a/vendor/golang.org/x/net/http2/hpack/tables.go
+++ b/vendor/golang.org/x/net/http2/hpack/tables.go
@@ -31,10 +31,18 @@ type headerFieldTable struct {
// byName maps a HeaderField name to the unique id of the newest entry with
// the same name. See above for a definition of "unique id".
+ //
+ // byName and byNameValue are used only by search, which is only called
+ // for tables used by encoders. For tables used only by decoders, the
+ // maps are never built, as a memory optimization for servers with many
+ // mostly-idle connections, each pinning a dynamic table. The maps are
+ // built lazily by the first search call and are nil until then. The two
+ // maps are always both nil or both non-nil.
byName map[string]uint64
// byNameValue maps a HeaderField name/value pair to the unique id of the newest
// entry with the same name and value. See above for a definition of "unique id".
+ // See byName for when this map is non-nil.
byNameValue map[pairNameValue]uint64
}
@@ -42,9 +50,17 @@ type pairNameValue struct {
name, value string
}
-func (t *headerFieldTable) init() {
- t.byName = make(map[string]uint64)
- t.byNameValue = make(map[pairNameValue]uint64)
+// buildMaps initializes byName and byNameValue from ents.
+func (t *headerFieldTable) buildMaps() {
+ t.byName = make(map[string]uint64, len(t.ents))
+ t.byNameValue = make(map[pairNameValue]uint64, len(t.ents))
+ for k, f := range t.ents {
+ // Map to the newest matching entry: later (newer) entries
+ // overwrite earlier ones, matching addEntry's behavior.
+ id := t.evictCount + uint64(k) + 1
+ t.byName[f.Name] = id
+ t.byNameValue[pairNameValue{f.Name, f.Value}] = id
+ }
}
// len reports the number of entries in the table.
@@ -54,9 +70,11 @@ func (t *headerFieldTable) len() int {
// addEntry adds a new entry.
func (t *headerFieldTable) addEntry(f HeaderField) {
- id := uint64(t.len()) + t.evictCount + 1
- t.byName[f.Name] = id
- t.byNameValue[pairNameValue{f.Name, f.Value}] = id
+ if t.byName != nil {
+ id := uint64(t.len()) + t.evictCount + 1
+ t.byName[f.Name] = id
+ t.byNameValue[pairNameValue{f.Name, f.Value}] = id
+ }
t.ents = append(t.ents, f)
}
@@ -65,14 +83,16 @@ func (t *headerFieldTable) evictOldest(n int) {
if n > t.len() {
panic(fmt.Sprintf("evictOldest(%v) on table with %v entries", n, t.len()))
}
- for k := 0; k < n; k++ {
- f := t.ents[k]
- id := t.evictCount + uint64(k) + 1
- if t.byName[f.Name] == id {
- delete(t.byName, f.Name)
- }
- if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id {
- delete(t.byNameValue, p)
+ if t.byName != nil {
+ for k := 0; k < n; k++ {
+ f := t.ents[k]
+ id := t.evictCount + uint64(k) + 1
+ if t.byName[f.Name] == id {
+ delete(t.byName, f.Name)
+ }
+ if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id {
+ delete(t.byNameValue, p)
+ }
}
}
copy(t.ents, t.ents[n:])
@@ -100,6 +120,9 @@ func (t *headerFieldTable) evictOldest(n int) {
//
// See Section 2.3.3.
func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
+ if t.byName == nil {
+ t.buildMaps()
+ }
if !f.Sensitive {
if id := t.byNameValue[pairNameValue{f.Name, f.Value}]; id != 0 {
return t.idToIndex(id), true
diff --git a/vendor/golang.org/x/net/http2/server_common.go b/vendor/golang.org/x/net/http2/server_common.go
index 449538c..fec3690 100644
--- a/vendor/golang.org/x/net/http2/server_common.go
+++ b/vendor/golang.org/x/net/http2/server_common.go
@@ -25,6 +25,8 @@ import (
//
// https://golang.org/pkg/net/http/#ResponseWriter
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+//
+// Deprecated: Use [http.TrailerPrefix] instead.
const TrailerPrefix = "Trailer:"
// Push errors.
@@ -38,16 +40,22 @@ var (
// The configuration conf may be nil.
//
// ConfigureServer must be called before s begins serving.
+//
+// Deprecated: Set [http.Server.Protocols] instead.
func ConfigureServer(s *http.Server, conf *Server) error {
return configureServer(s, conf)
}
// Server is an HTTP/2 server.
+//
+// Deprecated: Use [http.Server] instead.
type Server struct {
// MaxHandlers limits the number of http.Handler ServeHTTP goroutines
// which may run at a time over all connections.
// Negative or zero no limit.
// TODO: implement
+ //
+ // Deprecated: This field has never had any effect.
MaxHandlers int
// MaxConcurrentStreams optionally specifies the number of
@@ -56,6 +64,9 @@ type Server struct {
// which may be active globally, which is MaxHandlers.
// If zero, MaxConcurrentStreams defaults to at least 100, per
// the HTTP/2 spec's recommendations.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.MaxConcurrentStreams] instead.
MaxConcurrentStreams uint32
// MaxDecoderHeaderTableSize optionally specifies the http2
@@ -63,44 +74,67 @@ type Server struct {
// informs the remote endpoint of the maximum size of the header compression
// table used to decode header blocks, in octets. If zero, the default value
// of 4096 is used.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.MaxDecoderHeaderTableSize] instead.
MaxDecoderHeaderTableSize uint32
// MaxEncoderHeaderTableSize optionally specifies an upper limit for the
// header compression table used for encoding request headers. Received
// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero,
// the default value of 4096 is used.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.MaxEncoderHeaderTableSize] instead.
MaxEncoderHeaderTableSize uint32
// MaxReadFrameSize optionally specifies the largest frame
// this server is willing to read. A valid value is between
// 16k and 16M, inclusive. If zero or otherwise invalid, a
// default value is used.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.MaxReadFrameSize] instead.
MaxReadFrameSize uint32
// PermitProhibitedCipherSuites, if true, permits the use of
// cipher suites prohibited by the HTTP/2 spec.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.PermitProhibitedCipherSuites] instead.
PermitProhibitedCipherSuites bool
// IdleTimeout specifies how long until idle clients should be
// closed with a GOAWAY frame. PING frames are not considered
// activity for the purposes of IdleTimeout.
// If zero or negative, there is no timeout.
+ //
+ // Deprecated: Use [http.Server.IdleTimeout] instead.
IdleTimeout time.Duration
// ReadIdleTimeout is the timeout after which a health check using a ping
// frame will be carried out if no frame is received on the connection.
// If zero, no health check is performed.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.SendPingTimeout] instead.
ReadIdleTimeout time.Duration
// PingTimeout is the timeout after which the connection will be closed
// if a response to a ping is not received.
// If zero, a default of 15 seconds is used.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.PingTimeout] instead.
PingTimeout time.Duration
// WriteByteTimeout is the timeout after which a connection will be
// closed if no data can be written to it. The timeout begins when data is
// available to write, and is extended whenever any bytes are written.
// If zero or negative, there is no timeout.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.WriteByteTimeout] instead.
WriteByteTimeout time.Duration
// MaxUploadBufferPerConnection is the size of the initial flow
@@ -108,12 +142,18 @@ type Server struct {
// allow this to be smaller than 65535 or larger than 2^32-1.
// If the value is outside this range, a default value will be
// used instead.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.MaxReceiveBufferPerConnection] instead.
MaxUploadBufferPerConnection int32
// MaxUploadBufferPerStream is the size of the initial flow control
// window for each stream. The HTTP/2 spec does not allow this to
// be larger than 2^32-1. If the value is zero or larger than the
// maximum, a default value will be used instead.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.MaxReceiveBufferPerStream] instead.
MaxUploadBufferPerStream int32
// NewWriteScheduler constructs a write scheduler for a connection.
@@ -126,6 +166,9 @@ type Server struct {
// It's intended to increment a metric for monitoring, such
// as an expvar or Prometheus metric.
// The errType consists of only ASCII word characters.
+ //
+ // Deprecated: Use [http.Server.HTTP2] and
+ // [http.HTTP2Config.CountError] instead.
CountError func(errType string)
// Internal state. This is a pointer (rather than embedded directly)
@@ -135,6 +178,8 @@ type Server struct {
}
// ServeConnOpts are options for the Server.ServeConn method.
+//
+// Deprecated: ServeConnOpts is deprecated.
type ServeConnOpts struct {
// Context is the base context to use.
// If nil, context.Background is used.
@@ -178,6 +223,8 @@ type ServeConnOpts struct {
// implemented in terms of providing a suitably-behaving net.Conn.
//
// The opts parameter is optional. If nil, default values are used.
+//
+// Deprecated: Use [http.Server.Serve] or [http.Server.ServeTLS] instead.
func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
if opts == nil {
opts = &ServeConnOpts{}
diff --git a/vendor/golang.org/x/net/http2/server_wrap.go b/vendor/golang.org/x/net/http2/server_wrap.go
index a7a0955..737f1f0 100644
--- a/vendor/golang.org/x/net/http2/server_wrap.go
+++ b/vendor/golang.org/x/net/http2/server_wrap.go
@@ -10,9 +10,11 @@ package http2
import (
"context"
+ "crypto/tls"
"errors"
"net"
"net/http"
+ "slices"
"sync"
"time"
)
@@ -44,6 +46,20 @@ func configureServer(s *http.Server, conf *Server) error {
h2.IdleTimeout = h1.ReadTimeout
}
}
+
+ // Register h2 and http/1.1 ALPN protocols on s.TLSConfig, matching
+ // the pre-wrapping implementation in server.go, so that TLS listeners
+ // built from s.TLSConfig still negotiate HTTP/2.
+ if s.TLSConfig == nil {
+ s.TLSConfig = new(tls.Config)
+ }
+ if !slices.Contains(s.TLSConfig.NextProtos, NextProtoTLS) {
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS)
+ }
+ if !slices.Contains(s.TLSConfig.NextProtos, "http/1.1") {
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "http/1.1")
+ }
+
conf.state = &serverInternalState{
s1: s,
}
diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go
index 08ac409..088eb9b 100644
--- a/vendor/golang.org/x/net/http2/transport.go
+++ b/vendor/golang.org/x/net/http2/transport.go
@@ -184,6 +184,8 @@ func (t *Transport) initConnPool() {
// ClientConn is the state of a single HTTP/2 client connection to an
// HTTP/2 server.
+//
+// Deprecated: Use [http.ClientConn] instead.
type ClientConn struct {
t *Transport
tconn net.Conn // usually *tls.Conn, except specialized impls
diff --git a/vendor/golang.org/x/net/http2/transport_common.go b/vendor/golang.org/x/net/http2/transport_common.go
index b9f5293..4f0333a 100644
--- a/vendor/golang.org/x/net/http2/transport_common.go
+++ b/vendor/golang.org/x/net/http2/transport_common.go
@@ -24,6 +24,8 @@ import (
// It returns an error if t1 has already been HTTP/2-enabled.
//
// Use ConfigureTransports instead to configure the HTTP/2 Transport.
+//
+// Deprecated: Set [http.Transport.Protocols] instead.
func ConfigureTransport(t1 *http.Transport) error {
return configureTransport(t1)
}
@@ -31,6 +33,8 @@ func ConfigureTransport(t1 *http.Transport) error {
// ConfigureTransports configures a net/http HTTP/1 Transport to use HTTP/2.
// It returns a new HTTP/2 Transport for further configuration.
// It returns an error if t1 has already been HTTP/2-enabled.
+//
+// Deprecated: Set [http.Transport.Protocols] instead.
func ConfigureTransports(t1 *http.Transport) (*Transport, error) {
return configureTransports(t1)
}
@@ -39,6 +43,8 @@ func ConfigureTransports(t1 *http.Transport) (*Transport, error) {
//
// A Transport internally caches connections to servers. It is safe
// for concurrent use by multiple goroutines.
+//
+// Deprecated: Use [http.Transport] instead.
type Transport struct {
// DialTLSContext specifies an optional dial function with context for
// creating TLS connections for requests.
@@ -47,6 +53,8 @@ type Transport struct {
//
// If the returned net.Conn has a ConnectionState method like tls.Conn,
// it will be used to set http.Response.TLS.
+ //
+ // Deprecated: Use [http.Transport.DialTLSContext] instead.
DialTLSContext func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error)
// DialTLS specifies an optional dial function for creating
@@ -54,17 +62,21 @@ type Transport struct {
//
// If DialTLSContext and DialTLS is nil, tls.Dial is used.
//
- // Deprecated: Use DialTLSContext instead, which allows the transport
- // to cancel dials as soon as they are no longer needed.
- // If both are set, DialTLSContext takes priority.
+ // Deprecated: Use [http.Transport.DialTLSContext] instead.
DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error)
// TLSClientConfig specifies the TLS configuration to use with
// tls.Client. If nil, the default configuration is used.
+ //
+ // Deprecated: Use [http.Transport.TLSClientConfig] instead.
TLSClientConfig *tls.Config
// ConnPool optionally specifies an alternate connection pool to use.
// If nil, the default is used.
+ //
+ // Deprecated: To create a custom connection pool, implement
+ // [http.RoundTripper]. Use [http.Transport.NewClientConn]
+ // to create connections for the pool.
ConnPool ClientConnPool
// DisableCompression, if true, prevents the Transport from
@@ -75,10 +87,14 @@ type Transport struct {
// decoded in the Response.Body. However, if the user
// explicitly requested gzip it is not automatically
// uncompressed.
+ //
+ // Deprecated: Use [http.Transport.DisableCompression] instead.
DisableCompression bool
// AllowHTTP, if true, permits HTTP/2 requests using the insecure,
// plain-text "http" scheme. Note that this does not enable h2c support.
+ //
+ // Deprecated: Use [http.Transport.Protocols] instead.
AllowHTTP bool
// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
@@ -88,6 +104,8 @@ type Transport struct {
// want to advertise an unlimited value to the peer, Transport
// interprets the highest possible value here (0xffffffff or 1<<32-1)
// to mean no limit.
+ //
+ // Deprecated: Use [http.Transport.MaxResponseHeaderBytes] instead.
MaxHeaderListSize uint32
// MaxReadFrameSize is the http2 SETTINGS_MAX_FRAME_SIZE to send in the
@@ -97,6 +115,9 @@ type Transport struct {
// according to the spec:
// https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2.
// Values are bounded in the range 16k to 16M.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.MaxReadFrameSize] instead.
MaxReadFrameSize uint32
// MaxDecoderHeaderTableSize optionally specifies the http2
@@ -104,12 +125,18 @@ type Transport struct {
// informs the remote endpoint of the maximum size of the header compression
// table used to decode header blocks, in octets. If zero, the default value
// of 4096 is used.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.MaxDecoderHeaderTableSize] instead.
MaxDecoderHeaderTableSize uint32
// MaxEncoderHeaderTableSize optionally specifies an upper limit for the
// header compression table used for encoding request headers. Received
// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero,
// the default value of 4096 is used.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.MaxEncoderHeaderTableSize] instead.
MaxEncoderHeaderTableSize uint32
// StrictMaxConcurrentStreams controls whether the server's
@@ -120,12 +147,17 @@ type Transport struct {
// server's SETTINGS_MAX_CONCURRENT_STREAMS is interpreted as
// a global limit and callers of RoundTrip block when needed,
// waiting for their turn.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.StrictMaxConcurrentRequests] instead.
StrictMaxConcurrentStreams bool
// IdleConnTimeout is the maximum amount of time an idle
// (keep-alive) connection will remain idle before closing
// itself.
// Zero means no limit.
+ //
+ // Deprecated: Use [http.Transport.IdleConnTimeout] instead.
IdleConnTimeout time.Duration
// ReadIdleTimeout is the timeout after which a health check using ping
@@ -134,22 +166,34 @@ type Transport struct {
// there is no other traffic on the connection, the health check will
// be performed every ReadIdleTimeout interval.
// If zero, no health check is performed.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.SendPingTimeout] instead.
ReadIdleTimeout time.Duration
// PingTimeout is the timeout after which the connection will be closed
// if a response to Ping is not received.
// Defaults to 15s.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.PingTimeout] instead.
PingTimeout time.Duration
// WriteByteTimeout is the timeout after which the connection will be
// closed no data can be written to it. The timeout begins when data is
// available to write, and is extended whenever any bytes are written.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.WriteByteTimeout] instead.
WriteByteTimeout time.Duration
// CountError, if non-nil, is called on HTTP/2 transport errors.
// It's intended to increment a metric for monitoring, such
// as an expvar or Prometheus metric.
// The errType consists of only ASCII word characters.
+ //
+ // Deprecated: Use [http.Transport.HTTP2] and
+ // [http.HTTP2Config.CountError] instead.
CountError func(errType string)
// Internal state, differs between wrapped and non-wrapped implementations.
@@ -165,6 +209,10 @@ var (
)
// ClientConnPool manages a pool of HTTP/2 client connections.
+//
+// Deprecated: To create a custom connection pool, implement
+// [http.RoundTripper]. Use [http.Transport.NewClientConn]
+// to create connections for the pool.
type ClientConnPool interface {
// GetClientConn returns a specific HTTP/2 connection (usually
// a TLS-TCP connection) to an HTTP/2 server. On success, the
@@ -177,6 +225,8 @@ type ClientConnPool interface {
}
// ClientConnState describes the state of a ClientConn.
+//
+// Deprecated: Use [http.ClientConn] instead.
type ClientConnState struct {
// Closed is whether the connection is closed.
Closed bool
@@ -210,6 +260,8 @@ type ClientConnState struct {
}
// RoundTripOpt are options for the Transport.RoundTripOpt method.
+//
+// Deprecated: There are no options to set.
type RoundTripOpt struct {
// OnlyCachedConn controls whether RoundTripOpt may
// create a new TCP connection. If set true and
@@ -222,11 +274,14 @@ type RoundTripOpt struct {
allowHTTP bool // allow http:// URLs
}
+// Deprecated: Use [http.Transport.RoundTrip] instead.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
return t.RoundTripOpt(req, RoundTripOpt{})
}
// RoundTripOpt is like RoundTrip, but takes options.
+//
+// Deprecated: Use [http.Transport.RoundTrip] instead.
func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
return t.roundTripOpt(req, opt)
}
@@ -234,10 +289,15 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
// CloseIdleConnections closes any connections which were previously
// connected from previous requests but are now sitting idle.
// It does not interrupt any connections currently in use.
+//
+// Deprecated: Use [http.Transport.CloseIdleConnections] instead.
func (t *Transport) CloseIdleConnections() {
t.closeIdleConnections()
}
+// NewClientConn is deprecated.
+//
+// Deprecated: Use [http.Transport.NewClientConn] instead.
func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
return t.newUserClientConn(c)
}
@@ -256,8 +316,15 @@ func authorityAddr(scheme string, authority string) (addr string) {
port = "80"
}
}
- if a, err := idna.ToASCII(host); err == nil {
- host = a
+ // Skip IDNA processing on hosts which are already ASCII.
+ // This is consistent with net/http and the WHATWG URL Specification.
+ // (We currently don't follow all of WHATWG, but we're aligned on
+ // permitting all-ASCII hostnames which fail IDNA validation.
+ // There are existing, valid domain names which TR #46 processing rejects.)
+ if !isASCII(host) {
+ if a, err := idna.Lookup.ToASCII(host); err == nil && a != "" {
+ host = a
+ }
}
// IPv6 address literal, without a port:
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
@@ -414,6 +481,8 @@ func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string
// GoAwayError is returned by the Transport when the server closes the
// TCP connection after sending a GOAWAY frame.
+//
+// Deprecated: GoAwayError is deprecated.
type GoAwayError struct {
LastStreamID uint32
ErrCode ErrCode
diff --git a/vendor/golang.org/x/net/http2/transport_wrap.go b/vendor/golang.org/x/net/http2/transport_wrap.go
index d25d99b..34dfb3c 100644
--- a/vendor/golang.org/x/net/http2/transport_wrap.go
+++ b/vendor/golang.org/x/net/http2/transport_wrap.go
@@ -22,8 +22,8 @@ import (
)
func configureTransport(t1 *http.Transport) error {
- // ConfigureTransport is a no-op: The http.Transport already supports HTTP/2.
- return nil
+ _, err := configureTransports(t1)
+ return err
}
func configureTransports(t1 *http.Transport) (*Transport, error) {
@@ -31,6 +31,17 @@ func configureTransports(t1 *http.Transport) (*Transport, error) {
// linked to the http.Transport's.
tr2 := &Transport{}
tr2.configure(t1)
+ // Enable HTTP/2 on the transport, as the pre-wrapping implementation did:
+ // net/http does not auto-enable it for a transport with a custom
+ // TLSClientConfig or dialer.
+ if t1.TLSClientConfig == nil {
+ t1.TLSClientConfig = &tls.Config{}
+ }
+ if t1.Protocols == nil {
+ t1.Protocols = new(http.Protocols)
+ t1.Protocols.SetHTTP1(true)
+ }
+ t1.Protocols.SetHTTP2(true)
return tr2, nil
}
@@ -44,7 +55,7 @@ type transportConfig struct {
// Registered is called by net/http.Transport.RegisterProtocol,
// to let us know that it understands the registration mechanism we're using.
func (t transportConfig) Registered(t1 *http.Transport) {
- t.t.t1 = t1
+ t.t.lazyt1 = t1
}
func (t transportConfig) DisableCompression() bool {
@@ -134,29 +145,30 @@ func (t transportConfig) DialFromContext(ctx context.Context, network, address s
type transportInternal struct {
initOnce sync.Once
- t1 *http.Transport
+ lazyt1 *http.Transport
}
-func (t *Transport) init() {
+func (t *Transport) init() *http.Transport {
t.initOnce.Do(func() {
- if t.t1 != nil {
+ if t.lazyt1 != nil {
return
}
t1 := &http.Transport{}
t.configure(t1)
})
+ return t.lazyt1
}
func (t *Transport) configure(t1 *http.Transport) {
t1.RegisterProtocol("http/2", transportConfig{t})
- // tr2.t1 is set by transportConfig.Registered.
- if t.t1 != t1 {
+ // tr2.lazyt1 is set by transportConfig.Registered.
+ if t.lazyt1 != t1 {
panic("http2: net/http does not support this version of x/net/http2")
}
}
func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) {
- t.init()
+ t1 := t.init()
if req.URL.Scheme == "http" && !t.AllowHTTP {
return nil, errors.New("http2: unencrypted HTTP/2 not enabled")
@@ -177,22 +189,23 @@ func (t *Transport) roundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
ctx := context.WithValue(req.Context(), http2TransportContextKey{}, t)
req = req.WithContext(ctx)
- return t.t1.RoundTrip(req)
+ return t1.RoundTrip(req)
}
func (t *Transport) closeIdleConnections() {
- t.init()
- t.t1.CloseIdleConnections()
+ t1 := t.init()
+ t1.CloseIdleConnections()
}
func (t *Transport) newUserClientConn(c net.Conn) (*ClientConn, error) {
+ t1 := t.init()
// http.Transport's NewClientConn doesn't provide a supported way to create
// a connection from a net.Conn. (This might be useful to add in the future?)
// We're going to craftily sneak one in via the context key, with the
// scheme of "http/2" telling NewClientConn to look for it.
ctx := context.WithValue(context.Background(), netConnContextKey{}, c)
- nhcc, err := t.t1.NewClientConn(ctx, "http/2", "")
+ nhcc, err := t1.NewClientConn(ctx, "http/2", "")
if err != nil {
return nil, err
}
@@ -203,6 +216,8 @@ func (t *Transport) newUserClientConn(c net.Conn) (*ClientConn, error) {
// ClientConn is the state of a single HTTP/2 client connection to an
// HTTP/2 server.
+//
+// Deprecated: Use [http.ClientConn] instead.
type ClientConn struct {
cc *http.ClientConn
tconn net.Conn
@@ -224,32 +239,40 @@ type ClientConn struct {
}
func (cc *ClientConn) roundTrip(req *http.Request) (*http.Response, error) {
- err := func() error {
+ haveReservation, err := func() (bool, error) {
cc.mu.Lock()
defer cc.mu.Unlock()
if cc.doNotReuse {
- return errClientConnUnusable
- }
- cc.roundTrips++
- if cc.reserved > 0 {
- // We've already reserved a concurrency slot for this request.
- cc.reserved--
- } else if cc.cc.Reserve() != nil {
- // We don't seem to have an available concurrency slot,
- // so bump the pending count (requests waiting for a slot).
- cc.pending++
+ return false, errClientConnUnusable
}
+
// ClientConn.Shutdown will not shut down the conn while
// cc.starting > 0 or cc.cc.InFlight() > 0.
//
// The starting state covers the gap between us deciding to
// start sending the request, and actually sending it.
cc.starting++
- return nil
+
+ cc.roundTrips++
+ if cc.reserved == 0 {
+ // We do not have a concurrency slot reserved for this request.
+ return false, nil
+ }
+ cc.reserved--
+ return true, nil
}()
if err != nil {
return nil, err
}
+ // If we have no reservation, try to acquire one.
+ // (This must be done without cc.mu held, since Reserve may call back to the state hook.)
+ if !haveReservation && cc.cc.Reserve() != nil {
+ // We could not acquire a concurrency slot, so bump the pending count
+ // (requests waiting for a slot).
+ cc.mu.Lock()
+ cc.pending++
+ cc.mu.Unlock()
+ }
resp, err := cc.cc.RoundTrip(req)
cc.mu.Lock()
cc.starting--
@@ -280,16 +303,21 @@ func (cc *ClientConn) ping(ctx context.Context) error {
}
func (cc *ClientConn) reserveNewRequest() bool {
+ if err := cc.cc.Reserve(); err != nil {
+ return false
+ }
+ reserved := true
cc.mu.Lock()
- defer cc.mu.Unlock()
if cc.doNotReuse {
- return false
+ reserved = false
+ } else {
+ cc.reserved++
}
- if err := cc.cc.Reserve(); err != nil {
- return false
+ cc.mu.Unlock()
+ if !reserved {
+ cc.cc.Release()
}
- cc.reserved++
- return true
+ return reserved
}
func (cc *ClientConn) setDoNotReuse() {
diff --git a/vendor/golang.org/x/net/idna/idna.go b/vendor/golang.org/x/net/idna/idna.go
index 2276712..e2f28fe 100644
--- a/vendor/golang.org/x/net/idna/idna.go
+++ b/vendor/golang.org/x/net/idna/idna.go
@@ -400,7 +400,11 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
// Spec says keep the old label.
continue
}
- if unicode16 && err == nil && len(u) > 0 && isASCII(u) {
+ if err == nil && len(u) > 0 && isASCII(u) {
+ // UTS 43 pre-revision 33 doesn't classify a xn-- label
+ // which contains only ASCII characters as an error,
+ // but that's a specification bug and a security issue.
+ // Always return an error in this case.
err = punyError(enc)
}
isBidi = isBidi || bidirule.DirectionString(u) != bidi.LeftToRight
diff --git a/vendor/golang.org/x/net/internal/httpcommon/README.md b/vendor/golang.org/x/net/internal/httpcommon/README.md
new file mode 100644
index 0000000..951c346
--- /dev/null
+++ b/vendor/golang.org/x/net/internal/httpcommon/README.md
@@ -0,0 +1,7 @@
+These two packages are identical:
+
+- net/http/internal/httpcommon
+- golang.org/x/net/internal/httpcommon
+
+The two are kept in sync manually.
+Any change to one should be made in the other.
diff --git a/vendor/golang.org/x/net/internal/httpcommon/request.go b/vendor/golang.org/x/net/internal/httpcommon/request.go
index d94c874..5aaca59 100644
--- a/vendor/golang.org/x/net/internal/httpcommon/request.go
+++ b/vendor/golang.org/x/net/internal/httpcommon/request.go
@@ -391,6 +391,7 @@ type ServerRequestParam struct {
// ServerRequestResult is the result of NewServerRequest.
type ServerRequestResult struct {
// Various http.Request fields.
+ Host string
URL *url.URL
RequestURI string
Trailer map[string][]string
@@ -433,20 +434,46 @@ func NewServerRequest(rp ServerRequestParam) ServerRequestResult {
}
delete(rp.Header, "Trailer")
+ authority := rp.Authority
+ if host := rp.Header["Host"]; len(host) == 1 {
+ // HTTP/2 and HTTP/3 permit the Host header to be present,
+ // but it must match the :authority pseudo-header.
+ if authority == "" {
+ authority = host[0]
+ } else if host[0] != authority {
+ return ServerRequestResult{
+ InvalidReason: "authority_host_mismatch",
+ }
+ }
+ delete(rp.Header, "Host")
+ } else if len(host) > 1 {
+ // HTTP/1.1 rejects any request containing more than one Host header.
+ // HTTP/2 and HTTP/3 don't use the Host header, but reject multiple anyway.
+ return ServerRequestResult{
+ InvalidReason: "multiple_host_headers",
+ }
+ }
+
// "':authority' MUST NOT include the deprecated userinfo subcomponent
// for "http" or "https" schemed URIs."
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.3.8
- if strings.IndexByte(rp.Authority, '@') != -1 && (rp.Scheme == "http" || rp.Scheme == "https") {
+ if strings.IndexByte(authority, '@') != -1 && (rp.Scheme == "http" || rp.Scheme == "https") {
return ServerRequestResult{
InvalidReason: "userinfo_in_authority",
}
}
+ if authority != "" && !httpguts.ValidHostHeader(authority) {
+ return ServerRequestResult{
+ InvalidReason: "invalid_authority",
+ }
+ }
+
var url_ *url.URL
var requestURI string
if rp.Method == "CONNECT" && rp.Protocol == "" {
- url_ = &url.URL{Host: rp.Authority}
- requestURI = rp.Authority // mimic HTTP/1 server behavior
+ url_ = &url.URL{Host: authority}
+ requestURI = authority // mimic HTTP/1 server behavior
} else {
// "[The :path] pseudo-header field MUST NOT be empty [...]"
// https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.4.2
@@ -467,6 +494,7 @@ func NewServerRequest(rp ServerRequestParam) ServerRequestResult {
}
return ServerRequestResult{
+ Host: authority,
URL: url_,
NeedsContinue: needsContinue,
RequestURI: requestURI,
diff --git a/vendor/golang.org/x/net/trace/histogram.go b/vendor/golang.org/x/net/trace/histogram.go
index d6c7110..2f78683 100644
--- a/vendor/golang.org/x/net/trace/histogram.go
+++ b/vendor/golang.org/x/net/trace/histogram.go
@@ -70,10 +70,7 @@ func log2(i int64) int {
}
func getBucket(i int64) (index int) {
- index = log2(i) - 1
- if index < 0 {
- index = 0
- }
+ index = max(log2(i)-1, 0)
if index >= bucketCount {
index = bucketCount - 1
}
diff --git a/vendor/golang.org/x/sync/LICENSE b/vendor/golang.org/x/sync/LICENSE
new file mode 100644
index 0000000..2a7cf70
--- /dev/null
+++ b/vendor/golang.org/x/sync/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/sync/PATENTS b/vendor/golang.org/x/sync/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/vendor/golang.org/x/sync/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/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go
new file mode 100644
index 0000000..c261a8e
--- /dev/null
+++ b/vendor/golang.org/x/sync/errgroup/errgroup.go
@@ -0,0 +1,151 @@
+// 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 errgroup provides synchronization, error propagation, and Context
+// cancellation for groups of goroutines working on subtasks of a common task.
+//
+// [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks
+// returning errors.
+package errgroup
+
+import (
+ "context"
+ "fmt"
+ "sync"
+)
+
+type token struct{}
+
+// A Group is a collection of goroutines working on subtasks that are part of
+// the same overall task. A Group should not be reused for different tasks.
+//
+// A zero Group is valid, has no limit on the number of active goroutines,
+// and does not cancel on error.
+type Group struct {
+ cancel func(error)
+
+ wg sync.WaitGroup
+
+ sem chan token
+
+ errOnce sync.Once
+ err error
+}
+
+func (g *Group) done() {
+ if g.sem != nil {
+ <-g.sem
+ }
+ g.wg.Done()
+}
+
+// WithContext returns a new Group and an associated Context derived from ctx.
+//
+// The derived Context is canceled the first time a function passed to Go
+// returns a non-nil error or the first time Wait returns, whichever occurs
+// first.
+func WithContext(ctx context.Context) (*Group, context.Context) {
+ ctx, cancel := context.WithCancelCause(ctx)
+ return &Group{cancel: cancel}, ctx
+}
+
+// Wait blocks until all function calls from the Go method have returned, then
+// returns the first non-nil error (if any) from them.
+func (g *Group) Wait() error {
+ g.wg.Wait()
+ if g.cancel != nil {
+ g.cancel(g.err)
+ }
+ return g.err
+}
+
+// Go calls the given function in a new goroutine.
+//
+// The first call to Go must happen before a Wait.
+// It blocks until the new goroutine can be added without the number of
+// goroutines in the group exceeding the configured limit.
+//
+// The first goroutine in the group that returns a non-nil error will
+// cancel the associated Context, if any. The error will be returned
+// by Wait.
+func (g *Group) Go(f func() error) {
+ if g.sem != nil {
+ g.sem <- token{}
+ }
+
+ g.wg.Add(1)
+ go func() {
+ defer g.done()
+
+ // It is tempting to propagate panics from f()
+ // up to the goroutine that calls Wait, but
+ // it creates more problems than it solves:
+ // - it delays panics arbitrarily,
+ // making bugs harder to detect;
+ // - it turns f's panic stack into a mere value,
+ // hiding it from crash-monitoring tools;
+ // - it risks deadlocks that hide the panic entirely,
+ // if f's panic leaves the program in a state
+ // that prevents the Wait call from being reached.
+ // See #53757, #74275, #74304, #74306.
+
+ if err := f(); err != nil {
+ g.errOnce.Do(func() {
+ g.err = err
+ if g.cancel != nil {
+ g.cancel(g.err)
+ }
+ })
+ }
+ }()
+}
+
+// TryGo calls the given function in a new goroutine only if the number of
+// active goroutines in the group is currently below the configured limit.
+//
+// The return value reports whether the goroutine was started.
+func (g *Group) TryGo(f func() error) bool {
+ if g.sem != nil {
+ select {
+ case g.sem <- token{}:
+ // Note: this allows barging if and only if channels in general allow barging.
+ default:
+ return false
+ }
+ }
+
+ g.wg.Add(1)
+ go func() {
+ defer g.done()
+
+ if err := f(); err != nil {
+ g.errOnce.Do(func() {
+ g.err = err
+ if g.cancel != nil {
+ g.cancel(g.err)
+ }
+ })
+ }
+ }()
+ return true
+}
+
+// SetLimit limits the number of active goroutines in this group to at most n.
+// A negative value indicates no limit.
+// A limit of zero will prevent any new goroutines from being added.
+//
+// Any subsequent call to the Go method will block until it can add an active
+// goroutine without exceeding the configured limit.
+//
+// The limit must not be modified while any goroutines in the group are active.
+func (g *Group) SetLimit(n int) {
+ if n < 0 {
+ g.sem = nil
+ return
+ }
+ if active := len(g.sem); active != 0 {
+ panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", active))
+ }
+ g.sem = make(chan token, n)
+}
diff --git a/vendor/golang.org/x/sys/cpu/cpu.go b/vendor/golang.org/x/sys/cpu/cpu.go
index f1ce515..df8dbd1 100644
--- a/vendor/golang.org/x/sys/cpu/cpu.go
+++ b/vendor/golang.org/x/sys/cpu/cpu.go
@@ -182,12 +182,13 @@ var MIPS64X struct {
// require kernel support to work (DARN, SCV), so there are feature bits for
// those as well. The struct is padded to avoid false sharing.
var PPC64 struct {
- _ CacheLinePad
- HasDARN bool // Hardware random number generator (requires kernel enablement)
- HasSCV bool // Syscall vectored (requires kernel enablement)
- IsPOWER8 bool // ISA v2.07 (POWER8)
- IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8
- _ CacheLinePad
+ _ CacheLinePad
+ HasDARN bool // Hardware random number generator (requires kernel enablement)
+ HasSCV bool // Syscall vectored (requires kernel enablement)
+ IsPOWER8 bool // ISA v2.07 (POWER8)
+ IsPOWER9 bool // ISA v3.00 (POWER9), implies IsPOWER8
+ IsPOWER10 bool // ISA v3.1 (POWER10 and POWER11; POWER11 did not add a new architected level), implies IsPOWER9
+ _ CacheLinePad
}
// S390X contains the supported CPU features of the current IBM Z
@@ -248,13 +249,21 @@ var RISCV64 struct {
HasZvks bool // ShangMi Algorithm Suite
HasZvksc bool // ShangMi Algorithm Suite with carryless multiplication
HasZvksg bool // ShangMi Algorithm Suite with GCM
+ VLENB uint // Vector register length in bytes, 0 if undetected
_ CacheLinePad
}
+// doDerived, if non-nil, is called after processing GODEBUG to set "derived"
+// feature flags.
+var doDerived func()
+
func init() {
archInit()
initOptions()
processOptions()
+ if doDerived != nil {
+ doDerived()
+ }
}
// options contains the cpu debug options that can be used in GODEBUG.
diff --git a/vendor/golang.org/x/sys/cpu/cpu_gc_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_gc_riscv64.go
new file mode 100644
index 0000000..3d660dd
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/cpu_gc_riscv64.go
@@ -0,0 +1,11 @@
+// Copyright 2026 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
+
+package cpu
+
+// Can only be called when the vector extension is present.
+// Implemented in cpu_riscv64.s.
+func readVLENB() uint
diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
index 197188e..70b3dc7 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go
@@ -11,6 +11,7 @@ const (
// ISA Level
_PPC_FEATURE2_ARCH_2_07 = 0x80000000
_PPC_FEATURE2_ARCH_3_00 = 0x00800000
+ _PPC_FEATURE2_ARCH_3_1 = 0x00040000
// CPU features
_PPC_FEATURE2_DARN = 0x00200000
@@ -21,6 +22,9 @@ func doinit() {
// HWCAP2 feature bits
PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07)
PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00)
+ // ISA 3.1 covers both POWER10 and POWER11: POWER11 did not introduce a
+ // new architected HWCAP level, so there is no separate IsPOWER11.
+ PPC64.IsPOWER10 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_1)
PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN)
PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV)
}
diff --git a/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
index f4fb52e..53e9091 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
@@ -130,6 +130,9 @@ func doinit() {
RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST
}
}
+ if RISCV64.HasV {
+ RISCV64.VLENB = readVLENB()
+ }
// Let's double check with HWCAP if the C extension does not appear to be supported.
// This may happen if we're running on a kernel older than 6.4.
@@ -137,6 +140,14 @@ func doinit() {
if !RISCV64.HasC {
RISCV64.HasC = isSet(hwCap, hwcap_RISCV_ISA_C)
}
+
+ doDerived = func() {
+ // If the vector extension is disabled by GODEBUG, then the VLENB is zero.
+ if !RISCV64.HasV {
+ RISCV64.VLENB = 0
+ }
+ }
+
}
func isSet(hwc uint, value uint) bool {
diff --git a/vendor/golang.org/x/sys/cpu/cpu_netbsd_amd64.go b/vendor/golang.org/x/sys/cpu/cpu_netbsd_amd64.go
new file mode 100644
index 0000000..4f981b1
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/cpu_netbsd_amd64.go
@@ -0,0 +1,47 @@
+// Copyright 2026 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 netbsd && amd64 && gc
+
+package cpu
+
+func doinit() {
+ // NetBSD corrupts avx registers when receiving signals.
+ // See issue 80285.
+ // TODO: when NetBSD fixes the bug, add a version
+ // check and skip here.
+ X86.HasAVX = false
+ X86.HasAVX2 = false
+ // Set these also, just to be safe
+ X86.HasAVXVNNI = false
+ X86.HasAVX512 = false
+ X86.HasAVX512F = false
+ X86.HasAVX512CD = false
+ X86.HasAVX512CD = false
+ X86.HasAVX512ER = false
+ X86.HasAVX512PF = false
+ X86.HasAVX512VL = false
+ X86.HasAVX512BW = false
+ X86.HasAVX512DQ = false
+ X86.HasAVX512IFMA = false
+ X86.HasAVX512VBMI = false
+ X86.HasAVX5124VNNIW = false
+ X86.HasAVX5124FMAPS = false
+ X86.HasAVX512VPOPCNTDQ = false
+ X86.HasAVX512VPCLMULQDQ = false
+ X86.HasAVX512VNNI = false
+ X86.HasAVX512GFNI = false
+ X86.HasAVX512VAES = false
+ X86.HasAVX512VBMI2 = false
+ X86.HasAVX512BITALG = false
+ X86.HasAVX512BF16 = false
+ X86.HasAVXIFMA = false
+ X86.HasAVXVNNI = false
+ X86.HasAVXVNNIInt8 = false
+
+}
+
+func darwinSupportsAVX512() bool {
+ panic("only implemented for gc && amd64 && darwin")
+}
diff --git a/vendor/golang.org/x/sys/cpu/cpu_other_x86.go b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go
index a0fd7e2..82b7580 100644
--- a/vendor/golang.org/x/sys/cpu/cpu_other_x86.go
+++ b/vendor/golang.org/x/sys/cpu/cpu_other_x86.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build 386 || amd64p32 || (amd64 && (!darwin || !gc))
+//go:build 386 || amd64p32 || (amd64 && ((!darwin && !netbsd) || !gc))
package cpu
diff --git a/vendor/golang.org/x/sys/cpu/cpu_riscv64.s b/vendor/golang.org/x/sys/cpu/cpu_riscv64.s
new file mode 100644
index 0000000..b092fb2
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/cpu_riscv64.s
@@ -0,0 +1,17 @@
+// Copyright 2026 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build gc
+
+#include "textflag.h"
+
+// Read the vector register length in bytes from the vlenb CSR.
+// May only be called when the vector extension is present.
+// func readVLENB() uint
+TEXT ·readVLENB(SB), NOSPLIT|NOFRAME, $0-8
+ // Go 1.25's assembler does not recognize VLENB, so use its raw CSRR encoding.
+ // Replace WORD with CSRR VLENB, X10 once go.mod requires Go 1.27.
+ WORD $0xc2202573
+ MOV X10, ret+0(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/cpu/cpu_sparc64.go b/vendor/golang.org/x/sys/cpu/cpu_sparc64.go
new file mode 100644
index 0000000..0199ef1
--- /dev/null
+++ b/vendor/golang.org/x/sys/cpu/cpu_sparc64.go
@@ -0,0 +1,12 @@
+// Copyright 2026 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 sparc64
+
+package cpu
+
+// The L1 line is 32 bytes; false sharing is governed by the 64-byte L2 line.
+const cacheLineSize = 64
+
+func initOptions() {}
diff --git a/vendor/golang.org/x/sys/cpu/parse.go b/vendor/golang.org/x/sys/cpu/parse.go
index 56a7e1a..12a99af 100644
--- a/vendor/golang.org/x/sys/cpu/parse.go
+++ b/vendor/golang.org/x/sys/cpu/parse.go
@@ -6,38 +6,50 @@ package cpu
import "strconv"
-// parseRelease parses a dot-separated version number. It follows the semver
-// syntax, but allows the minor and patch versions to be elided.
+// parseRelease parses a dot-separated version number from the prefix
+// of rel. It returns ok=true only if at least the major and minor
+// components were successfully parsed; the patch component is
+// best-effort. Trailing vendor or build suffixes such as
+// "-generic", "+", "_hi3535", or "-rc1" are ignored.
//
// This is a copy of the Go runtime's parseRelease from
-// https://golang.org/cl/209597.
+// https://golang.org/cl/209597, updated in https://golang.org/cl/781800.
func parseRelease(rel string) (major, minor, patch int, ok bool) {
- // Strip anything after a dash or plus.
- for i := range len(rel) {
- if rel[i] == '-' || rel[i] == '+' {
- rel = rel[:i]
- break
+ // next consumes a run of decimal digits from the front of rel,
+ // returning the parsed value. If the digits are followed by a
+ // '.', it is consumed and more is set so the caller knows to
+ // parse another component; otherwise scanning terminates and
+ // the rest of rel is discarded.
+ next := func() (n int, more, ok bool) {
+ i := 0
+ for i < len(rel) && rel[i] >= '0' && rel[i] <= '9' {
+ i++
}
- }
-
- next := func() (int, bool) {
- for i := range len(rel) {
- if rel[i] == '.' {
- ver, err := strconv.Atoi(rel[:i])
- rel = rel[i+1:]
- return ver, err == nil
- }
+ if i == 0 {
+ return 0, false, false
+ }
+ n, err := strconv.Atoi(rel[:i])
+ if err != nil {
+ return 0, false, false
+ }
+ if i < len(rel) && rel[i] == '.' {
+ rel = rel[i+1:]
+ return n, true, true
}
- ver, err := strconv.Atoi(rel)
rel = ""
- return ver, err == nil
+ return n, false, true
+ }
+
+ var more bool
+ if major, more, ok = next(); !ok || !more {
+ return 0, 0, 0, false
}
- if major, ok = next(); !ok || rel == "" {
- return
+ if minor, more, ok = next(); !ok {
+ return 0, 0, 0, false
}
- if minor, ok = next(); !ok || rel == "" {
- return
+ if !more {
+ return major, minor, 0, true
}
- patch, ok = next()
- return
+ patch, _, _ = next()
+ return major, minor, patch, true
}
diff --git a/vendor/golang.org/x/sys/unix/ifreq_linux.go b/vendor/golang.org/x/sys/unix/ifreq_linux.go
index 309f5a2..3f7fa76 100644
--- a/vendor/golang.org/x/sys/unix/ifreq_linux.go
+++ b/vendor/golang.org/x/sys/unix/ifreq_linux.go
@@ -22,7 +22,13 @@ import (
// fields can be get and set using the following methods:
// - Uint16/SetUint16: flags
// - Uint32/SetUint32: ifindex, metric, mtu
-type Ifreq struct{ raw ifreq }
+type Ifreq struct {
+ // Aligns the union for the accessors below, which cast it in place;
+ // the generated ifreq is all byte arrays, so its alignment is one.
+ _ [0]int64
+
+ raw ifreq
+}
// NewIfreq creates an Ifreq with the input network interface name after
// validating the name does not exceed IFNAMSIZ-1 (trailing NULL required)
diff --git a/vendor/golang.org/x/sys/unix/ioctl_linux.go b/vendor/golang.org/x/sys/unix/ioctl_linux.go
index 7ca4fa1..5589d4f 100644
--- a/vendor/golang.org/x/sys/unix/ioctl_linux.go
+++ b/vendor/golang.org/x/sys/unix/ioctl_linux.go
@@ -332,3 +332,10 @@ func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
func IoctlLoopConfigure(fd int, value *LoopConfig) error {
return ioctlPtr(fd, LOOP_CONFIGURE, unsafe.Pointer(value))
}
+
+// IoctlPidfdInfo fetches information about a pidfd.
+// The Mask field of the info argument indicates which
+// values to fetch.
+func IoctlPidfdInfo(fd int, info *PidfdInfo) error {
+ return ioctlPtr(fd, PIDFD_GET_INFO, unsafe.Pointer(info))
+}
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index fa74cfe..9e907ac 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -290,14 +290,7 @@ struct ltchars {
#include
#include
-#if defined(__sparc__)
-// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
-// definition in glibc. As only the error constants are needed here, include the
-// generic termibits.h (which is included by termbits.h on sparc).
-#include
-#else
#include
-#endif
#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc
@@ -544,7 +537,7 @@ ccflags="$@"
$2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
$2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
$2 == "LOOP_CONFIGURE" ||
- $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
+ $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MREMAP|MFD|MLOCK|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL|TCPOPT|UDP)_/ ||
$2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ ||
$2 ~ /^NFC_.*_(MAX)?SIZE$/ ||
$2 ~ /^PTP_/ ||
diff --git a/vendor/golang.org/x/sys/unix/syscall.go b/vendor/golang.org/x/sys/unix/syscall.go
index 5ea74da..8f27e7e 100644
--- a/vendor/golang.org/x/sys/unix/syscall.go
+++ b/vendor/golang.org/x/sys/unix/syscall.go
@@ -76,7 +76,7 @@ func BytePtrToString(p *byte) string {
// Find NUL terminator.
n := 0
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
- ptr = unsafe.Pointer(uintptr(ptr) + 1)
+ ptr = unsafe.Add(ptr, 1)
}
return string(unsafe.Slice(p, n))
diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go
index a00c3e5..035c2cd 100644
--- a/vendor/golang.org/x/sys/unix/syscall_bsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_bsd.go
@@ -188,7 +188,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
}
sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
sa.raw.Family = AF_UNIX
- for i := 0; i < n; i++ {
+ for i := range n {
sa.raw.Path[i] = int8(name[i])
}
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index ce4d7ab..6926057 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -1874,6 +1874,7 @@ func Dup2(oldfd, newfd int) error {
//sys Dup3(oldfd int, newfd int, flags int) (err error)
//sysnb EpollCreate1(flag int) (fd int, err error)
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD2
//sys Exit(code int) = SYS_EXIT_GROUP
//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
@@ -2362,7 +2363,7 @@ func (fh *FileHandle) Bytes() []byte {
if n == 0 {
return nil
}
- return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type))+4)), n)
+ return unsafe.Slice((*byte)(unsafe.Add(unsafe.Pointer(&fh.fileHandle.Type), 4)), n)
}
// NameToHandleAt wraps the name_to_handle_at system call; it obtains
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_386.go
index 506dafa..210d545 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_386.go
@@ -20,7 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
// 64-bit file system and 32-bit uid calls
// (386 default is 32-bit file system and 16-bit uid).
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
index d557cf8..a9a52f2 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
index ecf92bf..54474c2 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
@@ -44,7 +44,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
// 64-bit file system and 32-bit uid calls
// (16-bit uid calls are not always supported in newer kernels)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
index 1737380..e9f30db 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
@@ -8,7 +8,6 @@ package unix
import "unsafe"
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
index a3fd1d0..6f09ca2 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
@@ -8,7 +8,6 @@ package unix
import "unsafe"
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
index 70963a9..ca3b565 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
index c218ebd..54ba667 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
@@ -13,7 +13,6 @@ import (
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
index e6c4850..ce46285 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
@@ -11,7 +11,6 @@ import (
"unsafe"
)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
index 7286a9a..33f7af3 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
index fc5543c..c658871 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
@@ -8,7 +8,6 @@ package unix
import "unsafe"
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
index 66f3121..2c85876 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
@@ -10,7 +10,6 @@ import (
"unsafe"
)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
index 11d1f16..4964119 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
@@ -6,7 +6,6 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index 9d72a6b..45feb12 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -1359,6 +1359,7 @@ const (
FAN_UNLIMITED_MARKS = 0x20
FAN_UNLIMITED_QUEUE = 0x10
FD_CLOEXEC = 0x1
+ FD_PIDFS_ROOT = -0x2712
FD_SETSIZE = 0x400
FF0 = 0x0
FIB_RULE_DEV_DETACHED = 0x8
@@ -1970,6 +1971,8 @@ const (
MADV_DONTNEED = 0x4
MADV_DONTNEED_LOCKED = 0x18
MADV_FREE = 0x8
+ MADV_GUARD_INSTALL = 0x66
+ MADV_GUARD_REMOVE = 0x67
MADV_HUGEPAGE = 0xe
MADV_HWPOISON = 0x64
MADV_KEEPONFORK = 0x13
@@ -2045,6 +2048,7 @@ const (
MINIX3_SUPER_MAGIC = 0x4d5a
MINIX_SUPER_MAGIC = 0x137f
MINIX_SUPER_MAGIC2 = 0x138f
+ MLOCK_ONFAULT = 0x1
MNT_DETACH = 0x2
MNT_EXPIRE = 0x4
MNT_FORCE = 0x1
@@ -2114,7 +2118,7 @@ const (
MS_NOSEC = 0x10000000
MS_NOSUID = 0x2
MS_NOSYMFOLLOW = 0x100
- MS_NOUSER = -0x80000000
+ MS_NOUSER = 0x80000000
MS_POSIXACL = 0x10000
MS_PRIVATE = 0x40000
MS_RDONLY = 0x1
@@ -3786,6 +3790,9 @@ const (
TCPOPT_TIMESTAMP = 0x8
TCPOPT_TSTAMP_HDR = 0x101080a
TCPOPT_WINDOW = 0x3
+ TCP_AO_KEYF_EXCLUDE_OPT = 0x2
+ TCP_AO_KEYF_IFINDEX = 0x1
+ TCP_AO_MAXKEYLEN = 0x50
TCP_CC_INFO = 0x1a
TCP_CM_INQ = 0x24
TCP_CONGESTION = 0xd
@@ -3856,6 +3863,7 @@ const (
TIOCPKT_NOSTOP = 0x10
TIOCPKT_START = 0x8
TIOCPKT_STOP = 0x4
+ TIOCSER_TEMT = 0x1
TIPC_ADDR_ID = 0x3
TIPC_ADDR_MCAST = 0x1
TIPC_ADDR_NAME = 0x2
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
index c0a8ea1..6f74d4a 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
@@ -483,7 +483,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
TIOCSIG = 0x40045436
TIOCSISO7816 = 0xc0285443
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
index ff927c8..36c1f0b 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
@@ -484,7 +484,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
TIOCSIG = 0x40045436
TIOCSISO7816 = 0xc0285443
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
index 55294ed..c5512db 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
@@ -489,7 +489,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
TIOCSIG = 0x40045436
TIOCSISO7816 = 0xc0285443
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
index 5dac54c..4dabfae 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
@@ -483,7 +483,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
TIOCSIG = 0x40045436
TIOCSISO7816 = 0xc0285443
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
index 46ac1fc..ea97930 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
@@ -476,7 +476,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
TIOCSIG = 0x40045436
TIOCSISO7816 = 0xc0285443
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
index b55483e..0826a92 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
@@ -481,7 +481,6 @@ const (
TIOCSERGWILD = 0x5489
TIOCSERSETMULTI = 0x5490
TIOCSERSWILD = 0x548a
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x7401
TIOCSETN = 0x740a
TIOCSETP = 0x7409
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
index 71890c9..139deed 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
@@ -481,7 +481,6 @@ const (
TIOCSERGWILD = 0x5489
TIOCSERSETMULTI = 0x5490
TIOCSERSWILD = 0x548a
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x7401
TIOCSETN = 0x740a
TIOCSETP = 0x7409
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
index a78b6cc..b8018af 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
@@ -481,7 +481,6 @@ const (
TIOCSERGWILD = 0x5489
TIOCSERSETMULTI = 0x5490
TIOCSERSWILD = 0x548a
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x7401
TIOCSETN = 0x740a
TIOCSETP = 0x7409
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
index d0e38ca..deb5c2e 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
@@ -481,7 +481,6 @@ const (
TIOCSERGWILD = 0x5489
TIOCSERSETMULTI = 0x5490
TIOCSERSWILD = 0x548a
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x7401
TIOCSETN = 0x740a
TIOCSETP = 0x7409
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
index c883e14..0603bf3 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
@@ -535,7 +535,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETC = 0x80067411
TIOCSETD = 0x5423
TIOCSETN = 0x8006740a
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
index 1834273..5fa8a5d 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
@@ -539,7 +539,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETC = 0x80067411
TIOCSETD = 0x5423
TIOCSETN = 0x8006740a
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
index 39945dd..2733e99 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
@@ -539,7 +539,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETC = 0x80067411
TIOCSETD = 0x5423
TIOCSETN = 0x8006740a
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
index bc0f372..1470172 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
@@ -486,7 +486,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
TIOCSIG = 0x40045436
TIOCSISO7816 = 0xc0285443
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
index 6e87bd6..1871579 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
@@ -545,7 +545,6 @@ const (
TIOCSERGWILD = 0x5454
TIOCSERSETMULTI = 0x545b
TIOCSERSWILD = 0x5455
- TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
TIOCSIG = 0x40045436
TIOCSISO7816 = 0xc0285443
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
index 7e2b2e8..10881cf 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
@@ -14,21 +14,21 @@ const (
ASI_LEON_DFLUSH = 0x11
ASI_LEON_IFLUSH = 0x10
ASI_LEON_MMUFLUSH = 0x18
- B1000000 = 0x1008
+ B1000000 = 0x100c
B115200 = 0x1002
- B1152000 = 0x1009
- B1500000 = 0x100a
- B2000000 = 0x100b
+ B1152000 = 0x100d
+ B1500000 = 0x100e
+ B153600 = 0x1006
+ B2000000 = 0x100f
B230400 = 0x1003
- B2500000 = 0x100c
- B3000000 = 0x100d
- B3500000 = 0x100e
- B4000000 = 0x100f
+ B307200 = 0x1007
B460800 = 0x1004
- B500000 = 0x1005
+ B500000 = 0x100a
B57600 = 0x1001
- B576000 = 0x1006
- B921600 = 0x1007
+ B576000 = 0x100b
+ B614400 = 0x1008
+ B76800 = 0x1005
+ B921600 = 0x1009
BLKALIGNOFF = 0x2000127a
BLKBSZGET = 0x40081270
BLKBSZSET = 0x80081271
@@ -91,7 +91,7 @@ const (
FFDLY = 0x8000
FICLONE = 0x80049409
FICLONERANGE = 0x8020940d
- FLUSHO = 0x1000
+ FLUSHO = 0x2000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40086601
FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
@@ -563,6 +563,9 @@ const (
TIOCM_CD = 0x40
TIOCM_CTS = 0x20
TIOCM_DSR = 0x100
+ TIOCM_LOOP = 0x8000
+ TIOCM_OUT1 = 0x2000
+ TIOCM_OUT2 = 0x4000
TIOCM_RI = 0x80
TIOCM_RNG = 0x80
TIOCM_SR = 0x10
@@ -641,10 +644,11 @@ const (
UBI_IOCVOLRMBLK = 0x20004f08
UBI_IOCVOLUP = 0x80084f00
VDISCARD = 0xd
+ VDSUSP = 0xb
VEOF = 0x4
- VEOL = 0xb
- VEOL2 = 0x10
- VMIN = 0x6
+ VEOL = 0x5
+ VEOL2 = 0x6
+ VMIN = 0x4
VREPRINT = 0xc
VSTART = 0x8
VSTOP = 0x9
@@ -664,6 +668,7 @@ const (
WDIOC_KEEPALIVE = 0x40045705
WDIOC_SETOPTIONS = 0x40045704
WORDSIZE = 0x40
+ WRAP = 0x20000
XCASE = 0x4
XTABS = 0x1800
_HIDIOCGRAWNAME = 0x40804804
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
index 80f40e4..5788c2a 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
@@ -700,6 +700,23 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Eventfd(initval uint, flags int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0)
fd = int(r0)
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
index 4def3e9..254f339 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64_64, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
index fef2bc8..27c05db 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
index a9fd76a..840d85b 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
@@ -213,23 +213,6 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
index 4600650..fe41449 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
index c8987d2..eb358ce 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
index 921f430..c437622 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset>>32), uintptr(offset), uintptr(length>>32), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
index 44f0678..bc4ca25 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
index e7fa0ab..5051435 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
index 8c51256..33aa541 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
index 7392fd4..3bef8ef 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
index 4118043..fc1bd4e 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
index 40c6ce7..d78fe7d 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
index 2cfe34a..76dcf87 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
index 61e6f07..2cf020f 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
index 834b842..5276376 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(events) > 0 {
- _p0 = unsafe.Pointer(&events[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go
index 526a0d5..538a18f 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -4264,19 +4264,29 @@ type HwTstampConfig struct {
}
const (
- HWTSTAMP_FILTER_NONE = 0x0
- HWTSTAMP_FILTER_ALL = 0x1
- HWTSTAMP_FILTER_SOME = 0x2
- HWTSTAMP_FILTER_PTP_V1_L4_EVENT = 0x3
- HWTSTAMP_FILTER_PTP_V2_L4_EVENT = 0x6
- HWTSTAMP_FILTER_PTP_V2_L2_EVENT = 0x9
- HWTSTAMP_FILTER_PTP_V2_EVENT = 0xc
+ HWTSTAMP_FILTER_NONE = 0x0
+ HWTSTAMP_FILTER_ALL = 0x1
+ HWTSTAMP_FILTER_SOME = 0x2
+ HWTSTAMP_FILTER_PTP_V1_L4_EVENT = 0x3
+ HWTSTAMP_FILTER_PTP_V1_L4_SYNC = 0x4
+ HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ = 0x5
+ HWTSTAMP_FILTER_PTP_V2_L4_EVENT = 0x6
+ HWTSTAMP_FILTER_PTP_V2_L4_SYNC = 0x7
+ HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ = 0x8
+ HWTSTAMP_FILTER_PTP_V2_L2_EVENT = 0x9
+ HWTSTAMP_FILTER_PTP_V2_L2_SYNC = 0xa
+ HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ = 0xb
+ HWTSTAMP_FILTER_PTP_V2_EVENT = 0xc
+ HWTSTAMP_FILTER_PTP_V2_SYNC = 0xd
+ HWTSTAMP_FILTER_PTP_V2_DELAY_REQ = 0xe
+ HWTSTAMP_FILTER_NTP_ALL = 0xf
)
const (
HWTSTAMP_TX_OFF = 0x0
HWTSTAMP_TX_ON = 0x1
HWTSTAMP_TX_ONESTEP_SYNC = 0x2
+ HWTSTAMP_TX_ONESTEP_P2P = 0x3
)
type (
@@ -4541,6 +4551,48 @@ const (
LANDLOCK_RULE_PATH_BENEATH = 0x1
)
+const (
+ PIDFD_SIGNAL_THREAD = 0x1
+ PIDFD_SIGNAL_THREAD_GROUP = 0x2
+ PIDFD_SIGNAL_PROCESS_GROUP = 0x4
+ PIDFD_SELF_THREAD = -0x2710
+ PIDFD_SELF_THREAD_GROUP = -0x2711
+ PIDFD_SELF = -0x2710
+ PIDFD_SELF_PROCESS = -0x2711
+ PIDFD_INFO_PID = 0x1
+ PIDFD_INFO_CREDS = 0x2
+ PIDFD_INFO_CGROUPID = 0x4
+ PIDFD_INFO_EXIT = 0x8
+ PIDFD_INFO_COREDUMP = 0x10
+ PIDFD_COREDUMPED = 0x1
+ PIDFD_COREDUMP_SKIP = 0x2
+ PIDFD_COREDUMP_USER = 0x4
+ PIDFD_COREDUMP_ROOT = 0x8
+ PIDFD_INFO_SIZE_VER0 = 0x40
+ PIDFD_GET_INFO = 0xc048ff0b
+)
+
+const SizeofPidfdInfo = 0x48
+
+type PidfdInfo struct {
+ Mask uint64
+ Cgroupid uint64
+ Pid uint32
+ Tgid uint32
+ Ppid uint32
+ Ruid uint32
+ Rgid uint32
+ Euid uint32
+ Egid uint32
+ Suid uint32
+ Sgid uint32
+ Fsuid uint32
+ Fsgid uint32
+ Exit_code int32
+ Coredump_mask uint32
+ _ uint32
+}
+
const (
IPC_CREAT = 0x200
IPC_EXCL = 0x400
@@ -6473,3 +6525,23 @@ type GPIOV2LineEvent struct {
Line_seqno uint32
_ [6]uint32
}
+
+const (
+ IPMI_MAX_ADDR_SIZE = 0x20
+ IPMI_SYSTEM_INTERFACE_ADDR_TYPE = 0xc
+ IPMI_BMC_CHANNEL = 0xf
+ IPMI_RESPONSE_RECV_TYPE = 0x1
+)
+
+type IPMISystemInterfaceAddr struct {
+ Type int32
+ Channel int16
+ Lun uint8
+ _ [1]byte
+}
+type IPMIMsg struct {
+ Netfn uint8
+ Cmd uint8
+ Len uint16
+ Data *uint8
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
index aede1de..38658a3 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
@@ -680,7 +680,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0xff01
+ PIDFD_GET_IPC_NAMESPACE = 0xff02
+ PIDFD_GET_MNT_NAMESPACE = 0xff03
+ PIDFD_GET_NET_NAMESPACE = 0xff04
+ PIDFD_GET_PID_NAMESPACE = 0xff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0xff06
+ PIDFD_GET_TIME_NAMESPACE = 0xff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0xff08
+ PIDFD_GET_USER_NAMESPACE = 0xff09
+ PIDFD_GET_UTS_NAMESPACE = 0xff0a
)
type SysvIpcPerm struct {
@@ -715,3 +726,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x8044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x8014690d
+ IPMICTL_RECEIVE_MSG = 0xc018690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
index bb3bc4d..267ffe0 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
@@ -697,7 +697,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0xff01
+ PIDFD_GET_IPC_NAMESPACE = 0xff02
+ PIDFD_GET_MNT_NAMESPACE = 0xff03
+ PIDFD_GET_NET_NAMESPACE = 0xff04
+ PIDFD_GET_PID_NAMESPACE = 0xff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0xff06
+ PIDFD_GET_TIME_NAMESPACE = 0xff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0xff08
+ PIDFD_GET_USER_NAMESPACE = 0xff09
+ PIDFD_GET_UTS_NAMESPACE = 0xff0a
)
type SysvIpcPerm struct {
@@ -729,3 +740,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x8044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x8028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
index 1fdf4c5..ec459d5 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
@@ -674,7 +674,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0xff01
+ PIDFD_GET_IPC_NAMESPACE = 0xff02
+ PIDFD_GET_MNT_NAMESPACE = 0xff03
+ PIDFD_GET_NET_NAMESPACE = 0xff04
+ PIDFD_GET_PID_NAMESPACE = 0xff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0xff06
+ PIDFD_GET_TIME_NAMESPACE = 0xff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0xff08
+ PIDFD_GET_USER_NAMESPACE = 0xff09
+ PIDFD_GET_UTS_NAMESPACE = 0xff0a
)
type SysvIpcPerm struct {
@@ -709,3 +720,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x8044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x8014690d
+ IPMICTL_RECEIVE_MSG = 0xc018690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
index 063e6f0..fa45ab7 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
@@ -676,7 +676,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0xff01
+ PIDFD_GET_IPC_NAMESPACE = 0xff02
+ PIDFD_GET_MNT_NAMESPACE = 0xff03
+ PIDFD_GET_NET_NAMESPACE = 0xff04
+ PIDFD_GET_PID_NAMESPACE = 0xff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0xff06
+ PIDFD_GET_TIME_NAMESPACE = 0xff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0xff08
+ PIDFD_GET_USER_NAMESPACE = 0xff09
+ PIDFD_GET_UTS_NAMESPACE = 0xff0a
)
type SysvIpcPerm struct {
@@ -708,3 +719,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x8044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x8028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
index 9cf836c..3da72cc 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
@@ -677,7 +677,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0xff01
+ PIDFD_GET_IPC_NAMESPACE = 0xff02
+ PIDFD_GET_MNT_NAMESPACE = 0xff03
+ PIDFD_GET_NET_NAMESPACE = 0xff04
+ PIDFD_GET_PID_NAMESPACE = 0xff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0xff06
+ PIDFD_GET_TIME_NAMESPACE = 0xff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0xff08
+ PIDFD_GET_USER_NAMESPACE = 0xff09
+ PIDFD_GET_UTS_NAMESPACE = 0xff0a
)
type SysvIpcPerm struct {
@@ -709,3 +720,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x8044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x8028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
index 1d222fc..78f8c6d 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
@@ -680,7 +680,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x80
+ PIDFD_NONBLOCK = 0x80
+ PIDFD_THREAD = 0x400
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -714,3 +725,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4014690d
+ IPMICTL_RECEIVE_MSG = 0xc018690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
index 912cc4a..bbd4c6c 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
@@ -679,7 +679,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x80
+ PIDFD_NONBLOCK = 0x80
+ PIDFD_THREAD = 0x400
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -711,3 +722,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
index 1e358ef..644d31d 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
@@ -679,7 +679,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x80
+ PIDFD_NONBLOCK = 0x80
+ PIDFD_THREAD = 0x400
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -711,3 +722,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
index df59f32..a976f62 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
@@ -680,7 +680,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x80
+ PIDFD_NONBLOCK = 0x80
+ PIDFD_THREAD = 0x400
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -714,3 +725,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4014690d
+ IPMICTL_RECEIVE_MSG = 0xc018690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
index 29355aa..4632469 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
@@ -686,7 +686,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -722,3 +733,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4014690d
+ IPMICTL_RECEIVE_MSG = 0xc018690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int32
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
index c6083a1..cbc3039 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
@@ -686,7 +686,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -717,3 +728,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
index 6321cc7..b47f7b4 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
@@ -686,7 +686,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -717,3 +728,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
index b44f402..cb16add 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
@@ -704,7 +704,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0xff01
+ PIDFD_GET_IPC_NAMESPACE = 0xff02
+ PIDFD_GET_MNT_NAMESPACE = 0xff03
+ PIDFD_GET_NET_NAMESPACE = 0xff04
+ PIDFD_GET_PID_NAMESPACE = 0xff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0xff06
+ PIDFD_GET_TIME_NAMESPACE = 0xff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0xff08
+ PIDFD_GET_USER_NAMESPACE = 0xff09
+ PIDFD_GET_UTS_NAMESPACE = 0xff0a
)
type SysvIpcPerm struct {
@@ -796,3 +807,22 @@ const (
const (
GPIO_GET_CHIPINFO_IOCTL = 0x8044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x8028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
index b22c795..a57ab8f 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
@@ -700,7 +700,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x800
+ PIDFD_NONBLOCK = 0x800
+ PIDFD_THREAD = 0x80
+ PIDFD_GET_CGROUP_NAMESPACE = 0xff01
+ PIDFD_GET_IPC_NAMESPACE = 0xff02
+ PIDFD_GET_MNT_NAMESPACE = 0xff03
+ PIDFD_GET_NET_NAMESPACE = 0xff04
+ PIDFD_GET_PID_NAMESPACE = 0xff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0xff06
+ PIDFD_GET_TIME_NAMESPACE = 0xff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0xff08
+ PIDFD_GET_USER_NAMESPACE = 0xff09
+ PIDFD_GET_UTS_NAMESPACE = 0xff0a
)
type SysvIpcPerm struct {
@@ -731,3 +742,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x8044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x8028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
index 0b18075..bf99635 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
@@ -681,7 +681,18 @@ const (
)
const (
- PIDFD_NONBLOCK = 0x4000
+ PIDFD_NONBLOCK = 0x4000
+ PIDFD_THREAD = 0x800
+ PIDFD_GET_CGROUP_NAMESPACE = 0x2000ff01
+ PIDFD_GET_IPC_NAMESPACE = 0x2000ff02
+ PIDFD_GET_MNT_NAMESPACE = 0x2000ff03
+ PIDFD_GET_NET_NAMESPACE = 0x2000ff04
+ PIDFD_GET_PID_NAMESPACE = 0x2000ff05
+ PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE = 0x2000ff06
+ PIDFD_GET_TIME_NAMESPACE = 0x2000ff07
+ PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE = 0x2000ff08
+ PIDFD_GET_USER_NAMESPACE = 0x2000ff09
+ PIDFD_GET_UTS_NAMESPACE = 0x2000ff0a
)
type SysvIpcPerm struct {
@@ -712,3 +723,22 @@ type SysvShmDesc struct {
const (
GPIO_GET_CHIPINFO_IOCTL = 0x4044b401
)
+
+const (
+ IPMICTL_SEND_COMMAND = 0x4028690d
+ IPMICTL_RECEIVE_MSG = 0xc030690c
+)
+
+type IPMIReq struct {
+ Addr *uint8
+ Len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
+type IPMIRecv struct {
+ Recv_type int32
+ Addr *uint8
+ Addr_len uint32
+ Msgid int64
+ Msg IPMIMsg
+}
diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go
index 6c955ce..7836215 100644
--- a/vendor/golang.org/x/sys/windows/security_windows.go
+++ b/vendor/golang.org/x/sys/windows/security_windows.go
@@ -1109,17 +1109,53 @@ const (
)
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
+//
+// Go pointers stored in a TrusteeValue must be pinned using [runtime.Pinner]
+// for the lifetime of the TrusteeValue.
type TrusteeValue uintptr
+// TrusteeValueFromString is unsafe and should not be used.
+//
+// It returns a uintptr containing a reference to newly-allocated memory
+// which will be freed by the garbage collector.
+// There is no way for the caller to safely reference this memory.
+//
+// To create a [TrusteeValue] from a string, use:
+//
+// p, err := windows.UTF16PtrFromString(s)
+// if err != nil {
+// // handle error
+// }
+//
+// // Pin the string for as long as it is used.
+// var pinner runtime.Pinner
+// pinner.Pin(p)
+// defer pinner.Unpin()
+//
+// tv := TrusteeValue(unsafe.Pointer(p))
+//
+// Deprecated: TrusteeValueFromString is unsafe and should not be used.
func TrusteeValueFromString(str string) TrusteeValue {
return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str)))
}
+
+// TrusteeValueFromSID returns a [TrusteeValue] referencing sid.
+//
+// The caller must pin sid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
func TrusteeValueFromSID(sid *SID) TrusteeValue {
return TrusteeValue(unsafe.Pointer(sid))
}
+
+// TrusteeValueFromObjectsAndSid returns a [TrusteeValue] referencing objectsAndSid.
+//
+// The caller must pin objectsAndSid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue {
return TrusteeValue(unsafe.Pointer(objectsAndSid))
}
+
+// TrusteeValueFromObjectsAndName returns a [TrusteeValue] referencing objectsAndName.
+//
+// The caller must pin objectsAndName using a [runtime.Pinner] for the lifetime of the TrusteeValue.
func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue {
return TrusteeValue(unsafe.Pointer(objectsAndName))
}
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 9755bca..e6966b4 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -1728,11 +1728,15 @@ func (s *NTUnicodeString) String() string {
// the more common *uint16 string type.
func NewNTString(s string) (*NTString, error) {
var nts NTString
- s8, err := BytePtrFromString(s)
+ s8, err := ByteSliceFromString(s)
if err != nil {
return nil, err
}
- RtlInitString(&nts, s8)
+ // The source string plus its terminating NUL must fit within MAX_USHORT.
+ if len(s8) > MAX_USHORT {
+ return nil, syscall.EINVAL
+ }
+ RtlInitString(&nts, &s8[0])
return &nts, nil
}
diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go
index d2574a7..643737d 100644
--- a/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/vendor/golang.org/x/sys/windows/types_windows.go
@@ -169,6 +169,7 @@ const (
FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
+ MAX_USHORT = 0xffff
MAX_PATH = 260
MAX_LONG_PATH = 32768
@@ -1064,6 +1065,7 @@ const (
SO_BROADCAST = 32
SO_LINGER = 128
SO_RCVBUF = 0x1002
+ SO_SNDTIMEO = 0x1005
SO_RCVTIMEO = 0x1006
SO_SNDBUF = 0x1001
SO_UPDATE_ACCEPT_CONTEXT = 0x700b
diff --git a/vendor/golang.org/x/term/terminal.go b/vendor/golang.org/x/term/terminal.go
index 6ec537c..e8327c8 100644
--- a/vendor/golang.org/x/term/terminal.go
+++ b/vendor/golang.org/x/term/terminal.go
@@ -106,6 +106,9 @@ type Terminal struct {
// a read. It aliases into inBuf.
remainder []byte
inBuf [256]byte
+ // readErr is an error returned by a read that also returned data. It is
+ // reported after all of that data has been processed.
+ readErr error
// History records and retrieves lines of input read by [ReadLine] which
// a user can retrieve and navigate using the up and down arrow keys.
@@ -788,7 +791,11 @@ func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
return
}
-// ReadLine returns a line of input from the terminal.
+// ReadLine returns a line of input from the terminal, excluding the
+// trailing newline. It may return partial data along with an error.
+// An [io.EOF] error indicates the end of the stream. For other errors,
+// such as [ErrPasteIndicator] in bracketed paste mode, a subsequent
+// call may return more data.
func (t *Terminal) ReadLine() (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()
@@ -863,21 +870,24 @@ func (t *Terminal) readLine() (line string, err error) {
}
return
}
+ if t.readErr != nil {
+ err = t.readErr
+ t.readErr = nil
+ return
+ }
// t.remainder is a slice at the beginning of t.inBuf
// containing a partial key sequence
readBuf := t.inBuf[len(t.remainder):]
- var n int
t.lock.Unlock()
- n, err = t.c.Read(readBuf)
+ n, readErr := t.c.Read(readBuf)
t.lock.Lock()
- if err != nil {
- return
- }
-
t.remainder = t.inBuf[:n+len(t.remainder)]
+ if readErr != nil {
+ t.readErr = readErr
+ }
}
}
diff --git a/vendor/golang.org/x/text/unicode/bidi/core.go b/vendor/golang.org/x/text/unicode/bidi/core.go
index fb82732..e28ac8c 100644
--- a/vendor/golang.org/x/text/unicode/bidi/core.go
+++ b/vendor/golang.org/x/text/unicode/bidi/core.go
@@ -6,7 +6,6 @@ package bidi
import (
"fmt"
- "log"
)
// This implementation is a port based on the reference implementation found at:
@@ -248,7 +247,7 @@ func (p *paragraph) determineParagraphEmbeddingLevel(start, end int) level {
} else if t.in(FSI, LRI, RLI) {
i = p.matchingPDI[i] // skip over to the matching PDI
if i > end {
- log.Panic("assert (i <= end)")
+ panic("assert (i <= end)")
}
}
}
@@ -729,7 +728,7 @@ loop:
continue loop
}
}
- log.Panicf("invalid bidi code %v present in assertOnly at position %d", t, s.indexes[i])
+ panic(fmt.Errorf("invalid bidi code %v present in assertOnly at position %d", t, s.indexes[i]))
}
}
diff --git a/vendor/golang.org/x/text/unicode/norm/composition.go b/vendor/golang.org/x/text/unicode/norm/composition.go
index e2087bc..e024e74 100644
--- a/vendor/golang.org/x/text/unicode/norm/composition.go
+++ b/vendor/golang.org/x/text/unicode/norm/composition.go
@@ -449,6 +449,16 @@ func (rb *reorderBuffer) combineHangul(s, i, k int) {
// ACxx plus 11Ax to LVT
rb.assignRune(s, l+v-jamoTBase)
default:
+ // Not a Hangul composition. The segment may still
+ // contain regular canonical compositions, such as
+ // combining marks following a Hangul syllable, so
+ // fall back to the composition table.
+ if b[i].combinesBackward() {
+ if combined := combine(l, v); combined != 0 {
+ rb.assignRune(s, combined)
+ continue
+ }
+ }
b[k] = b[i]
k++
}
@@ -484,25 +494,27 @@ func (rb *reorderBuffer) compose() {
return
}
ii := b[i]
+ // Track the last starter unconditionally: b[i] must be blocked by
+ // any starter between it and s, even one that b[i] itself cannot
+ // combine with, and even if the runes in between never enter the
+ // combinesBackward branch below.
+ cccB := b[k-1].ccc
+ cccC := ii.ccc
+ blocked := false // b[i] blocked by starter or greater or equal CCC?
+ if cccB == 0 {
+ s = k - 1
+ } else {
+ blocked = s != k-1 && cccB >= cccC
+ }
// We can only use combineForward as a filter if we later
// get the info for the combined character. This is more
// expensive than using the filter. Using combinesBackward()
// is safe.
- if ii.combinesBackward() {
- cccB := b[k-1].ccc
- cccC := ii.ccc
- blocked := false // b[i] blocked by starter or greater or equal CCC?
- if cccB == 0 {
- s = k - 1
- } else {
- blocked = s != k-1 && cccB >= cccC
- }
- if !blocked {
- combined := combine(rb.runeAt(s), rb.runeAt(i))
- if combined != 0 {
- rb.assignRune(s, combined)
- continue
- }
+ if ii.combinesBackward() && !blocked {
+ combined := combine(rb.runeAt(s), rb.runeAt(i))
+ if combined != 0 {
+ rb.assignRune(s, combined)
+ continue
}
}
b[k] = b[i]
diff --git a/vendor/golang.org/x/text/unicode/norm/forminfo.go b/vendor/golang.org/x/text/unicode/norm/forminfo.go
index f3a234e..956708e 100644
--- a/vendor/golang.org/x/text/unicode/norm/forminfo.go
+++ b/vendor/golang.org/x/text/unicode/norm/forminfo.go
@@ -121,8 +121,12 @@ func (p Properties) BoundaryAfter() bool {
//
// When all 6 bits are zero, the character is inert, meaning it is never
// influenced by normalization.
+//
+// We set flags to 0x80 (high bit 7 unused in quick check data) to indicate an invalid rune.
type qcInfo uint8
+func (p Properties) isInvalid() bool { return p.flags == 0x80 }
+
func (p Properties) isYesC() bool { return p.flags&0x10 == 0 }
func (p Properties) isYesD() bool { return p.flags&0x4 == 0 }
@@ -187,30 +191,30 @@ func (p Properties) TrailCCC() uint8 {
return ccc[p.tccc]
}
+// Recomposition
+// Each entry of recompMapPacked holds the two runes of the key and the
+// composed rune of the value packed into a big-endian uint64 as three
+// 21-bit fields, which is wide enough for any rune.
+// Note that the recomposition map for NFC and NFKC are identical.
+
+const recompShift = 21
+
func buildRecompMap() {
- recompMap = make(map[uint32]rune, len(recompMapPacked)/8)
+ recompMap = make(map[uint64]rune, len(recompMapPacked)/8)
var buf [8]byte
for i := 0; i < len(recompMapPacked); i += 8 {
copy(buf[:], recompMapPacked[i:i+8])
- key := binary.BigEndian.Uint32(buf[:4])
- val := binary.BigEndian.Uint32(buf[4:])
- recompMap[key] = rune(val)
+ e := binary.BigEndian.Uint64(buf[:])
+ recompMap[e>>recompShift] = rune(e & (1<= 0x8000 {
@@ -254,7 +261,7 @@ func compInfo(v uint16, sz int) Properties {
size: uint8(sz),
ccc: uint8(v),
tccc: uint8(v),
- flags: qcInfo(v >> 8),
+ flags: qcInfo(v>>8) & 0x3f,
}
if p.ccc > 0 || p.combinesBackward() {
p.nLead = uint8(p.flags & 0x3)
diff --git a/vendor/golang.org/x/text/unicode/norm/iter.go b/vendor/golang.org/x/text/unicode/norm/iter.go
index 417c6b2..3cc0592 100644
--- a/vendor/golang.org/x/text/unicode/norm/iter.go
+++ b/vendor/golang.org/x/text/unicode/norm/iter.go
@@ -376,16 +376,12 @@ func nextComposed(i *Iter) []byte {
goto doNorm
}
prevCC = i.info.tccc
- sz := int(i.info.size)
- if sz == 0 {
- sz = 1 // illegal rune: copy byte-by-byte
- }
- p := outp + sz
+ p := outp + int(i.info.size)
if p > len(i.buf) {
break
}
outp = p
- i.p += sz
+ i.p += int(i.info.size)
if i.p >= i.rb.nsrc {
i.setDone()
break
diff --git a/vendor/golang.org/x/text/unicode/norm/normalize.go b/vendor/golang.org/x/text/unicode/norm/normalize.go
index 4747ad0..d7345ab 100644
--- a/vendor/golang.org/x/text/unicode/norm/normalize.go
+++ b/vendor/golang.org/x/text/unicode/norm/normalize.go
@@ -148,7 +148,7 @@ func (f Form) IsNormalString(s string) bool {
// patched buffer and whether the decomposition is still in progress.
func patchTail(rb *reorderBuffer) bool {
info, p := lastRuneStart(&rb.f, rb.out)
- if p == -1 || info.size == 0 {
+ if p == -1 || info.isInvalid() {
return true
}
end := p + int(info.size)
@@ -225,7 +225,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
}
fd := &rb.f
if doMerge {
- var info Properties
+ info := Properties{flags: 0x80, size: 1} // invalid rune
if p < n {
info = fd.info(src, p)
if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 {
@@ -235,7 +235,7 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
p = decomposeSegment(rb, p, true)
}
}
- if info.size == 0 {
+ if info.isInvalid() {
rb.doFlush()
// Append incomplete UTF-8 encoding.
return src.appendSlice(rb.out, p, n)
@@ -314,7 +314,7 @@ func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool)
continue
}
info := f.info(src, i)
- if info.size == 0 {
+ if info.isInvalid() {
if atEOF {
// include incomplete runes
return n, true
@@ -379,7 +379,7 @@ func (f Form) firstBoundary(src input, nsrc int) int {
// CGJ insertion points correctly. Luckily it doesn't have to.
for {
info := fd.info(src, i)
- if info.size == 0 {
+ if info.isInvalid() {
return -1
}
if s := ss.next(info); s != ssSuccess {
@@ -424,7 +424,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
}
fd := formTable[f]
info := fd.info(src, 0)
- if info.size == 0 {
+ if info.isInvalid() {
if atEOF {
return 1
}
@@ -435,7 +435,7 @@ func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
for i := int(info.size); i < nsrc; i += int(info.size) {
info = fd.info(src, i)
- if info.size == 0 {
+ if info.isInvalid() {
if atEOF {
return i
}
@@ -465,7 +465,7 @@ func lastBoundary(fd *formInfo, b []byte) int {
if p == -1 {
return -1
}
- if info.size == 0 { // ends with incomplete rune
+ if info.isInvalid() { // ends with incomplete rune
if p == 0 { // starts with incomplete rune
return -1
}
@@ -504,8 +504,11 @@ func lastBoundary(fd *formInfo, b []byte) int {
func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
// Force one character to be consumed.
info := rb.f.info(rb.src, sp)
- if info.size == 0 {
- return 0
+ if info.isInvalid() {
+ // Consume the invalid character.
+ // Perhaps this should return iShortSrc instead?
+ // May not matter, this path does not appear to be reachable in practice.
+ return sp + 1
}
if s := rb.ss.next(info); s == ssStarter {
// TODO: this could be removed if we don't support merging.
@@ -528,7 +531,7 @@ func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
break
}
info = rb.f.info(rb.src, sp)
- if info.size == 0 {
+ if info.isInvalid() {
if !atEOF {
return int(iShortSrc)
}
diff --git a/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go b/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go
index d962324..c30c6f7 100644
--- a/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go
+++ b/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go
@@ -6958,950 +6958,950 @@ var nfkcSparseValues = [919]valueRange{
}
// recompMap: 7528 bytes (entries only)
-var recompMap map[uint32]rune
+var recompMap map[uint64]rune
var recompMapOnce sync.Once
const recompMapPacked = "" +
- "\x00A\x03\x00\x00\x00\x00\xc0" + // 0x00410300: 0x000000C0
- "\x00A\x03\x01\x00\x00\x00\xc1" + // 0x00410301: 0x000000C1
- "\x00A\x03\x02\x00\x00\x00\xc2" + // 0x00410302: 0x000000C2
- "\x00A\x03\x03\x00\x00\x00\xc3" + // 0x00410303: 0x000000C3
- "\x00A\x03\b\x00\x00\x00\xc4" + // 0x00410308: 0x000000C4
- "\x00A\x03\n\x00\x00\x00\xc5" + // 0x0041030A: 0x000000C5
- "\x00C\x03'\x00\x00\x00\xc7" + // 0x00430327: 0x000000C7
- "\x00E\x03\x00\x00\x00\x00\xc8" + // 0x00450300: 0x000000C8
- "\x00E\x03\x01\x00\x00\x00\xc9" + // 0x00450301: 0x000000C9
- "\x00E\x03\x02\x00\x00\x00\xca" + // 0x00450302: 0x000000CA
- "\x00E\x03\b\x00\x00\x00\xcb" + // 0x00450308: 0x000000CB
- "\x00I\x03\x00\x00\x00\x00\xcc" + // 0x00490300: 0x000000CC
- "\x00I\x03\x01\x00\x00\x00\xcd" + // 0x00490301: 0x000000CD
- "\x00I\x03\x02\x00\x00\x00\xce" + // 0x00490302: 0x000000CE
- "\x00I\x03\b\x00\x00\x00\xcf" + // 0x00490308: 0x000000CF
- "\x00N\x03\x03\x00\x00\x00\xd1" + // 0x004E0303: 0x000000D1
- "\x00O\x03\x00\x00\x00\x00\xd2" + // 0x004F0300: 0x000000D2
- "\x00O\x03\x01\x00\x00\x00\xd3" + // 0x004F0301: 0x000000D3
- "\x00O\x03\x02\x00\x00\x00\xd4" + // 0x004F0302: 0x000000D4
- "\x00O\x03\x03\x00\x00\x00\xd5" + // 0x004F0303: 0x000000D5
- "\x00O\x03\b\x00\x00\x00\xd6" + // 0x004F0308: 0x000000D6
- "\x00U\x03\x00\x00\x00\x00\xd9" + // 0x00550300: 0x000000D9
- "\x00U\x03\x01\x00\x00\x00\xda" + // 0x00550301: 0x000000DA
- "\x00U\x03\x02\x00\x00\x00\xdb" + // 0x00550302: 0x000000DB
- "\x00U\x03\b\x00\x00\x00\xdc" + // 0x00550308: 0x000000DC
- "\x00Y\x03\x01\x00\x00\x00\xdd" + // 0x00590301: 0x000000DD
- "\x00a\x03\x00\x00\x00\x00\xe0" + // 0x00610300: 0x000000E0
- "\x00a\x03\x01\x00\x00\x00\xe1" + // 0x00610301: 0x000000E1
- "\x00a\x03\x02\x00\x00\x00\xe2" + // 0x00610302: 0x000000E2
- "\x00a\x03\x03\x00\x00\x00\xe3" + // 0x00610303: 0x000000E3
- "\x00a\x03\b\x00\x00\x00\xe4" + // 0x00610308: 0x000000E4
- "\x00a\x03\n\x00\x00\x00\xe5" + // 0x0061030A: 0x000000E5
- "\x00c\x03'\x00\x00\x00\xe7" + // 0x00630327: 0x000000E7
- "\x00e\x03\x00\x00\x00\x00\xe8" + // 0x00650300: 0x000000E8
- "\x00e\x03\x01\x00\x00\x00\xe9" + // 0x00650301: 0x000000E9
- "\x00e\x03\x02\x00\x00\x00\xea" + // 0x00650302: 0x000000EA
- "\x00e\x03\b\x00\x00\x00\xeb" + // 0x00650308: 0x000000EB
- "\x00i\x03\x00\x00\x00\x00\xec" + // 0x00690300: 0x000000EC
- "\x00i\x03\x01\x00\x00\x00\xed" + // 0x00690301: 0x000000ED
- "\x00i\x03\x02\x00\x00\x00\xee" + // 0x00690302: 0x000000EE
- "\x00i\x03\b\x00\x00\x00\xef" + // 0x00690308: 0x000000EF
- "\x00n\x03\x03\x00\x00\x00\xf1" + // 0x006E0303: 0x000000F1
- "\x00o\x03\x00\x00\x00\x00\xf2" + // 0x006F0300: 0x000000F2
- "\x00o\x03\x01\x00\x00\x00\xf3" + // 0x006F0301: 0x000000F3
- "\x00o\x03\x02\x00\x00\x00\xf4" + // 0x006F0302: 0x000000F4
- "\x00o\x03\x03\x00\x00\x00\xf5" + // 0x006F0303: 0x000000F5
- "\x00o\x03\b\x00\x00\x00\xf6" + // 0x006F0308: 0x000000F6
- "\x00u\x03\x00\x00\x00\x00\xf9" + // 0x00750300: 0x000000F9
- "\x00u\x03\x01\x00\x00\x00\xfa" + // 0x00750301: 0x000000FA
- "\x00u\x03\x02\x00\x00\x00\xfb" + // 0x00750302: 0x000000FB
- "\x00u\x03\b\x00\x00\x00\xfc" + // 0x00750308: 0x000000FC
- "\x00y\x03\x01\x00\x00\x00\xfd" + // 0x00790301: 0x000000FD
- "\x00y\x03\b\x00\x00\x00\xff" + // 0x00790308: 0x000000FF
- "\x00A\x03\x04\x00\x00\x01\x00" + // 0x00410304: 0x00000100
- "\x00a\x03\x04\x00\x00\x01\x01" + // 0x00610304: 0x00000101
- "\x00A\x03\x06\x00\x00\x01\x02" + // 0x00410306: 0x00000102
- "\x00a\x03\x06\x00\x00\x01\x03" + // 0x00610306: 0x00000103
- "\x00A\x03(\x00\x00\x01\x04" + // 0x00410328: 0x00000104
- "\x00a\x03(\x00\x00\x01\x05" + // 0x00610328: 0x00000105
- "\x00C\x03\x01\x00\x00\x01\x06" + // 0x00430301: 0x00000106
- "\x00c\x03\x01\x00\x00\x01\a" + // 0x00630301: 0x00000107
- "\x00C\x03\x02\x00\x00\x01\b" + // 0x00430302: 0x00000108
- "\x00c\x03\x02\x00\x00\x01\t" + // 0x00630302: 0x00000109
- "\x00C\x03\a\x00\x00\x01\n" + // 0x00430307: 0x0000010A
- "\x00c\x03\a\x00\x00\x01\v" + // 0x00630307: 0x0000010B
- "\x00C\x03\f\x00\x00\x01\f" + // 0x0043030C: 0x0000010C
- "\x00c\x03\f\x00\x00\x01\r" + // 0x0063030C: 0x0000010D
- "\x00D\x03\f\x00\x00\x01\x0e" + // 0x0044030C: 0x0000010E
- "\x00d\x03\f\x00\x00\x01\x0f" + // 0x0064030C: 0x0000010F
- "\x00E\x03\x04\x00\x00\x01\x12" + // 0x00450304: 0x00000112
- "\x00e\x03\x04\x00\x00\x01\x13" + // 0x00650304: 0x00000113
- "\x00E\x03\x06\x00\x00\x01\x14" + // 0x00450306: 0x00000114
- "\x00e\x03\x06\x00\x00\x01\x15" + // 0x00650306: 0x00000115
- "\x00E\x03\a\x00\x00\x01\x16" + // 0x00450307: 0x00000116
- "\x00e\x03\a\x00\x00\x01\x17" + // 0x00650307: 0x00000117
- "\x00E\x03(\x00\x00\x01\x18" + // 0x00450328: 0x00000118
- "\x00e\x03(\x00\x00\x01\x19" + // 0x00650328: 0x00000119
- "\x00E\x03\f\x00\x00\x01\x1a" + // 0x0045030C: 0x0000011A
- "\x00e\x03\f\x00\x00\x01\x1b" + // 0x0065030C: 0x0000011B
- "\x00G\x03\x02\x00\x00\x01\x1c" + // 0x00470302: 0x0000011C
- "\x00g\x03\x02\x00\x00\x01\x1d" + // 0x00670302: 0x0000011D
- "\x00G\x03\x06\x00\x00\x01\x1e" + // 0x00470306: 0x0000011E
- "\x00g\x03\x06\x00\x00\x01\x1f" + // 0x00670306: 0x0000011F
- "\x00G\x03\a\x00\x00\x01 " + // 0x00470307: 0x00000120
- "\x00g\x03\a\x00\x00\x01!" + // 0x00670307: 0x00000121
- "\x00G\x03'\x00\x00\x01\"" + // 0x00470327: 0x00000122
- "\x00g\x03'\x00\x00\x01#" + // 0x00670327: 0x00000123
- "\x00H\x03\x02\x00\x00\x01$" + // 0x00480302: 0x00000124
- "\x00h\x03\x02\x00\x00\x01%" + // 0x00680302: 0x00000125
- "\x00I\x03\x03\x00\x00\x01(" + // 0x00490303: 0x00000128
- "\x00i\x03\x03\x00\x00\x01)" + // 0x00690303: 0x00000129
- "\x00I\x03\x04\x00\x00\x01*" + // 0x00490304: 0x0000012A
- "\x00i\x03\x04\x00\x00\x01+" + // 0x00690304: 0x0000012B
- "\x00I\x03\x06\x00\x00\x01," + // 0x00490306: 0x0000012C
- "\x00i\x03\x06\x00\x00\x01-" + // 0x00690306: 0x0000012D
- "\x00I\x03(\x00\x00\x01." + // 0x00490328: 0x0000012E
- "\x00i\x03(\x00\x00\x01/" + // 0x00690328: 0x0000012F
- "\x00I\x03\a\x00\x00\x010" + // 0x00490307: 0x00000130
- "\x00J\x03\x02\x00\x00\x014" + // 0x004A0302: 0x00000134
- "\x00j\x03\x02\x00\x00\x015" + // 0x006A0302: 0x00000135
- "\x00K\x03'\x00\x00\x016" + // 0x004B0327: 0x00000136
- "\x00k\x03'\x00\x00\x017" + // 0x006B0327: 0x00000137
- "\x00L\x03\x01\x00\x00\x019" + // 0x004C0301: 0x00000139
- "\x00l\x03\x01\x00\x00\x01:" + // 0x006C0301: 0x0000013A
- "\x00L\x03'\x00\x00\x01;" + // 0x004C0327: 0x0000013B
- "\x00l\x03'\x00\x00\x01<" + // 0x006C0327: 0x0000013C
- "\x00L\x03\f\x00\x00\x01=" + // 0x004C030C: 0x0000013D
- "\x00l\x03\f\x00\x00\x01>" + // 0x006C030C: 0x0000013E
- "\x00N\x03\x01\x00\x00\x01C" + // 0x004E0301: 0x00000143
- "\x00n\x03\x01\x00\x00\x01D" + // 0x006E0301: 0x00000144
- "\x00N\x03'\x00\x00\x01E" + // 0x004E0327: 0x00000145
- "\x00n\x03'\x00\x00\x01F" + // 0x006E0327: 0x00000146
- "\x00N\x03\f\x00\x00\x01G" + // 0x004E030C: 0x00000147
- "\x00n\x03\f\x00\x00\x01H" + // 0x006E030C: 0x00000148
- "\x00O\x03\x04\x00\x00\x01L" + // 0x004F0304: 0x0000014C
- "\x00o\x03\x04\x00\x00\x01M" + // 0x006F0304: 0x0000014D
- "\x00O\x03\x06\x00\x00\x01N" + // 0x004F0306: 0x0000014E
- "\x00o\x03\x06\x00\x00\x01O" + // 0x006F0306: 0x0000014F
- "\x00O\x03\v\x00\x00\x01P" + // 0x004F030B: 0x00000150
- "\x00o\x03\v\x00\x00\x01Q" + // 0x006F030B: 0x00000151
- "\x00R\x03\x01\x00\x00\x01T" + // 0x00520301: 0x00000154
- "\x00r\x03\x01\x00\x00\x01U" + // 0x00720301: 0x00000155
- "\x00R\x03'\x00\x00\x01V" + // 0x00520327: 0x00000156
- "\x00r\x03'\x00\x00\x01W" + // 0x00720327: 0x00000157
- "\x00R\x03\f\x00\x00\x01X" + // 0x0052030C: 0x00000158
- "\x00r\x03\f\x00\x00\x01Y" + // 0x0072030C: 0x00000159
- "\x00S\x03\x01\x00\x00\x01Z" + // 0x00530301: 0x0000015A
- "\x00s\x03\x01\x00\x00\x01[" + // 0x00730301: 0x0000015B
- "\x00S\x03\x02\x00\x00\x01\\" + // 0x00530302: 0x0000015C
- "\x00s\x03\x02\x00\x00\x01]" + // 0x00730302: 0x0000015D
- "\x00S\x03'\x00\x00\x01^" + // 0x00530327: 0x0000015E
- "\x00s\x03'\x00\x00\x01_" + // 0x00730327: 0x0000015F
- "\x00S\x03\f\x00\x00\x01`" + // 0x0053030C: 0x00000160
- "\x00s\x03\f\x00\x00\x01a" + // 0x0073030C: 0x00000161
- "\x00T\x03'\x00\x00\x01b" + // 0x00540327: 0x00000162
- "\x00t\x03'\x00\x00\x01c" + // 0x00740327: 0x00000163
- "\x00T\x03\f\x00\x00\x01d" + // 0x0054030C: 0x00000164
- "\x00t\x03\f\x00\x00\x01e" + // 0x0074030C: 0x00000165
- "\x00U\x03\x03\x00\x00\x01h" + // 0x00550303: 0x00000168
- "\x00u\x03\x03\x00\x00\x01i" + // 0x00750303: 0x00000169
- "\x00U\x03\x04\x00\x00\x01j" + // 0x00550304: 0x0000016A
- "\x00u\x03\x04\x00\x00\x01k" + // 0x00750304: 0x0000016B
- "\x00U\x03\x06\x00\x00\x01l" + // 0x00550306: 0x0000016C
- "\x00u\x03\x06\x00\x00\x01m" + // 0x00750306: 0x0000016D
- "\x00U\x03\n\x00\x00\x01n" + // 0x0055030A: 0x0000016E
- "\x00u\x03\n\x00\x00\x01o" + // 0x0075030A: 0x0000016F
- "\x00U\x03\v\x00\x00\x01p" + // 0x0055030B: 0x00000170
- "\x00u\x03\v\x00\x00\x01q" + // 0x0075030B: 0x00000171
- "\x00U\x03(\x00\x00\x01r" + // 0x00550328: 0x00000172
- "\x00u\x03(\x00\x00\x01s" + // 0x00750328: 0x00000173
- "\x00W\x03\x02\x00\x00\x01t" + // 0x00570302: 0x00000174
- "\x00w\x03\x02\x00\x00\x01u" + // 0x00770302: 0x00000175
- "\x00Y\x03\x02\x00\x00\x01v" + // 0x00590302: 0x00000176
- "\x00y\x03\x02\x00\x00\x01w" + // 0x00790302: 0x00000177
- "\x00Y\x03\b\x00\x00\x01x" + // 0x00590308: 0x00000178
- "\x00Z\x03\x01\x00\x00\x01y" + // 0x005A0301: 0x00000179
- "\x00z\x03\x01\x00\x00\x01z" + // 0x007A0301: 0x0000017A
- "\x00Z\x03\a\x00\x00\x01{" + // 0x005A0307: 0x0000017B
- "\x00z\x03\a\x00\x00\x01|" + // 0x007A0307: 0x0000017C
- "\x00Z\x03\f\x00\x00\x01}" + // 0x005A030C: 0x0000017D
- "\x00z\x03\f\x00\x00\x01~" + // 0x007A030C: 0x0000017E
- "\x00O\x03\x1b\x00\x00\x01\xa0" + // 0x004F031B: 0x000001A0
- "\x00o\x03\x1b\x00\x00\x01\xa1" + // 0x006F031B: 0x000001A1
- "\x00U\x03\x1b\x00\x00\x01\xaf" + // 0x0055031B: 0x000001AF
- "\x00u\x03\x1b\x00\x00\x01\xb0" + // 0x0075031B: 0x000001B0
- "\x00A\x03\f\x00\x00\x01\xcd" + // 0x0041030C: 0x000001CD
- "\x00a\x03\f\x00\x00\x01\xce" + // 0x0061030C: 0x000001CE
- "\x00I\x03\f\x00\x00\x01\xcf" + // 0x0049030C: 0x000001CF
- "\x00i\x03\f\x00\x00\x01\xd0" + // 0x0069030C: 0x000001D0
- "\x00O\x03\f\x00\x00\x01\xd1" + // 0x004F030C: 0x000001D1
- "\x00o\x03\f\x00\x00\x01\xd2" + // 0x006F030C: 0x000001D2
- "\x00U\x03\f\x00\x00\x01\xd3" + // 0x0055030C: 0x000001D3
- "\x00u\x03\f\x00\x00\x01\xd4" + // 0x0075030C: 0x000001D4
- "\x00\xdc\x03\x04\x00\x00\x01\xd5" + // 0x00DC0304: 0x000001D5
- "\x00\xfc\x03\x04\x00\x00\x01\xd6" + // 0x00FC0304: 0x000001D6
- "\x00\xdc\x03\x01\x00\x00\x01\xd7" + // 0x00DC0301: 0x000001D7
- "\x00\xfc\x03\x01\x00\x00\x01\xd8" + // 0x00FC0301: 0x000001D8
- "\x00\xdc\x03\f\x00\x00\x01\xd9" + // 0x00DC030C: 0x000001D9
- "\x00\xfc\x03\f\x00\x00\x01\xda" + // 0x00FC030C: 0x000001DA
- "\x00\xdc\x03\x00\x00\x00\x01\xdb" + // 0x00DC0300: 0x000001DB
- "\x00\xfc\x03\x00\x00\x00\x01\xdc" + // 0x00FC0300: 0x000001DC
- "\x00\xc4\x03\x04\x00\x00\x01\xde" + // 0x00C40304: 0x000001DE
- "\x00\xe4\x03\x04\x00\x00\x01\xdf" + // 0x00E40304: 0x000001DF
- "\x02&\x03\x04\x00\x00\x01\xe0" + // 0x02260304: 0x000001E0
- "\x02'\x03\x04\x00\x00\x01\xe1" + // 0x02270304: 0x000001E1
- "\x00\xc6\x03\x04\x00\x00\x01\xe2" + // 0x00C60304: 0x000001E2
- "\x00\xe6\x03\x04\x00\x00\x01\xe3" + // 0x00E60304: 0x000001E3
- "\x00G\x03\f\x00\x00\x01\xe6" + // 0x0047030C: 0x000001E6
- "\x00g\x03\f\x00\x00\x01\xe7" + // 0x0067030C: 0x000001E7
- "\x00K\x03\f\x00\x00\x01\xe8" + // 0x004B030C: 0x000001E8
- "\x00k\x03\f\x00\x00\x01\xe9" + // 0x006B030C: 0x000001E9
- "\x00O\x03(\x00\x00\x01\xea" + // 0x004F0328: 0x000001EA
- "\x00o\x03(\x00\x00\x01\xeb" + // 0x006F0328: 0x000001EB
- "\x01\xea\x03\x04\x00\x00\x01\xec" + // 0x01EA0304: 0x000001EC
- "\x01\xeb\x03\x04\x00\x00\x01\xed" + // 0x01EB0304: 0x000001ED
- "\x01\xb7\x03\f\x00\x00\x01\xee" + // 0x01B7030C: 0x000001EE
- "\x02\x92\x03\f\x00\x00\x01\xef" + // 0x0292030C: 0x000001EF
- "\x00j\x03\f\x00\x00\x01\xf0" + // 0x006A030C: 0x000001F0
- "\x00G\x03\x01\x00\x00\x01\xf4" + // 0x00470301: 0x000001F4
- "\x00g\x03\x01\x00\x00\x01\xf5" + // 0x00670301: 0x000001F5
- "\x00N\x03\x00\x00\x00\x01\xf8" + // 0x004E0300: 0x000001F8
- "\x00n\x03\x00\x00\x00\x01\xf9" + // 0x006E0300: 0x000001F9
- "\x00\xc5\x03\x01\x00\x00\x01\xfa" + // 0x00C50301: 0x000001FA
- "\x00\xe5\x03\x01\x00\x00\x01\xfb" + // 0x00E50301: 0x000001FB
- "\x00\xc6\x03\x01\x00\x00\x01\xfc" + // 0x00C60301: 0x000001FC
- "\x00\xe6\x03\x01\x00\x00\x01\xfd" + // 0x00E60301: 0x000001FD
- "\x00\xd8\x03\x01\x00\x00\x01\xfe" + // 0x00D80301: 0x000001FE
- "\x00\xf8\x03\x01\x00\x00\x01\xff" + // 0x00F80301: 0x000001FF
- "\x00A\x03\x0f\x00\x00\x02\x00" + // 0x0041030F: 0x00000200
- "\x00a\x03\x0f\x00\x00\x02\x01" + // 0x0061030F: 0x00000201
- "\x00A\x03\x11\x00\x00\x02\x02" + // 0x00410311: 0x00000202
- "\x00a\x03\x11\x00\x00\x02\x03" + // 0x00610311: 0x00000203
- "\x00E\x03\x0f\x00\x00\x02\x04" + // 0x0045030F: 0x00000204
- "\x00e\x03\x0f\x00\x00\x02\x05" + // 0x0065030F: 0x00000205
- "\x00E\x03\x11\x00\x00\x02\x06" + // 0x00450311: 0x00000206
- "\x00e\x03\x11\x00\x00\x02\a" + // 0x00650311: 0x00000207
- "\x00I\x03\x0f\x00\x00\x02\b" + // 0x0049030F: 0x00000208
- "\x00i\x03\x0f\x00\x00\x02\t" + // 0x0069030F: 0x00000209
- "\x00I\x03\x11\x00\x00\x02\n" + // 0x00490311: 0x0000020A
- "\x00i\x03\x11\x00\x00\x02\v" + // 0x00690311: 0x0000020B
- "\x00O\x03\x0f\x00\x00\x02\f" + // 0x004F030F: 0x0000020C
- "\x00o\x03\x0f\x00\x00\x02\r" + // 0x006F030F: 0x0000020D
- "\x00O\x03\x11\x00\x00\x02\x0e" + // 0x004F0311: 0x0000020E
- "\x00o\x03\x11\x00\x00\x02\x0f" + // 0x006F0311: 0x0000020F
- "\x00R\x03\x0f\x00\x00\x02\x10" + // 0x0052030F: 0x00000210
- "\x00r\x03\x0f\x00\x00\x02\x11" + // 0x0072030F: 0x00000211
- "\x00R\x03\x11\x00\x00\x02\x12" + // 0x00520311: 0x00000212
- "\x00r\x03\x11\x00\x00\x02\x13" + // 0x00720311: 0x00000213
- "\x00U\x03\x0f\x00\x00\x02\x14" + // 0x0055030F: 0x00000214
- "\x00u\x03\x0f\x00\x00\x02\x15" + // 0x0075030F: 0x00000215
- "\x00U\x03\x11\x00\x00\x02\x16" + // 0x00550311: 0x00000216
- "\x00u\x03\x11\x00\x00\x02\x17" + // 0x00750311: 0x00000217
- "\x00S\x03&\x00\x00\x02\x18" + // 0x00530326: 0x00000218
- "\x00s\x03&\x00\x00\x02\x19" + // 0x00730326: 0x00000219
- "\x00T\x03&\x00\x00\x02\x1a" + // 0x00540326: 0x0000021A
- "\x00t\x03&\x00\x00\x02\x1b" + // 0x00740326: 0x0000021B
- "\x00H\x03\f\x00\x00\x02\x1e" + // 0x0048030C: 0x0000021E
- "\x00h\x03\f\x00\x00\x02\x1f" + // 0x0068030C: 0x0000021F
- "\x00A\x03\a\x00\x00\x02&" + // 0x00410307: 0x00000226
- "\x00a\x03\a\x00\x00\x02'" + // 0x00610307: 0x00000227
- "\x00E\x03'\x00\x00\x02(" + // 0x00450327: 0x00000228
- "\x00e\x03'\x00\x00\x02)" + // 0x00650327: 0x00000229
- "\x00\xd6\x03\x04\x00\x00\x02*" + // 0x00D60304: 0x0000022A
- "\x00\xf6\x03\x04\x00\x00\x02+" + // 0x00F60304: 0x0000022B
- "\x00\xd5\x03\x04\x00\x00\x02," + // 0x00D50304: 0x0000022C
- "\x00\xf5\x03\x04\x00\x00\x02-" + // 0x00F50304: 0x0000022D
- "\x00O\x03\a\x00\x00\x02." + // 0x004F0307: 0x0000022E
- "\x00o\x03\a\x00\x00\x02/" + // 0x006F0307: 0x0000022F
- "\x02.\x03\x04\x00\x00\x020" + // 0x022E0304: 0x00000230
- "\x02/\x03\x04\x00\x00\x021" + // 0x022F0304: 0x00000231
- "\x00Y\x03\x04\x00\x00\x022" + // 0x00590304: 0x00000232
- "\x00y\x03\x04\x00\x00\x023" + // 0x00790304: 0x00000233
- "\x00\xa8\x03\x01\x00\x00\x03\x85" + // 0x00A80301: 0x00000385
- "\x03\x91\x03\x01\x00\x00\x03\x86" + // 0x03910301: 0x00000386
- "\x03\x95\x03\x01\x00\x00\x03\x88" + // 0x03950301: 0x00000388
- "\x03\x97\x03\x01\x00\x00\x03\x89" + // 0x03970301: 0x00000389
- "\x03\x99\x03\x01\x00\x00\x03\x8a" + // 0x03990301: 0x0000038A
- "\x03\x9f\x03\x01\x00\x00\x03\x8c" + // 0x039F0301: 0x0000038C
- "\x03\xa5\x03\x01\x00\x00\x03\x8e" + // 0x03A50301: 0x0000038E
- "\x03\xa9\x03\x01\x00\x00\x03\x8f" + // 0x03A90301: 0x0000038F
- "\x03\xca\x03\x01\x00\x00\x03\x90" + // 0x03CA0301: 0x00000390
- "\x03\x99\x03\b\x00\x00\x03\xaa" + // 0x03990308: 0x000003AA
- "\x03\xa5\x03\b\x00\x00\x03\xab" + // 0x03A50308: 0x000003AB
- "\x03\xb1\x03\x01\x00\x00\x03\xac" + // 0x03B10301: 0x000003AC
- "\x03\xb5\x03\x01\x00\x00\x03\xad" + // 0x03B50301: 0x000003AD
- "\x03\xb7\x03\x01\x00\x00\x03\xae" + // 0x03B70301: 0x000003AE
- "\x03\xb9\x03\x01\x00\x00\x03\xaf" + // 0x03B90301: 0x000003AF
- "\x03\xcb\x03\x01\x00\x00\x03\xb0" + // 0x03CB0301: 0x000003B0
- "\x03\xb9\x03\b\x00\x00\x03\xca" + // 0x03B90308: 0x000003CA
- "\x03\xc5\x03\b\x00\x00\x03\xcb" + // 0x03C50308: 0x000003CB
- "\x03\xbf\x03\x01\x00\x00\x03\xcc" + // 0x03BF0301: 0x000003CC
- "\x03\xc5\x03\x01\x00\x00\x03\xcd" + // 0x03C50301: 0x000003CD
- "\x03\xc9\x03\x01\x00\x00\x03\xce" + // 0x03C90301: 0x000003CE
- "\x03\xd2\x03\x01\x00\x00\x03\xd3" + // 0x03D20301: 0x000003D3
- "\x03\xd2\x03\b\x00\x00\x03\xd4" + // 0x03D20308: 0x000003D4
- "\x04\x15\x03\x00\x00\x00\x04\x00" + // 0x04150300: 0x00000400
- "\x04\x15\x03\b\x00\x00\x04\x01" + // 0x04150308: 0x00000401
- "\x04\x13\x03\x01\x00\x00\x04\x03" + // 0x04130301: 0x00000403
- "\x04\x06\x03\b\x00\x00\x04\a" + // 0x04060308: 0x00000407
- "\x04\x1a\x03\x01\x00\x00\x04\f" + // 0x041A0301: 0x0000040C
- "\x04\x18\x03\x00\x00\x00\x04\r" + // 0x04180300: 0x0000040D
- "\x04#\x03\x06\x00\x00\x04\x0e" + // 0x04230306: 0x0000040E
- "\x04\x18\x03\x06\x00\x00\x04\x19" + // 0x04180306: 0x00000419
- "\x048\x03\x06\x00\x00\x049" + // 0x04380306: 0x00000439
- "\x045\x03\x00\x00\x00\x04P" + // 0x04350300: 0x00000450
- "\x045\x03\b\x00\x00\x04Q" + // 0x04350308: 0x00000451
- "\x043\x03\x01\x00\x00\x04S" + // 0x04330301: 0x00000453
- "\x04V\x03\b\x00\x00\x04W" + // 0x04560308: 0x00000457
- "\x04:\x03\x01\x00\x00\x04\\" + // 0x043A0301: 0x0000045C
- "\x048\x03\x00\x00\x00\x04]" + // 0x04380300: 0x0000045D
- "\x04C\x03\x06\x00\x00\x04^" + // 0x04430306: 0x0000045E
- "\x04t\x03\x0f\x00\x00\x04v" + // 0x0474030F: 0x00000476
- "\x04u\x03\x0f\x00\x00\x04w" + // 0x0475030F: 0x00000477
- "\x04\x16\x03\x06\x00\x00\x04\xc1" + // 0x04160306: 0x000004C1
- "\x046\x03\x06\x00\x00\x04\xc2" + // 0x04360306: 0x000004C2
- "\x04\x10\x03\x06\x00\x00\x04\xd0" + // 0x04100306: 0x000004D0
- "\x040\x03\x06\x00\x00\x04\xd1" + // 0x04300306: 0x000004D1
- "\x04\x10\x03\b\x00\x00\x04\xd2" + // 0x04100308: 0x000004D2
- "\x040\x03\b\x00\x00\x04\xd3" + // 0x04300308: 0x000004D3
- "\x04\x15\x03\x06\x00\x00\x04\xd6" + // 0x04150306: 0x000004D6
- "\x045\x03\x06\x00\x00\x04\xd7" + // 0x04350306: 0x000004D7
- "\x04\xd8\x03\b\x00\x00\x04\xda" + // 0x04D80308: 0x000004DA
- "\x04\xd9\x03\b\x00\x00\x04\xdb" + // 0x04D90308: 0x000004DB
- "\x04\x16\x03\b\x00\x00\x04\xdc" + // 0x04160308: 0x000004DC
- "\x046\x03\b\x00\x00\x04\xdd" + // 0x04360308: 0x000004DD
- "\x04\x17\x03\b\x00\x00\x04\xde" + // 0x04170308: 0x000004DE
- "\x047\x03\b\x00\x00\x04\xdf" + // 0x04370308: 0x000004DF
- "\x04\x18\x03\x04\x00\x00\x04\xe2" + // 0x04180304: 0x000004E2
- "\x048\x03\x04\x00\x00\x04\xe3" + // 0x04380304: 0x000004E3
- "\x04\x18\x03\b\x00\x00\x04\xe4" + // 0x04180308: 0x000004E4
- "\x048\x03\b\x00\x00\x04\xe5" + // 0x04380308: 0x000004E5
- "\x04\x1e\x03\b\x00\x00\x04\xe6" + // 0x041E0308: 0x000004E6
- "\x04>\x03\b\x00\x00\x04\xe7" + // 0x043E0308: 0x000004E7
- "\x04\xe8\x03\b\x00\x00\x04\xea" + // 0x04E80308: 0x000004EA
- "\x04\xe9\x03\b\x00\x00\x04\xeb" + // 0x04E90308: 0x000004EB
- "\x04-\x03\b\x00\x00\x04\xec" + // 0x042D0308: 0x000004EC
- "\x04M\x03\b\x00\x00\x04\xed" + // 0x044D0308: 0x000004ED
- "\x04#\x03\x04\x00\x00\x04\xee" + // 0x04230304: 0x000004EE
- "\x04C\x03\x04\x00\x00\x04\xef" + // 0x04430304: 0x000004EF
- "\x04#\x03\b\x00\x00\x04\xf0" + // 0x04230308: 0x000004F0
- "\x04C\x03\b\x00\x00\x04\xf1" + // 0x04430308: 0x000004F1
- "\x04#\x03\v\x00\x00\x04\xf2" + // 0x0423030B: 0x000004F2
- "\x04C\x03\v\x00\x00\x04\xf3" + // 0x0443030B: 0x000004F3
- "\x04'\x03\b\x00\x00\x04\xf4" + // 0x04270308: 0x000004F4
- "\x04G\x03\b\x00\x00\x04\xf5" + // 0x04470308: 0x000004F5
- "\x04+\x03\b\x00\x00\x04\xf8" + // 0x042B0308: 0x000004F8
- "\x04K\x03\b\x00\x00\x04\xf9" + // 0x044B0308: 0x000004F9
- "\x06'\x06S\x00\x00\x06\"" + // 0x06270653: 0x00000622
- "\x06'\x06T\x00\x00\x06#" + // 0x06270654: 0x00000623
- "\x06H\x06T\x00\x00\x06$" + // 0x06480654: 0x00000624
- "\x06'\x06U\x00\x00\x06%" + // 0x06270655: 0x00000625
- "\x06J\x06T\x00\x00\x06&" + // 0x064A0654: 0x00000626
- "\x06\xd5\x06T\x00\x00\x06\xc0" + // 0x06D50654: 0x000006C0
- "\x06\xc1\x06T\x00\x00\x06\xc2" + // 0x06C10654: 0x000006C2
- "\x06\xd2\x06T\x00\x00\x06\xd3" + // 0x06D20654: 0x000006D3
- "\t(\t<\x00\x00\t)" + // 0x0928093C: 0x00000929
- "\t0\t<\x00\x00\t1" + // 0x0930093C: 0x00000931
- "\t3\t<\x00\x00\t4" + // 0x0933093C: 0x00000934
- "\t\xc7\t\xbe\x00\x00\t\xcb" + // 0x09C709BE: 0x000009CB
- "\t\xc7\t\xd7\x00\x00\t\xcc" + // 0x09C709D7: 0x000009CC
- "\vG\vV\x00\x00\vH" + // 0x0B470B56: 0x00000B48
- "\vG\v>\x00\x00\vK" + // 0x0B470B3E: 0x00000B4B
- "\vG\vW\x00\x00\vL" + // 0x0B470B57: 0x00000B4C
- "\v\x92\v\xd7\x00\x00\v\x94" + // 0x0B920BD7: 0x00000B94
- "\v\xc6\v\xbe\x00\x00\v\xca" + // 0x0BC60BBE: 0x00000BCA
- "\v\xc7\v\xbe\x00\x00\v\xcb" + // 0x0BC70BBE: 0x00000BCB
- "\v\xc6\v\xd7\x00\x00\v\xcc" + // 0x0BC60BD7: 0x00000BCC
- "\fF\fV\x00\x00\fH" + // 0x0C460C56: 0x00000C48
- "\f\xbf\f\xd5\x00\x00\f\xc0" + // 0x0CBF0CD5: 0x00000CC0
- "\f\xc6\f\xd5\x00\x00\f\xc7" + // 0x0CC60CD5: 0x00000CC7
- "\f\xc6\f\xd6\x00\x00\f\xc8" + // 0x0CC60CD6: 0x00000CC8
- "\f\xc6\f\xc2\x00\x00\f\xca" + // 0x0CC60CC2: 0x00000CCA
- "\f\xca\f\xd5\x00\x00\f\xcb" + // 0x0CCA0CD5: 0x00000CCB
- "\rF\r>\x00\x00\rJ" + // 0x0D460D3E: 0x00000D4A
- "\rG\r>\x00\x00\rK" + // 0x0D470D3E: 0x00000D4B
- "\rF\rW\x00\x00\rL" + // 0x0D460D57: 0x00000D4C
- "\r\xd9\r\xca\x00\x00\r\xda" + // 0x0DD90DCA: 0x00000DDA
- "\r\xd9\r\xcf\x00\x00\r\xdc" + // 0x0DD90DCF: 0x00000DDC
- "\r\xdc\r\xca\x00\x00\r\xdd" + // 0x0DDC0DCA: 0x00000DDD
- "\r\xd9\r\xdf\x00\x00\r\xde" + // 0x0DD90DDF: 0x00000DDE
- "\x10%\x10.\x00\x00\x10&" + // 0x1025102E: 0x00001026
- "\x1b\x05\x1b5\x00\x00\x1b\x06" + // 0x1B051B35: 0x00001B06
- "\x1b\a\x1b5\x00\x00\x1b\b" + // 0x1B071B35: 0x00001B08
- "\x1b\t\x1b5\x00\x00\x1b\n" + // 0x1B091B35: 0x00001B0A
- "\x1b\v\x1b5\x00\x00\x1b\f" + // 0x1B0B1B35: 0x00001B0C
- "\x1b\r\x1b5\x00\x00\x1b\x0e" + // 0x1B0D1B35: 0x00001B0E
- "\x1b\x11\x1b5\x00\x00\x1b\x12" + // 0x1B111B35: 0x00001B12
- "\x1b:\x1b5\x00\x00\x1b;" + // 0x1B3A1B35: 0x00001B3B
- "\x1b<\x1b5\x00\x00\x1b=" + // 0x1B3C1B35: 0x00001B3D
- "\x1b>\x1b5\x00\x00\x1b@" + // 0x1B3E1B35: 0x00001B40
- "\x1b?\x1b5\x00\x00\x1bA" + // 0x1B3F1B35: 0x00001B41
- "\x1bB\x1b5\x00\x00\x1bC" + // 0x1B421B35: 0x00001B43
- "\x00A\x03%\x00\x00\x1e\x00" + // 0x00410325: 0x00001E00
- "\x00a\x03%\x00\x00\x1e\x01" + // 0x00610325: 0x00001E01
- "\x00B\x03\a\x00\x00\x1e\x02" + // 0x00420307: 0x00001E02
- "\x00b\x03\a\x00\x00\x1e\x03" + // 0x00620307: 0x00001E03
- "\x00B\x03#\x00\x00\x1e\x04" + // 0x00420323: 0x00001E04
- "\x00b\x03#\x00\x00\x1e\x05" + // 0x00620323: 0x00001E05
- "\x00B\x031\x00\x00\x1e\x06" + // 0x00420331: 0x00001E06
- "\x00b\x031\x00\x00\x1e\a" + // 0x00620331: 0x00001E07
- "\x00\xc7\x03\x01\x00\x00\x1e\b" + // 0x00C70301: 0x00001E08
- "\x00\xe7\x03\x01\x00\x00\x1e\t" + // 0x00E70301: 0x00001E09
- "\x00D\x03\a\x00\x00\x1e\n" + // 0x00440307: 0x00001E0A
- "\x00d\x03\a\x00\x00\x1e\v" + // 0x00640307: 0x00001E0B
- "\x00D\x03#\x00\x00\x1e\f" + // 0x00440323: 0x00001E0C
- "\x00d\x03#\x00\x00\x1e\r" + // 0x00640323: 0x00001E0D
- "\x00D\x031\x00\x00\x1e\x0e" + // 0x00440331: 0x00001E0E
- "\x00d\x031\x00\x00\x1e\x0f" + // 0x00640331: 0x00001E0F
- "\x00D\x03'\x00\x00\x1e\x10" + // 0x00440327: 0x00001E10
- "\x00d\x03'\x00\x00\x1e\x11" + // 0x00640327: 0x00001E11
- "\x00D\x03-\x00\x00\x1e\x12" + // 0x0044032D: 0x00001E12
- "\x00d\x03-\x00\x00\x1e\x13" + // 0x0064032D: 0x00001E13
- "\x01\x12\x03\x00\x00\x00\x1e\x14" + // 0x01120300: 0x00001E14
- "\x01\x13\x03\x00\x00\x00\x1e\x15" + // 0x01130300: 0x00001E15
- "\x01\x12\x03\x01\x00\x00\x1e\x16" + // 0x01120301: 0x00001E16
- "\x01\x13\x03\x01\x00\x00\x1e\x17" + // 0x01130301: 0x00001E17
- "\x00E\x03-\x00\x00\x1e\x18" + // 0x0045032D: 0x00001E18
- "\x00e\x03-\x00\x00\x1e\x19" + // 0x0065032D: 0x00001E19
- "\x00E\x030\x00\x00\x1e\x1a" + // 0x00450330: 0x00001E1A
- "\x00e\x030\x00\x00\x1e\x1b" + // 0x00650330: 0x00001E1B
- "\x02(\x03\x06\x00\x00\x1e\x1c" + // 0x02280306: 0x00001E1C
- "\x02)\x03\x06\x00\x00\x1e\x1d" + // 0x02290306: 0x00001E1D
- "\x00F\x03\a\x00\x00\x1e\x1e" + // 0x00460307: 0x00001E1E
- "\x00f\x03\a\x00\x00\x1e\x1f" + // 0x00660307: 0x00001E1F
- "\x00G\x03\x04\x00\x00\x1e " + // 0x00470304: 0x00001E20
- "\x00g\x03\x04\x00\x00\x1e!" + // 0x00670304: 0x00001E21
- "\x00H\x03\a\x00\x00\x1e\"" + // 0x00480307: 0x00001E22
- "\x00h\x03\a\x00\x00\x1e#" + // 0x00680307: 0x00001E23
- "\x00H\x03#\x00\x00\x1e$" + // 0x00480323: 0x00001E24
- "\x00h\x03#\x00\x00\x1e%" + // 0x00680323: 0x00001E25
- "\x00H\x03\b\x00\x00\x1e&" + // 0x00480308: 0x00001E26
- "\x00h\x03\b\x00\x00\x1e'" + // 0x00680308: 0x00001E27
- "\x00H\x03'\x00\x00\x1e(" + // 0x00480327: 0x00001E28
- "\x00h\x03'\x00\x00\x1e)" + // 0x00680327: 0x00001E29
- "\x00H\x03.\x00\x00\x1e*" + // 0x0048032E: 0x00001E2A
- "\x00h\x03.\x00\x00\x1e+" + // 0x0068032E: 0x00001E2B
- "\x00I\x030\x00\x00\x1e," + // 0x00490330: 0x00001E2C
- "\x00i\x030\x00\x00\x1e-" + // 0x00690330: 0x00001E2D
- "\x00\xcf\x03\x01\x00\x00\x1e." + // 0x00CF0301: 0x00001E2E
- "\x00\xef\x03\x01\x00\x00\x1e/" + // 0x00EF0301: 0x00001E2F
- "\x00K\x03\x01\x00\x00\x1e0" + // 0x004B0301: 0x00001E30
- "\x00k\x03\x01\x00\x00\x1e1" + // 0x006B0301: 0x00001E31
- "\x00K\x03#\x00\x00\x1e2" + // 0x004B0323: 0x00001E32
- "\x00k\x03#\x00\x00\x1e3" + // 0x006B0323: 0x00001E33
- "\x00K\x031\x00\x00\x1e4" + // 0x004B0331: 0x00001E34
- "\x00k\x031\x00\x00\x1e5" + // 0x006B0331: 0x00001E35
- "\x00L\x03#\x00\x00\x1e6" + // 0x004C0323: 0x00001E36
- "\x00l\x03#\x00\x00\x1e7" + // 0x006C0323: 0x00001E37
- "\x1e6\x03\x04\x00\x00\x1e8" + // 0x1E360304: 0x00001E38
- "\x1e7\x03\x04\x00\x00\x1e9" + // 0x1E370304: 0x00001E39
- "\x00L\x031\x00\x00\x1e:" + // 0x004C0331: 0x00001E3A
- "\x00l\x031\x00\x00\x1e;" + // 0x006C0331: 0x00001E3B
- "\x00L\x03-\x00\x00\x1e<" + // 0x004C032D: 0x00001E3C
- "\x00l\x03-\x00\x00\x1e=" + // 0x006C032D: 0x00001E3D
- "\x00M\x03\x01\x00\x00\x1e>" + // 0x004D0301: 0x00001E3E
- "\x00m\x03\x01\x00\x00\x1e?" + // 0x006D0301: 0x00001E3F
- "\x00M\x03\a\x00\x00\x1e@" + // 0x004D0307: 0x00001E40
- "\x00m\x03\a\x00\x00\x1eA" + // 0x006D0307: 0x00001E41
- "\x00M\x03#\x00\x00\x1eB" + // 0x004D0323: 0x00001E42
- "\x00m\x03#\x00\x00\x1eC" + // 0x006D0323: 0x00001E43
- "\x00N\x03\a\x00\x00\x1eD" + // 0x004E0307: 0x00001E44
- "\x00n\x03\a\x00\x00\x1eE" + // 0x006E0307: 0x00001E45
- "\x00N\x03#\x00\x00\x1eF" + // 0x004E0323: 0x00001E46
- "\x00n\x03#\x00\x00\x1eG" + // 0x006E0323: 0x00001E47
- "\x00N\x031\x00\x00\x1eH" + // 0x004E0331: 0x00001E48
- "\x00n\x031\x00\x00\x1eI" + // 0x006E0331: 0x00001E49
- "\x00N\x03-\x00\x00\x1eJ" + // 0x004E032D: 0x00001E4A
- "\x00n\x03-\x00\x00\x1eK" + // 0x006E032D: 0x00001E4B
- "\x00\xd5\x03\x01\x00\x00\x1eL" + // 0x00D50301: 0x00001E4C
- "\x00\xf5\x03\x01\x00\x00\x1eM" + // 0x00F50301: 0x00001E4D
- "\x00\xd5\x03\b\x00\x00\x1eN" + // 0x00D50308: 0x00001E4E
- "\x00\xf5\x03\b\x00\x00\x1eO" + // 0x00F50308: 0x00001E4F
- "\x01L\x03\x00\x00\x00\x1eP" + // 0x014C0300: 0x00001E50
- "\x01M\x03\x00\x00\x00\x1eQ" + // 0x014D0300: 0x00001E51
- "\x01L\x03\x01\x00\x00\x1eR" + // 0x014C0301: 0x00001E52
- "\x01M\x03\x01\x00\x00\x1eS" + // 0x014D0301: 0x00001E53
- "\x00P\x03\x01\x00\x00\x1eT" + // 0x00500301: 0x00001E54
- "\x00p\x03\x01\x00\x00\x1eU" + // 0x00700301: 0x00001E55
- "\x00P\x03\a\x00\x00\x1eV" + // 0x00500307: 0x00001E56
- "\x00p\x03\a\x00\x00\x1eW" + // 0x00700307: 0x00001E57
- "\x00R\x03\a\x00\x00\x1eX" + // 0x00520307: 0x00001E58
- "\x00r\x03\a\x00\x00\x1eY" + // 0x00720307: 0x00001E59
- "\x00R\x03#\x00\x00\x1eZ" + // 0x00520323: 0x00001E5A
- "\x00r\x03#\x00\x00\x1e[" + // 0x00720323: 0x00001E5B
- "\x1eZ\x03\x04\x00\x00\x1e\\" + // 0x1E5A0304: 0x00001E5C
- "\x1e[\x03\x04\x00\x00\x1e]" + // 0x1E5B0304: 0x00001E5D
- "\x00R\x031\x00\x00\x1e^" + // 0x00520331: 0x00001E5E
- "\x00r\x031\x00\x00\x1e_" + // 0x00720331: 0x00001E5F
- "\x00S\x03\a\x00\x00\x1e`" + // 0x00530307: 0x00001E60
- "\x00s\x03\a\x00\x00\x1ea" + // 0x00730307: 0x00001E61
- "\x00S\x03#\x00\x00\x1eb" + // 0x00530323: 0x00001E62
- "\x00s\x03#\x00\x00\x1ec" + // 0x00730323: 0x00001E63
- "\x01Z\x03\a\x00\x00\x1ed" + // 0x015A0307: 0x00001E64
- "\x01[\x03\a\x00\x00\x1ee" + // 0x015B0307: 0x00001E65
- "\x01`\x03\a\x00\x00\x1ef" + // 0x01600307: 0x00001E66
- "\x01a\x03\a\x00\x00\x1eg" + // 0x01610307: 0x00001E67
- "\x1eb\x03\a\x00\x00\x1eh" + // 0x1E620307: 0x00001E68
- "\x1ec\x03\a\x00\x00\x1ei" + // 0x1E630307: 0x00001E69
- "\x00T\x03\a\x00\x00\x1ej" + // 0x00540307: 0x00001E6A
- "\x00t\x03\a\x00\x00\x1ek" + // 0x00740307: 0x00001E6B
- "\x00T\x03#\x00\x00\x1el" + // 0x00540323: 0x00001E6C
- "\x00t\x03#\x00\x00\x1em" + // 0x00740323: 0x00001E6D
- "\x00T\x031\x00\x00\x1en" + // 0x00540331: 0x00001E6E
- "\x00t\x031\x00\x00\x1eo" + // 0x00740331: 0x00001E6F
- "\x00T\x03-\x00\x00\x1ep" + // 0x0054032D: 0x00001E70
- "\x00t\x03-\x00\x00\x1eq" + // 0x0074032D: 0x00001E71
- "\x00U\x03$\x00\x00\x1er" + // 0x00550324: 0x00001E72
- "\x00u\x03$\x00\x00\x1es" + // 0x00750324: 0x00001E73
- "\x00U\x030\x00\x00\x1et" + // 0x00550330: 0x00001E74
- "\x00u\x030\x00\x00\x1eu" + // 0x00750330: 0x00001E75
- "\x00U\x03-\x00\x00\x1ev" + // 0x0055032D: 0x00001E76
- "\x00u\x03-\x00\x00\x1ew" + // 0x0075032D: 0x00001E77
- "\x01h\x03\x01\x00\x00\x1ex" + // 0x01680301: 0x00001E78
- "\x01i\x03\x01\x00\x00\x1ey" + // 0x01690301: 0x00001E79
- "\x01j\x03\b\x00\x00\x1ez" + // 0x016A0308: 0x00001E7A
- "\x01k\x03\b\x00\x00\x1e{" + // 0x016B0308: 0x00001E7B
- "\x00V\x03\x03\x00\x00\x1e|" + // 0x00560303: 0x00001E7C
- "\x00v\x03\x03\x00\x00\x1e}" + // 0x00760303: 0x00001E7D
- "\x00V\x03#\x00\x00\x1e~" + // 0x00560323: 0x00001E7E
- "\x00v\x03#\x00\x00\x1e\x7f" + // 0x00760323: 0x00001E7F
- "\x00W\x03\x00\x00\x00\x1e\x80" + // 0x00570300: 0x00001E80
- "\x00w\x03\x00\x00\x00\x1e\x81" + // 0x00770300: 0x00001E81
- "\x00W\x03\x01\x00\x00\x1e\x82" + // 0x00570301: 0x00001E82
- "\x00w\x03\x01\x00\x00\x1e\x83" + // 0x00770301: 0x00001E83
- "\x00W\x03\b\x00\x00\x1e\x84" + // 0x00570308: 0x00001E84
- "\x00w\x03\b\x00\x00\x1e\x85" + // 0x00770308: 0x00001E85
- "\x00W\x03\a\x00\x00\x1e\x86" + // 0x00570307: 0x00001E86
- "\x00w\x03\a\x00\x00\x1e\x87" + // 0x00770307: 0x00001E87
- "\x00W\x03#\x00\x00\x1e\x88" + // 0x00570323: 0x00001E88
- "\x00w\x03#\x00\x00\x1e\x89" + // 0x00770323: 0x00001E89
- "\x00X\x03\a\x00\x00\x1e\x8a" + // 0x00580307: 0x00001E8A
- "\x00x\x03\a\x00\x00\x1e\x8b" + // 0x00780307: 0x00001E8B
- "\x00X\x03\b\x00\x00\x1e\x8c" + // 0x00580308: 0x00001E8C
- "\x00x\x03\b\x00\x00\x1e\x8d" + // 0x00780308: 0x00001E8D
- "\x00Y\x03\a\x00\x00\x1e\x8e" + // 0x00590307: 0x00001E8E
- "\x00y\x03\a\x00\x00\x1e\x8f" + // 0x00790307: 0x00001E8F
- "\x00Z\x03\x02\x00\x00\x1e\x90" + // 0x005A0302: 0x00001E90
- "\x00z\x03\x02\x00\x00\x1e\x91" + // 0x007A0302: 0x00001E91
- "\x00Z\x03#\x00\x00\x1e\x92" + // 0x005A0323: 0x00001E92
- "\x00z\x03#\x00\x00\x1e\x93" + // 0x007A0323: 0x00001E93
- "\x00Z\x031\x00\x00\x1e\x94" + // 0x005A0331: 0x00001E94
- "\x00z\x031\x00\x00\x1e\x95" + // 0x007A0331: 0x00001E95
- "\x00h\x031\x00\x00\x1e\x96" + // 0x00680331: 0x00001E96
- "\x00t\x03\b\x00\x00\x1e\x97" + // 0x00740308: 0x00001E97
- "\x00w\x03\n\x00\x00\x1e\x98" + // 0x0077030A: 0x00001E98
- "\x00y\x03\n\x00\x00\x1e\x99" + // 0x0079030A: 0x00001E99
- "\x01\x7f\x03\a\x00\x00\x1e\x9b" + // 0x017F0307: 0x00001E9B
- "\x00A\x03#\x00\x00\x1e\xa0" + // 0x00410323: 0x00001EA0
- "\x00a\x03#\x00\x00\x1e\xa1" + // 0x00610323: 0x00001EA1
- "\x00A\x03\t\x00\x00\x1e\xa2" + // 0x00410309: 0x00001EA2
- "\x00a\x03\t\x00\x00\x1e\xa3" + // 0x00610309: 0x00001EA3
- "\x00\xc2\x03\x01\x00\x00\x1e\xa4" + // 0x00C20301: 0x00001EA4
- "\x00\xe2\x03\x01\x00\x00\x1e\xa5" + // 0x00E20301: 0x00001EA5
- "\x00\xc2\x03\x00\x00\x00\x1e\xa6" + // 0x00C20300: 0x00001EA6
- "\x00\xe2\x03\x00\x00\x00\x1e\xa7" + // 0x00E20300: 0x00001EA7
- "\x00\xc2\x03\t\x00\x00\x1e\xa8" + // 0x00C20309: 0x00001EA8
- "\x00\xe2\x03\t\x00\x00\x1e\xa9" + // 0x00E20309: 0x00001EA9
- "\x00\xc2\x03\x03\x00\x00\x1e\xaa" + // 0x00C20303: 0x00001EAA
- "\x00\xe2\x03\x03\x00\x00\x1e\xab" + // 0x00E20303: 0x00001EAB
- "\x1e\xa0\x03\x02\x00\x00\x1e\xac" + // 0x1EA00302: 0x00001EAC
- "\x1e\xa1\x03\x02\x00\x00\x1e\xad" + // 0x1EA10302: 0x00001EAD
- "\x01\x02\x03\x01\x00\x00\x1e\xae" + // 0x01020301: 0x00001EAE
- "\x01\x03\x03\x01\x00\x00\x1e\xaf" + // 0x01030301: 0x00001EAF
- "\x01\x02\x03\x00\x00\x00\x1e\xb0" + // 0x01020300: 0x00001EB0
- "\x01\x03\x03\x00\x00\x00\x1e\xb1" + // 0x01030300: 0x00001EB1
- "\x01\x02\x03\t\x00\x00\x1e\xb2" + // 0x01020309: 0x00001EB2
- "\x01\x03\x03\t\x00\x00\x1e\xb3" + // 0x01030309: 0x00001EB3
- "\x01\x02\x03\x03\x00\x00\x1e\xb4" + // 0x01020303: 0x00001EB4
- "\x01\x03\x03\x03\x00\x00\x1e\xb5" + // 0x01030303: 0x00001EB5
- "\x1e\xa0\x03\x06\x00\x00\x1e\xb6" + // 0x1EA00306: 0x00001EB6
- "\x1e\xa1\x03\x06\x00\x00\x1e\xb7" + // 0x1EA10306: 0x00001EB7
- "\x00E\x03#\x00\x00\x1e\xb8" + // 0x00450323: 0x00001EB8
- "\x00e\x03#\x00\x00\x1e\xb9" + // 0x00650323: 0x00001EB9
- "\x00E\x03\t\x00\x00\x1e\xba" + // 0x00450309: 0x00001EBA
- "\x00e\x03\t\x00\x00\x1e\xbb" + // 0x00650309: 0x00001EBB
- "\x00E\x03\x03\x00\x00\x1e\xbc" + // 0x00450303: 0x00001EBC
- "\x00e\x03\x03\x00\x00\x1e\xbd" + // 0x00650303: 0x00001EBD
- "\x00\xca\x03\x01\x00\x00\x1e\xbe" + // 0x00CA0301: 0x00001EBE
- "\x00\xea\x03\x01\x00\x00\x1e\xbf" + // 0x00EA0301: 0x00001EBF
- "\x00\xca\x03\x00\x00\x00\x1e\xc0" + // 0x00CA0300: 0x00001EC0
- "\x00\xea\x03\x00\x00\x00\x1e\xc1" + // 0x00EA0300: 0x00001EC1
- "\x00\xca\x03\t\x00\x00\x1e\xc2" + // 0x00CA0309: 0x00001EC2
- "\x00\xea\x03\t\x00\x00\x1e\xc3" + // 0x00EA0309: 0x00001EC3
- "\x00\xca\x03\x03\x00\x00\x1e\xc4" + // 0x00CA0303: 0x00001EC4
- "\x00\xea\x03\x03\x00\x00\x1e\xc5" + // 0x00EA0303: 0x00001EC5
- "\x1e\xb8\x03\x02\x00\x00\x1e\xc6" + // 0x1EB80302: 0x00001EC6
- "\x1e\xb9\x03\x02\x00\x00\x1e\xc7" + // 0x1EB90302: 0x00001EC7
- "\x00I\x03\t\x00\x00\x1e\xc8" + // 0x00490309: 0x00001EC8
- "\x00i\x03\t\x00\x00\x1e\xc9" + // 0x00690309: 0x00001EC9
- "\x00I\x03#\x00\x00\x1e\xca" + // 0x00490323: 0x00001ECA
- "\x00i\x03#\x00\x00\x1e\xcb" + // 0x00690323: 0x00001ECB
- "\x00O\x03#\x00\x00\x1e\xcc" + // 0x004F0323: 0x00001ECC
- "\x00o\x03#\x00\x00\x1e\xcd" + // 0x006F0323: 0x00001ECD
- "\x00O\x03\t\x00\x00\x1e\xce" + // 0x004F0309: 0x00001ECE
- "\x00o\x03\t\x00\x00\x1e\xcf" + // 0x006F0309: 0x00001ECF
- "\x00\xd4\x03\x01\x00\x00\x1e\xd0" + // 0x00D40301: 0x00001ED0
- "\x00\xf4\x03\x01\x00\x00\x1e\xd1" + // 0x00F40301: 0x00001ED1
- "\x00\xd4\x03\x00\x00\x00\x1e\xd2" + // 0x00D40300: 0x00001ED2
- "\x00\xf4\x03\x00\x00\x00\x1e\xd3" + // 0x00F40300: 0x00001ED3
- "\x00\xd4\x03\t\x00\x00\x1e\xd4" + // 0x00D40309: 0x00001ED4
- "\x00\xf4\x03\t\x00\x00\x1e\xd5" + // 0x00F40309: 0x00001ED5
- "\x00\xd4\x03\x03\x00\x00\x1e\xd6" + // 0x00D40303: 0x00001ED6
- "\x00\xf4\x03\x03\x00\x00\x1e\xd7" + // 0x00F40303: 0x00001ED7
- "\x1e\xcc\x03\x02\x00\x00\x1e\xd8" + // 0x1ECC0302: 0x00001ED8
- "\x1e\xcd\x03\x02\x00\x00\x1e\xd9" + // 0x1ECD0302: 0x00001ED9
- "\x01\xa0\x03\x01\x00\x00\x1e\xda" + // 0x01A00301: 0x00001EDA
- "\x01\xa1\x03\x01\x00\x00\x1e\xdb" + // 0x01A10301: 0x00001EDB
- "\x01\xa0\x03\x00\x00\x00\x1e\xdc" + // 0x01A00300: 0x00001EDC
- "\x01\xa1\x03\x00\x00\x00\x1e\xdd" + // 0x01A10300: 0x00001EDD
- "\x01\xa0\x03\t\x00\x00\x1e\xde" + // 0x01A00309: 0x00001EDE
- "\x01\xa1\x03\t\x00\x00\x1e\xdf" + // 0x01A10309: 0x00001EDF
- "\x01\xa0\x03\x03\x00\x00\x1e\xe0" + // 0x01A00303: 0x00001EE0
- "\x01\xa1\x03\x03\x00\x00\x1e\xe1" + // 0x01A10303: 0x00001EE1
- "\x01\xa0\x03#\x00\x00\x1e\xe2" + // 0x01A00323: 0x00001EE2
- "\x01\xa1\x03#\x00\x00\x1e\xe3" + // 0x01A10323: 0x00001EE3
- "\x00U\x03#\x00\x00\x1e\xe4" + // 0x00550323: 0x00001EE4
- "\x00u\x03#\x00\x00\x1e\xe5" + // 0x00750323: 0x00001EE5
- "\x00U\x03\t\x00\x00\x1e\xe6" + // 0x00550309: 0x00001EE6
- "\x00u\x03\t\x00\x00\x1e\xe7" + // 0x00750309: 0x00001EE7
- "\x01\xaf\x03\x01\x00\x00\x1e\xe8" + // 0x01AF0301: 0x00001EE8
- "\x01\xb0\x03\x01\x00\x00\x1e\xe9" + // 0x01B00301: 0x00001EE9
- "\x01\xaf\x03\x00\x00\x00\x1e\xea" + // 0x01AF0300: 0x00001EEA
- "\x01\xb0\x03\x00\x00\x00\x1e\xeb" + // 0x01B00300: 0x00001EEB
- "\x01\xaf\x03\t\x00\x00\x1e\xec" + // 0x01AF0309: 0x00001EEC
- "\x01\xb0\x03\t\x00\x00\x1e\xed" + // 0x01B00309: 0x00001EED
- "\x01\xaf\x03\x03\x00\x00\x1e\xee" + // 0x01AF0303: 0x00001EEE
- "\x01\xb0\x03\x03\x00\x00\x1e\xef" + // 0x01B00303: 0x00001EEF
- "\x01\xaf\x03#\x00\x00\x1e\xf0" + // 0x01AF0323: 0x00001EF0
- "\x01\xb0\x03#\x00\x00\x1e\xf1" + // 0x01B00323: 0x00001EF1
- "\x00Y\x03\x00\x00\x00\x1e\xf2" + // 0x00590300: 0x00001EF2
- "\x00y\x03\x00\x00\x00\x1e\xf3" + // 0x00790300: 0x00001EF3
- "\x00Y\x03#\x00\x00\x1e\xf4" + // 0x00590323: 0x00001EF4
- "\x00y\x03#\x00\x00\x1e\xf5" + // 0x00790323: 0x00001EF5
- "\x00Y\x03\t\x00\x00\x1e\xf6" + // 0x00590309: 0x00001EF6
- "\x00y\x03\t\x00\x00\x1e\xf7" + // 0x00790309: 0x00001EF7
- "\x00Y\x03\x03\x00\x00\x1e\xf8" + // 0x00590303: 0x00001EF8
- "\x00y\x03\x03\x00\x00\x1e\xf9" + // 0x00790303: 0x00001EF9
- "\x03\xb1\x03\x13\x00\x00\x1f\x00" + // 0x03B10313: 0x00001F00
- "\x03\xb1\x03\x14\x00\x00\x1f\x01" + // 0x03B10314: 0x00001F01
- "\x1f\x00\x03\x00\x00\x00\x1f\x02" + // 0x1F000300: 0x00001F02
- "\x1f\x01\x03\x00\x00\x00\x1f\x03" + // 0x1F010300: 0x00001F03
- "\x1f\x00\x03\x01\x00\x00\x1f\x04" + // 0x1F000301: 0x00001F04
- "\x1f\x01\x03\x01\x00\x00\x1f\x05" + // 0x1F010301: 0x00001F05
- "\x1f\x00\x03B\x00\x00\x1f\x06" + // 0x1F000342: 0x00001F06
- "\x1f\x01\x03B\x00\x00\x1f\a" + // 0x1F010342: 0x00001F07
- "\x03\x91\x03\x13\x00\x00\x1f\b" + // 0x03910313: 0x00001F08
- "\x03\x91\x03\x14\x00\x00\x1f\t" + // 0x03910314: 0x00001F09
- "\x1f\b\x03\x00\x00\x00\x1f\n" + // 0x1F080300: 0x00001F0A
- "\x1f\t\x03\x00\x00\x00\x1f\v" + // 0x1F090300: 0x00001F0B
- "\x1f\b\x03\x01\x00\x00\x1f\f" + // 0x1F080301: 0x00001F0C
- "\x1f\t\x03\x01\x00\x00\x1f\r" + // 0x1F090301: 0x00001F0D
- "\x1f\b\x03B\x00\x00\x1f\x0e" + // 0x1F080342: 0x00001F0E
- "\x1f\t\x03B\x00\x00\x1f\x0f" + // 0x1F090342: 0x00001F0F
- "\x03\xb5\x03\x13\x00\x00\x1f\x10" + // 0x03B50313: 0x00001F10
- "\x03\xb5\x03\x14\x00\x00\x1f\x11" + // 0x03B50314: 0x00001F11
- "\x1f\x10\x03\x00\x00\x00\x1f\x12" + // 0x1F100300: 0x00001F12
- "\x1f\x11\x03\x00\x00\x00\x1f\x13" + // 0x1F110300: 0x00001F13
- "\x1f\x10\x03\x01\x00\x00\x1f\x14" + // 0x1F100301: 0x00001F14
- "\x1f\x11\x03\x01\x00\x00\x1f\x15" + // 0x1F110301: 0x00001F15
- "\x03\x95\x03\x13\x00\x00\x1f\x18" + // 0x03950313: 0x00001F18
- "\x03\x95\x03\x14\x00\x00\x1f\x19" + // 0x03950314: 0x00001F19
- "\x1f\x18\x03\x00\x00\x00\x1f\x1a" + // 0x1F180300: 0x00001F1A
- "\x1f\x19\x03\x00\x00\x00\x1f\x1b" + // 0x1F190300: 0x00001F1B
- "\x1f\x18\x03\x01\x00\x00\x1f\x1c" + // 0x1F180301: 0x00001F1C
- "\x1f\x19\x03\x01\x00\x00\x1f\x1d" + // 0x1F190301: 0x00001F1D
- "\x03\xb7\x03\x13\x00\x00\x1f " + // 0x03B70313: 0x00001F20
- "\x03\xb7\x03\x14\x00\x00\x1f!" + // 0x03B70314: 0x00001F21
- "\x1f \x03\x00\x00\x00\x1f\"" + // 0x1F200300: 0x00001F22
- "\x1f!\x03\x00\x00\x00\x1f#" + // 0x1F210300: 0x00001F23
- "\x1f \x03\x01\x00\x00\x1f$" + // 0x1F200301: 0x00001F24
- "\x1f!\x03\x01\x00\x00\x1f%" + // 0x1F210301: 0x00001F25
- "\x1f \x03B\x00\x00\x1f&" + // 0x1F200342: 0x00001F26
- "\x1f!\x03B\x00\x00\x1f'" + // 0x1F210342: 0x00001F27
- "\x03\x97\x03\x13\x00\x00\x1f(" + // 0x03970313: 0x00001F28
- "\x03\x97\x03\x14\x00\x00\x1f)" + // 0x03970314: 0x00001F29
- "\x1f(\x03\x00\x00\x00\x1f*" + // 0x1F280300: 0x00001F2A
- "\x1f)\x03\x00\x00\x00\x1f+" + // 0x1F290300: 0x00001F2B
- "\x1f(\x03\x01\x00\x00\x1f," + // 0x1F280301: 0x00001F2C
- "\x1f)\x03\x01\x00\x00\x1f-" + // 0x1F290301: 0x00001F2D
- "\x1f(\x03B\x00\x00\x1f." + // 0x1F280342: 0x00001F2E
- "\x1f)\x03B\x00\x00\x1f/" + // 0x1F290342: 0x00001F2F
- "\x03\xb9\x03\x13\x00\x00\x1f0" + // 0x03B90313: 0x00001F30
- "\x03\xb9\x03\x14\x00\x00\x1f1" + // 0x03B90314: 0x00001F31
- "\x1f0\x03\x00\x00\x00\x1f2" + // 0x1F300300: 0x00001F32
- "\x1f1\x03\x00\x00\x00\x1f3" + // 0x1F310300: 0x00001F33
- "\x1f0\x03\x01\x00\x00\x1f4" + // 0x1F300301: 0x00001F34
- "\x1f1\x03\x01\x00\x00\x1f5" + // 0x1F310301: 0x00001F35
- "\x1f0\x03B\x00\x00\x1f6" + // 0x1F300342: 0x00001F36
- "\x1f1\x03B\x00\x00\x1f7" + // 0x1F310342: 0x00001F37
- "\x03\x99\x03\x13\x00\x00\x1f8" + // 0x03990313: 0x00001F38
- "\x03\x99\x03\x14\x00\x00\x1f9" + // 0x03990314: 0x00001F39
- "\x1f8\x03\x00\x00\x00\x1f:" + // 0x1F380300: 0x00001F3A
- "\x1f9\x03\x00\x00\x00\x1f;" + // 0x1F390300: 0x00001F3B
- "\x1f8\x03\x01\x00\x00\x1f<" + // 0x1F380301: 0x00001F3C
- "\x1f9\x03\x01\x00\x00\x1f=" + // 0x1F390301: 0x00001F3D
- "\x1f8\x03B\x00\x00\x1f>" + // 0x1F380342: 0x00001F3E
- "\x1f9\x03B\x00\x00\x1f?" + // 0x1F390342: 0x00001F3F
- "\x03\xbf\x03\x13\x00\x00\x1f@" + // 0x03BF0313: 0x00001F40
- "\x03\xbf\x03\x14\x00\x00\x1fA" + // 0x03BF0314: 0x00001F41
- "\x1f@\x03\x00\x00\x00\x1fB" + // 0x1F400300: 0x00001F42
- "\x1fA\x03\x00\x00\x00\x1fC" + // 0x1F410300: 0x00001F43
- "\x1f@\x03\x01\x00\x00\x1fD" + // 0x1F400301: 0x00001F44
- "\x1fA\x03\x01\x00\x00\x1fE" + // 0x1F410301: 0x00001F45
- "\x03\x9f\x03\x13\x00\x00\x1fH" + // 0x039F0313: 0x00001F48
- "\x03\x9f\x03\x14\x00\x00\x1fI" + // 0x039F0314: 0x00001F49
- "\x1fH\x03\x00\x00\x00\x1fJ" + // 0x1F480300: 0x00001F4A
- "\x1fI\x03\x00\x00\x00\x1fK" + // 0x1F490300: 0x00001F4B
- "\x1fH\x03\x01\x00\x00\x1fL" + // 0x1F480301: 0x00001F4C
- "\x1fI\x03\x01\x00\x00\x1fM" + // 0x1F490301: 0x00001F4D
- "\x03\xc5\x03\x13\x00\x00\x1fP" + // 0x03C50313: 0x00001F50
- "\x03\xc5\x03\x14\x00\x00\x1fQ" + // 0x03C50314: 0x00001F51
- "\x1fP\x03\x00\x00\x00\x1fR" + // 0x1F500300: 0x00001F52
- "\x1fQ\x03\x00\x00\x00\x1fS" + // 0x1F510300: 0x00001F53
- "\x1fP\x03\x01\x00\x00\x1fT" + // 0x1F500301: 0x00001F54
- "\x1fQ\x03\x01\x00\x00\x1fU" + // 0x1F510301: 0x00001F55
- "\x1fP\x03B\x00\x00\x1fV" + // 0x1F500342: 0x00001F56
- "\x1fQ\x03B\x00\x00\x1fW" + // 0x1F510342: 0x00001F57
- "\x03\xa5\x03\x14\x00\x00\x1fY" + // 0x03A50314: 0x00001F59
- "\x1fY\x03\x00\x00\x00\x1f[" + // 0x1F590300: 0x00001F5B
- "\x1fY\x03\x01\x00\x00\x1f]" + // 0x1F590301: 0x00001F5D
- "\x1fY\x03B\x00\x00\x1f_" + // 0x1F590342: 0x00001F5F
- "\x03\xc9\x03\x13\x00\x00\x1f`" + // 0x03C90313: 0x00001F60
- "\x03\xc9\x03\x14\x00\x00\x1fa" + // 0x03C90314: 0x00001F61
- "\x1f`\x03\x00\x00\x00\x1fb" + // 0x1F600300: 0x00001F62
- "\x1fa\x03\x00\x00\x00\x1fc" + // 0x1F610300: 0x00001F63
- "\x1f`\x03\x01\x00\x00\x1fd" + // 0x1F600301: 0x00001F64
- "\x1fa\x03\x01\x00\x00\x1fe" + // 0x1F610301: 0x00001F65
- "\x1f`\x03B\x00\x00\x1ff" + // 0x1F600342: 0x00001F66
- "\x1fa\x03B\x00\x00\x1fg" + // 0x1F610342: 0x00001F67
- "\x03\xa9\x03\x13\x00\x00\x1fh" + // 0x03A90313: 0x00001F68
- "\x03\xa9\x03\x14\x00\x00\x1fi" + // 0x03A90314: 0x00001F69
- "\x1fh\x03\x00\x00\x00\x1fj" + // 0x1F680300: 0x00001F6A
- "\x1fi\x03\x00\x00\x00\x1fk" + // 0x1F690300: 0x00001F6B
- "\x1fh\x03\x01\x00\x00\x1fl" + // 0x1F680301: 0x00001F6C
- "\x1fi\x03\x01\x00\x00\x1fm" + // 0x1F690301: 0x00001F6D
- "\x1fh\x03B\x00\x00\x1fn" + // 0x1F680342: 0x00001F6E
- "\x1fi\x03B\x00\x00\x1fo" + // 0x1F690342: 0x00001F6F
- "\x03\xb1\x03\x00\x00\x00\x1fp" + // 0x03B10300: 0x00001F70
- "\x03\xb5\x03\x00\x00\x00\x1fr" + // 0x03B50300: 0x00001F72
- "\x03\xb7\x03\x00\x00\x00\x1ft" + // 0x03B70300: 0x00001F74
- "\x03\xb9\x03\x00\x00\x00\x1fv" + // 0x03B90300: 0x00001F76
- "\x03\xbf\x03\x00\x00\x00\x1fx" + // 0x03BF0300: 0x00001F78
- "\x03\xc5\x03\x00\x00\x00\x1fz" + // 0x03C50300: 0x00001F7A
- "\x03\xc9\x03\x00\x00\x00\x1f|" + // 0x03C90300: 0x00001F7C
- "\x1f\x00\x03E\x00\x00\x1f\x80" + // 0x1F000345: 0x00001F80
- "\x1f\x01\x03E\x00\x00\x1f\x81" + // 0x1F010345: 0x00001F81
- "\x1f\x02\x03E\x00\x00\x1f\x82" + // 0x1F020345: 0x00001F82
- "\x1f\x03\x03E\x00\x00\x1f\x83" + // 0x1F030345: 0x00001F83
- "\x1f\x04\x03E\x00\x00\x1f\x84" + // 0x1F040345: 0x00001F84
- "\x1f\x05\x03E\x00\x00\x1f\x85" + // 0x1F050345: 0x00001F85
- "\x1f\x06\x03E\x00\x00\x1f\x86" + // 0x1F060345: 0x00001F86
- "\x1f\a\x03E\x00\x00\x1f\x87" + // 0x1F070345: 0x00001F87
- "\x1f\b\x03E\x00\x00\x1f\x88" + // 0x1F080345: 0x00001F88
- "\x1f\t\x03E\x00\x00\x1f\x89" + // 0x1F090345: 0x00001F89
- "\x1f\n\x03E\x00\x00\x1f\x8a" + // 0x1F0A0345: 0x00001F8A
- "\x1f\v\x03E\x00\x00\x1f\x8b" + // 0x1F0B0345: 0x00001F8B
- "\x1f\f\x03E\x00\x00\x1f\x8c" + // 0x1F0C0345: 0x00001F8C
- "\x1f\r\x03E\x00\x00\x1f\x8d" + // 0x1F0D0345: 0x00001F8D
- "\x1f\x0e\x03E\x00\x00\x1f\x8e" + // 0x1F0E0345: 0x00001F8E
- "\x1f\x0f\x03E\x00\x00\x1f\x8f" + // 0x1F0F0345: 0x00001F8F
- "\x1f \x03E\x00\x00\x1f\x90" + // 0x1F200345: 0x00001F90
- "\x1f!\x03E\x00\x00\x1f\x91" + // 0x1F210345: 0x00001F91
- "\x1f\"\x03E\x00\x00\x1f\x92" + // 0x1F220345: 0x00001F92
- "\x1f#\x03E\x00\x00\x1f\x93" + // 0x1F230345: 0x00001F93
- "\x1f$\x03E\x00\x00\x1f\x94" + // 0x1F240345: 0x00001F94
- "\x1f%\x03E\x00\x00\x1f\x95" + // 0x1F250345: 0x00001F95
- "\x1f&\x03E\x00\x00\x1f\x96" + // 0x1F260345: 0x00001F96
- "\x1f'\x03E\x00\x00\x1f\x97" + // 0x1F270345: 0x00001F97
- "\x1f(\x03E\x00\x00\x1f\x98" + // 0x1F280345: 0x00001F98
- "\x1f)\x03E\x00\x00\x1f\x99" + // 0x1F290345: 0x00001F99
- "\x1f*\x03E\x00\x00\x1f\x9a" + // 0x1F2A0345: 0x00001F9A
- "\x1f+\x03E\x00\x00\x1f\x9b" + // 0x1F2B0345: 0x00001F9B
- "\x1f,\x03E\x00\x00\x1f\x9c" + // 0x1F2C0345: 0x00001F9C
- "\x1f-\x03E\x00\x00\x1f\x9d" + // 0x1F2D0345: 0x00001F9D
- "\x1f.\x03E\x00\x00\x1f\x9e" + // 0x1F2E0345: 0x00001F9E
- "\x1f/\x03E\x00\x00\x1f\x9f" + // 0x1F2F0345: 0x00001F9F
- "\x1f`\x03E\x00\x00\x1f\xa0" + // 0x1F600345: 0x00001FA0
- "\x1fa\x03E\x00\x00\x1f\xa1" + // 0x1F610345: 0x00001FA1
- "\x1fb\x03E\x00\x00\x1f\xa2" + // 0x1F620345: 0x00001FA2
- "\x1fc\x03E\x00\x00\x1f\xa3" + // 0x1F630345: 0x00001FA3
- "\x1fd\x03E\x00\x00\x1f\xa4" + // 0x1F640345: 0x00001FA4
- "\x1fe\x03E\x00\x00\x1f\xa5" + // 0x1F650345: 0x00001FA5
- "\x1ff\x03E\x00\x00\x1f\xa6" + // 0x1F660345: 0x00001FA6
- "\x1fg\x03E\x00\x00\x1f\xa7" + // 0x1F670345: 0x00001FA7
- "\x1fh\x03E\x00\x00\x1f\xa8" + // 0x1F680345: 0x00001FA8
- "\x1fi\x03E\x00\x00\x1f\xa9" + // 0x1F690345: 0x00001FA9
- "\x1fj\x03E\x00\x00\x1f\xaa" + // 0x1F6A0345: 0x00001FAA
- "\x1fk\x03E\x00\x00\x1f\xab" + // 0x1F6B0345: 0x00001FAB
- "\x1fl\x03E\x00\x00\x1f\xac" + // 0x1F6C0345: 0x00001FAC
- "\x1fm\x03E\x00\x00\x1f\xad" + // 0x1F6D0345: 0x00001FAD
- "\x1fn\x03E\x00\x00\x1f\xae" + // 0x1F6E0345: 0x00001FAE
- "\x1fo\x03E\x00\x00\x1f\xaf" + // 0x1F6F0345: 0x00001FAF
- "\x03\xb1\x03\x06\x00\x00\x1f\xb0" + // 0x03B10306: 0x00001FB0
- "\x03\xb1\x03\x04\x00\x00\x1f\xb1" + // 0x03B10304: 0x00001FB1
- "\x1fp\x03E\x00\x00\x1f\xb2" + // 0x1F700345: 0x00001FB2
- "\x03\xb1\x03E\x00\x00\x1f\xb3" + // 0x03B10345: 0x00001FB3
- "\x03\xac\x03E\x00\x00\x1f\xb4" + // 0x03AC0345: 0x00001FB4
- "\x03\xb1\x03B\x00\x00\x1f\xb6" + // 0x03B10342: 0x00001FB6
- "\x1f\xb6\x03E\x00\x00\x1f\xb7" + // 0x1FB60345: 0x00001FB7
- "\x03\x91\x03\x06\x00\x00\x1f\xb8" + // 0x03910306: 0x00001FB8
- "\x03\x91\x03\x04\x00\x00\x1f\xb9" + // 0x03910304: 0x00001FB9
- "\x03\x91\x03\x00\x00\x00\x1f\xba" + // 0x03910300: 0x00001FBA
- "\x03\x91\x03E\x00\x00\x1f\xbc" + // 0x03910345: 0x00001FBC
- "\x00\xa8\x03B\x00\x00\x1f\xc1" + // 0x00A80342: 0x00001FC1
- "\x1ft\x03E\x00\x00\x1f\xc2" + // 0x1F740345: 0x00001FC2
- "\x03\xb7\x03E\x00\x00\x1f\xc3" + // 0x03B70345: 0x00001FC3
- "\x03\xae\x03E\x00\x00\x1f\xc4" + // 0x03AE0345: 0x00001FC4
- "\x03\xb7\x03B\x00\x00\x1f\xc6" + // 0x03B70342: 0x00001FC6
- "\x1f\xc6\x03E\x00\x00\x1f\xc7" + // 0x1FC60345: 0x00001FC7
- "\x03\x95\x03\x00\x00\x00\x1f\xc8" + // 0x03950300: 0x00001FC8
- "\x03\x97\x03\x00\x00\x00\x1f\xca" + // 0x03970300: 0x00001FCA
- "\x03\x97\x03E\x00\x00\x1f\xcc" + // 0x03970345: 0x00001FCC
- "\x1f\xbf\x03\x00\x00\x00\x1f\xcd" + // 0x1FBF0300: 0x00001FCD
- "\x1f\xbf\x03\x01\x00\x00\x1f\xce" + // 0x1FBF0301: 0x00001FCE
- "\x1f\xbf\x03B\x00\x00\x1f\xcf" + // 0x1FBF0342: 0x00001FCF
- "\x03\xb9\x03\x06\x00\x00\x1f\xd0" + // 0x03B90306: 0x00001FD0
- "\x03\xb9\x03\x04\x00\x00\x1f\xd1" + // 0x03B90304: 0x00001FD1
- "\x03\xca\x03\x00\x00\x00\x1f\xd2" + // 0x03CA0300: 0x00001FD2
- "\x03\xb9\x03B\x00\x00\x1f\xd6" + // 0x03B90342: 0x00001FD6
- "\x03\xca\x03B\x00\x00\x1f\xd7" + // 0x03CA0342: 0x00001FD7
- "\x03\x99\x03\x06\x00\x00\x1f\xd8" + // 0x03990306: 0x00001FD8
- "\x03\x99\x03\x04\x00\x00\x1f\xd9" + // 0x03990304: 0x00001FD9
- "\x03\x99\x03\x00\x00\x00\x1f\xda" + // 0x03990300: 0x00001FDA
- "\x1f\xfe\x03\x00\x00\x00\x1f\xdd" + // 0x1FFE0300: 0x00001FDD
- "\x1f\xfe\x03\x01\x00\x00\x1f\xde" + // 0x1FFE0301: 0x00001FDE
- "\x1f\xfe\x03B\x00\x00\x1f\xdf" + // 0x1FFE0342: 0x00001FDF
- "\x03\xc5\x03\x06\x00\x00\x1f\xe0" + // 0x03C50306: 0x00001FE0
- "\x03\xc5\x03\x04\x00\x00\x1f\xe1" + // 0x03C50304: 0x00001FE1
- "\x03\xcb\x03\x00\x00\x00\x1f\xe2" + // 0x03CB0300: 0x00001FE2
- "\x03\xc1\x03\x13\x00\x00\x1f\xe4" + // 0x03C10313: 0x00001FE4
- "\x03\xc1\x03\x14\x00\x00\x1f\xe5" + // 0x03C10314: 0x00001FE5
- "\x03\xc5\x03B\x00\x00\x1f\xe6" + // 0x03C50342: 0x00001FE6
- "\x03\xcb\x03B\x00\x00\x1f\xe7" + // 0x03CB0342: 0x00001FE7
- "\x03\xa5\x03\x06\x00\x00\x1f\xe8" + // 0x03A50306: 0x00001FE8
- "\x03\xa5\x03\x04\x00\x00\x1f\xe9" + // 0x03A50304: 0x00001FE9
- "\x03\xa5\x03\x00\x00\x00\x1f\xea" + // 0x03A50300: 0x00001FEA
- "\x03\xa1\x03\x14\x00\x00\x1f\xec" + // 0x03A10314: 0x00001FEC
- "\x00\xa8\x03\x00\x00\x00\x1f\xed" + // 0x00A80300: 0x00001FED
- "\x1f|\x03E\x00\x00\x1f\xf2" + // 0x1F7C0345: 0x00001FF2
- "\x03\xc9\x03E\x00\x00\x1f\xf3" + // 0x03C90345: 0x00001FF3
- "\x03\xce\x03E\x00\x00\x1f\xf4" + // 0x03CE0345: 0x00001FF4
- "\x03\xc9\x03B\x00\x00\x1f\xf6" + // 0x03C90342: 0x00001FF6
- "\x1f\xf6\x03E\x00\x00\x1f\xf7" + // 0x1FF60345: 0x00001FF7
- "\x03\x9f\x03\x00\x00\x00\x1f\xf8" + // 0x039F0300: 0x00001FF8
- "\x03\xa9\x03\x00\x00\x00\x1f\xfa" + // 0x03A90300: 0x00001FFA
- "\x03\xa9\x03E\x00\x00\x1f\xfc" + // 0x03A90345: 0x00001FFC
- "!\x90\x038\x00\x00!\x9a" + // 0x21900338: 0x0000219A
- "!\x92\x038\x00\x00!\x9b" + // 0x21920338: 0x0000219B
- "!\x94\x038\x00\x00!\xae" + // 0x21940338: 0x000021AE
- "!\xd0\x038\x00\x00!\xcd" + // 0x21D00338: 0x000021CD
- "!\xd4\x038\x00\x00!\xce" + // 0x21D40338: 0x000021CE
- "!\xd2\x038\x00\x00!\xcf" + // 0x21D20338: 0x000021CF
- "\"\x03\x038\x00\x00\"\x04" + // 0x22030338: 0x00002204
- "\"\b\x038\x00\x00\"\t" + // 0x22080338: 0x00002209
- "\"\v\x038\x00\x00\"\f" + // 0x220B0338: 0x0000220C
- "\"#\x038\x00\x00\"$" + // 0x22230338: 0x00002224
- "\"%\x038\x00\x00\"&" + // 0x22250338: 0x00002226
- "\"<\x038\x00\x00\"A" + // 0x223C0338: 0x00002241
- "\"C\x038\x00\x00\"D" + // 0x22430338: 0x00002244
- "\"E\x038\x00\x00\"G" + // 0x22450338: 0x00002247
- "\"H\x038\x00\x00\"I" + // 0x22480338: 0x00002249
- "\x00=\x038\x00\x00\"`" + // 0x003D0338: 0x00002260
- "\"a\x038\x00\x00\"b" + // 0x22610338: 0x00002262
- "\"M\x038\x00\x00\"m" + // 0x224D0338: 0x0000226D
- "\x00<\x038\x00\x00\"n" + // 0x003C0338: 0x0000226E
- "\x00>\x038\x00\x00\"o" + // 0x003E0338: 0x0000226F
- "\"d\x038\x00\x00\"p" + // 0x22640338: 0x00002270
- "\"e\x038\x00\x00\"q" + // 0x22650338: 0x00002271
- "\"r\x038\x00\x00\"t" + // 0x22720338: 0x00002274
- "\"s\x038\x00\x00\"u" + // 0x22730338: 0x00002275
- "\"v\x038\x00\x00\"x" + // 0x22760338: 0x00002278
- "\"w\x038\x00\x00\"y" + // 0x22770338: 0x00002279
- "\"z\x038\x00\x00\"\x80" + // 0x227A0338: 0x00002280
- "\"{\x038\x00\x00\"\x81" + // 0x227B0338: 0x00002281
- "\"\x82\x038\x00\x00\"\x84" + // 0x22820338: 0x00002284
- "\"\x83\x038\x00\x00\"\x85" + // 0x22830338: 0x00002285
- "\"\x86\x038\x00\x00\"\x88" + // 0x22860338: 0x00002288
- "\"\x87\x038\x00\x00\"\x89" + // 0x22870338: 0x00002289
- "\"\xa2\x038\x00\x00\"\xac" + // 0x22A20338: 0x000022AC
- "\"\xa8\x038\x00\x00\"\xad" + // 0x22A80338: 0x000022AD
- "\"\xa9\x038\x00\x00\"\xae" + // 0x22A90338: 0x000022AE
- "\"\xab\x038\x00\x00\"\xaf" + // 0x22AB0338: 0x000022AF
- "\"|\x038\x00\x00\"\xe0" + // 0x227C0338: 0x000022E0
- "\"}\x038\x00\x00\"\xe1" + // 0x227D0338: 0x000022E1
- "\"\x91\x038\x00\x00\"\xe2" + // 0x22910338: 0x000022E2
- "\"\x92\x038\x00\x00\"\xe3" + // 0x22920338: 0x000022E3
- "\"\xb2\x038\x00\x00\"\xea" + // 0x22B20338: 0x000022EA
- "\"\xb3\x038\x00\x00\"\xeb" + // 0x22B30338: 0x000022EB
- "\"\xb4\x038\x00\x00\"\xec" + // 0x22B40338: 0x000022EC
- "\"\xb5\x038\x00\x00\"\xed" + // 0x22B50338: 0x000022ED
- "0K0\x99\x00\x000L" + // 0x304B3099: 0x0000304C
- "0M0\x99\x00\x000N" + // 0x304D3099: 0x0000304E
- "0O0\x99\x00\x000P" + // 0x304F3099: 0x00003050
- "0Q0\x99\x00\x000R" + // 0x30513099: 0x00003052
- "0S0\x99\x00\x000T" + // 0x30533099: 0x00003054
- "0U0\x99\x00\x000V" + // 0x30553099: 0x00003056
- "0W0\x99\x00\x000X" + // 0x30573099: 0x00003058
- "0Y0\x99\x00\x000Z" + // 0x30593099: 0x0000305A
- "0[0\x99\x00\x000\\" + // 0x305B3099: 0x0000305C
- "0]0\x99\x00\x000^" + // 0x305D3099: 0x0000305E
- "0_0\x99\x00\x000`" + // 0x305F3099: 0x00003060
- "0a0\x99\x00\x000b" + // 0x30613099: 0x00003062
- "0d0\x99\x00\x000e" + // 0x30643099: 0x00003065
- "0f0\x99\x00\x000g" + // 0x30663099: 0x00003067
- "0h0\x99\x00\x000i" + // 0x30683099: 0x00003069
- "0o0\x99\x00\x000p" + // 0x306F3099: 0x00003070
- "0o0\x9a\x00\x000q" + // 0x306F309A: 0x00003071
- "0r0\x99\x00\x000s" + // 0x30723099: 0x00003073
- "0r0\x9a\x00\x000t" + // 0x3072309A: 0x00003074
- "0u0\x99\x00\x000v" + // 0x30753099: 0x00003076
- "0u0\x9a\x00\x000w" + // 0x3075309A: 0x00003077
- "0x0\x99\x00\x000y" + // 0x30783099: 0x00003079
- "0x0\x9a\x00\x000z" + // 0x3078309A: 0x0000307A
- "0{0\x99\x00\x000|" + // 0x307B3099: 0x0000307C
- "0{0\x9a\x00\x000}" + // 0x307B309A: 0x0000307D
- "0F0\x99\x00\x000\x94" + // 0x30463099: 0x00003094
- "0\x9d0\x99\x00\x000\x9e" + // 0x309D3099: 0x0000309E
- "0\xab0\x99\x00\x000\xac" + // 0x30AB3099: 0x000030AC
- "0\xad0\x99\x00\x000\xae" + // 0x30AD3099: 0x000030AE
- "0\xaf0\x99\x00\x000\xb0" + // 0x30AF3099: 0x000030B0
- "0\xb10\x99\x00\x000\xb2" + // 0x30B13099: 0x000030B2
- "0\xb30\x99\x00\x000\xb4" + // 0x30B33099: 0x000030B4
- "0\xb50\x99\x00\x000\xb6" + // 0x30B53099: 0x000030B6
- "0\xb70\x99\x00\x000\xb8" + // 0x30B73099: 0x000030B8
- "0\xb90\x99\x00\x000\xba" + // 0x30B93099: 0x000030BA
- "0\xbb0\x99\x00\x000\xbc" + // 0x30BB3099: 0x000030BC
- "0\xbd0\x99\x00\x000\xbe" + // 0x30BD3099: 0x000030BE
- "0\xbf0\x99\x00\x000\xc0" + // 0x30BF3099: 0x000030C0
- "0\xc10\x99\x00\x000\xc2" + // 0x30C13099: 0x000030C2
- "0\xc40\x99\x00\x000\xc5" + // 0x30C43099: 0x000030C5
- "0\xc60\x99\x00\x000\xc7" + // 0x30C63099: 0x000030C7
- "0\xc80\x99\x00\x000\xc9" + // 0x30C83099: 0x000030C9
- "0\xcf0\x99\x00\x000\xd0" + // 0x30CF3099: 0x000030D0
- "0\xcf0\x9a\x00\x000\xd1" + // 0x30CF309A: 0x000030D1
- "0\xd20\x99\x00\x000\xd3" + // 0x30D23099: 0x000030D3
- "0\xd20\x9a\x00\x000\xd4" + // 0x30D2309A: 0x000030D4
- "0\xd50\x99\x00\x000\xd6" + // 0x30D53099: 0x000030D6
- "0\xd50\x9a\x00\x000\xd7" + // 0x30D5309A: 0x000030D7
- "0\xd80\x99\x00\x000\xd9" + // 0x30D83099: 0x000030D9
- "0\xd80\x9a\x00\x000\xda" + // 0x30D8309A: 0x000030DA
- "0\xdb0\x99\x00\x000\xdc" + // 0x30DB3099: 0x000030DC
- "0\xdb0\x9a\x00\x000\xdd" + // 0x30DB309A: 0x000030DD
- "0\xa60\x99\x00\x000\xf4" + // 0x30A63099: 0x000030F4
- "0\xef0\x99\x00\x000\xf7" + // 0x30EF3099: 0x000030F7
- "0\xf00\x99\x00\x000\xf8" + // 0x30F03099: 0x000030F8
- "0\xf10\x99\x00\x000\xf9" + // 0x30F13099: 0x000030F9
- "0\xf20\x99\x00\x000\xfa" + // 0x30F23099: 0x000030FA
- "0\xfd0\x99\x00\x000\xfe" + // 0x30FD3099: 0x000030FE
- "\x10\x99\x10\xba\x00\x01\x10\x9a" + // 0x109910BA: 0x0001109A
- "\x10\x9b\x10\xba\x00\x01\x10\x9c" + // 0x109B10BA: 0x0001109C
- "\x10\xa5\x10\xba\x00\x01\x10\xab" + // 0x10A510BA: 0x000110AB
- "\x111\x11'\x00\x01\x11." + // 0x11311127: 0x0001112E
- "\x112\x11'\x00\x01\x11/" + // 0x11321127: 0x0001112F
- "\x13G\x13>\x00\x01\x13K" + // 0x1347133E: 0x0001134B
- "\x13G\x13W\x00\x01\x13L" + // 0x13471357: 0x0001134C
- "\x14\xb9\x14\xba\x00\x01\x14\xbb" + // 0x14B914BA: 0x000114BB
- "\x14\xb9\x14\xb0\x00\x01\x14\xbc" + // 0x14B914B0: 0x000114BC
- "\x14\xb9\x14\xbd\x00\x01\x14\xbe" + // 0x14B914BD: 0x000114BE
- "\x15\xb8\x15\xaf\x00\x01\x15\xba" + // 0x15B815AF: 0x000115BA
- "\x15\xb9\x15\xaf\x00\x01\x15\xbb" + // 0x15B915AF: 0x000115BB
- "\x195\x190\x00\x01\x198" + // 0x19351930: 0x00011938
+ "\x00\x01\x04\x00`\x00\x00\xc0" + // 0x00041 0x00300: 0x000C0
+ "\x00\x01\x04\x00` \x00\xc1" + // 0x00041 0x00301: 0x000C1
+ "\x00\x01\x04\x00`@\x00\xc2" + // 0x00041 0x00302: 0x000C2
+ "\x00\x01\x04\x00``\x00\xc3" + // 0x00041 0x00303: 0x000C3
+ "\x00\x01\x04\x00a\x00\x00\xc4" + // 0x00041 0x00308: 0x000C4
+ "\x00\x01\x04\x00a@\x00\xc5" + // 0x00041 0x0030A: 0x000C5
+ "\x00\x01\f\x00d\xe0\x00\xc7" + // 0x00043 0x00327: 0x000C7
+ "\x00\x01\x14\x00`\x00\x00\xc8" + // 0x00045 0x00300: 0x000C8
+ "\x00\x01\x14\x00` \x00\xc9" + // 0x00045 0x00301: 0x000C9
+ "\x00\x01\x14\x00`@\x00\xca" + // 0x00045 0x00302: 0x000CA
+ "\x00\x01\x14\x00a\x00\x00\xcb" + // 0x00045 0x00308: 0x000CB
+ "\x00\x01$\x00`\x00\x00\xcc" + // 0x00049 0x00300: 0x000CC
+ "\x00\x01$\x00` \x00\xcd" + // 0x00049 0x00301: 0x000CD
+ "\x00\x01$\x00`@\x00\xce" + // 0x00049 0x00302: 0x000CE
+ "\x00\x01$\x00a\x00\x00\xcf" + // 0x00049 0x00308: 0x000CF
+ "\x00\x018\x00``\x00\xd1" + // 0x0004E 0x00303: 0x000D1
+ "\x00\x01<\x00`\x00\x00\xd2" + // 0x0004F 0x00300: 0x000D2
+ "\x00\x01<\x00` \x00\xd3" + // 0x0004F 0x00301: 0x000D3
+ "\x00\x01<\x00`@\x00\xd4" + // 0x0004F 0x00302: 0x000D4
+ "\x00\x01<\x00``\x00\xd5" + // 0x0004F 0x00303: 0x000D5
+ "\x00\x01<\x00a\x00\x00\xd6" + // 0x0004F 0x00308: 0x000D6
+ "\x00\x01T\x00`\x00\x00\xd9" + // 0x00055 0x00300: 0x000D9
+ "\x00\x01T\x00` \x00\xda" + // 0x00055 0x00301: 0x000DA
+ "\x00\x01T\x00`@\x00\xdb" + // 0x00055 0x00302: 0x000DB
+ "\x00\x01T\x00a\x00\x00\xdc" + // 0x00055 0x00308: 0x000DC
+ "\x00\x01d\x00` \x00\xdd" + // 0x00059 0x00301: 0x000DD
+ "\x00\x01\x84\x00`\x00\x00\xe0" + // 0x00061 0x00300: 0x000E0
+ "\x00\x01\x84\x00` \x00\xe1" + // 0x00061 0x00301: 0x000E1
+ "\x00\x01\x84\x00`@\x00\xe2" + // 0x00061 0x00302: 0x000E2
+ "\x00\x01\x84\x00``\x00\xe3" + // 0x00061 0x00303: 0x000E3
+ "\x00\x01\x84\x00a\x00\x00\xe4" + // 0x00061 0x00308: 0x000E4
+ "\x00\x01\x84\x00a@\x00\xe5" + // 0x00061 0x0030A: 0x000E5
+ "\x00\x01\x8c\x00d\xe0\x00\xe7" + // 0x00063 0x00327: 0x000E7
+ "\x00\x01\x94\x00`\x00\x00\xe8" + // 0x00065 0x00300: 0x000E8
+ "\x00\x01\x94\x00` \x00\xe9" + // 0x00065 0x00301: 0x000E9
+ "\x00\x01\x94\x00`@\x00\xea" + // 0x00065 0x00302: 0x000EA
+ "\x00\x01\x94\x00a\x00\x00\xeb" + // 0x00065 0x00308: 0x000EB
+ "\x00\x01\xa4\x00`\x00\x00\xec" + // 0x00069 0x00300: 0x000EC
+ "\x00\x01\xa4\x00` \x00\xed" + // 0x00069 0x00301: 0x000ED
+ "\x00\x01\xa4\x00`@\x00\xee" + // 0x00069 0x00302: 0x000EE
+ "\x00\x01\xa4\x00a\x00\x00\xef" + // 0x00069 0x00308: 0x000EF
+ "\x00\x01\xb8\x00``\x00\xf1" + // 0x0006E 0x00303: 0x000F1
+ "\x00\x01\xbc\x00`\x00\x00\xf2" + // 0x0006F 0x00300: 0x000F2
+ "\x00\x01\xbc\x00` \x00\xf3" + // 0x0006F 0x00301: 0x000F3
+ "\x00\x01\xbc\x00`@\x00\xf4" + // 0x0006F 0x00302: 0x000F4
+ "\x00\x01\xbc\x00``\x00\xf5" + // 0x0006F 0x00303: 0x000F5
+ "\x00\x01\xbc\x00a\x00\x00\xf6" + // 0x0006F 0x00308: 0x000F6
+ "\x00\x01\xd4\x00`\x00\x00\xf9" + // 0x00075 0x00300: 0x000F9
+ "\x00\x01\xd4\x00` \x00\xfa" + // 0x00075 0x00301: 0x000FA
+ "\x00\x01\xd4\x00`@\x00\xfb" + // 0x00075 0x00302: 0x000FB
+ "\x00\x01\xd4\x00a\x00\x00\xfc" + // 0x00075 0x00308: 0x000FC
+ "\x00\x01\xe4\x00` \x00\xfd" + // 0x00079 0x00301: 0x000FD
+ "\x00\x01\xe4\x00a\x00\x00\xff" + // 0x00079 0x00308: 0x000FF
+ "\x00\x01\x04\x00`\x80\x01\x00" + // 0x00041 0x00304: 0x00100
+ "\x00\x01\x84\x00`\x80\x01\x01" + // 0x00061 0x00304: 0x00101
+ "\x00\x01\x04\x00`\xc0\x01\x02" + // 0x00041 0x00306: 0x00102
+ "\x00\x01\x84\x00`\xc0\x01\x03" + // 0x00061 0x00306: 0x00103
+ "\x00\x01\x04\x00e\x00\x01\x04" + // 0x00041 0x00328: 0x00104
+ "\x00\x01\x84\x00e\x00\x01\x05" + // 0x00061 0x00328: 0x00105
+ "\x00\x01\f\x00` \x01\x06" + // 0x00043 0x00301: 0x00106
+ "\x00\x01\x8c\x00` \x01\a" + // 0x00063 0x00301: 0x00107
+ "\x00\x01\f\x00`@\x01\b" + // 0x00043 0x00302: 0x00108
+ "\x00\x01\x8c\x00`@\x01\t" + // 0x00063 0x00302: 0x00109
+ "\x00\x01\f\x00`\xe0\x01\n" + // 0x00043 0x00307: 0x0010A
+ "\x00\x01\x8c\x00`\xe0\x01\v" + // 0x00063 0x00307: 0x0010B
+ "\x00\x01\f\x00a\x80\x01\f" + // 0x00043 0x0030C: 0x0010C
+ "\x00\x01\x8c\x00a\x80\x01\r" + // 0x00063 0x0030C: 0x0010D
+ "\x00\x01\x10\x00a\x80\x01\x0e" + // 0x00044 0x0030C: 0x0010E
+ "\x00\x01\x90\x00a\x80\x01\x0f" + // 0x00064 0x0030C: 0x0010F
+ "\x00\x01\x14\x00`\x80\x01\x12" + // 0x00045 0x00304: 0x00112
+ "\x00\x01\x94\x00`\x80\x01\x13" + // 0x00065 0x00304: 0x00113
+ "\x00\x01\x14\x00`\xc0\x01\x14" + // 0x00045 0x00306: 0x00114
+ "\x00\x01\x94\x00`\xc0\x01\x15" + // 0x00065 0x00306: 0x00115
+ "\x00\x01\x14\x00`\xe0\x01\x16" + // 0x00045 0x00307: 0x00116
+ "\x00\x01\x94\x00`\xe0\x01\x17" + // 0x00065 0x00307: 0x00117
+ "\x00\x01\x14\x00e\x00\x01\x18" + // 0x00045 0x00328: 0x00118
+ "\x00\x01\x94\x00e\x00\x01\x19" + // 0x00065 0x00328: 0x00119
+ "\x00\x01\x14\x00a\x80\x01\x1a" + // 0x00045 0x0030C: 0x0011A
+ "\x00\x01\x94\x00a\x80\x01\x1b" + // 0x00065 0x0030C: 0x0011B
+ "\x00\x01\x1c\x00`@\x01\x1c" + // 0x00047 0x00302: 0x0011C
+ "\x00\x01\x9c\x00`@\x01\x1d" + // 0x00067 0x00302: 0x0011D
+ "\x00\x01\x1c\x00`\xc0\x01\x1e" + // 0x00047 0x00306: 0x0011E
+ "\x00\x01\x9c\x00`\xc0\x01\x1f" + // 0x00067 0x00306: 0x0011F
+ "\x00\x01\x1c\x00`\xe0\x01 " + // 0x00047 0x00307: 0x00120
+ "\x00\x01\x9c\x00`\xe0\x01!" + // 0x00067 0x00307: 0x00121
+ "\x00\x01\x1c\x00d\xe0\x01\"" + // 0x00047 0x00327: 0x00122
+ "\x00\x01\x9c\x00d\xe0\x01#" + // 0x00067 0x00327: 0x00123
+ "\x00\x01 \x00`@\x01$" + // 0x00048 0x00302: 0x00124
+ "\x00\x01\xa0\x00`@\x01%" + // 0x00068 0x00302: 0x00125
+ "\x00\x01$\x00``\x01(" + // 0x00049 0x00303: 0x00128
+ "\x00\x01\xa4\x00``\x01)" + // 0x00069 0x00303: 0x00129
+ "\x00\x01$\x00`\x80\x01*" + // 0x00049 0x00304: 0x0012A
+ "\x00\x01\xa4\x00`\x80\x01+" + // 0x00069 0x00304: 0x0012B
+ "\x00\x01$\x00`\xc0\x01," + // 0x00049 0x00306: 0x0012C
+ "\x00\x01\xa4\x00`\xc0\x01-" + // 0x00069 0x00306: 0x0012D
+ "\x00\x01$\x00e\x00\x01." + // 0x00049 0x00328: 0x0012E
+ "\x00\x01\xa4\x00e\x00\x01/" + // 0x00069 0x00328: 0x0012F
+ "\x00\x01$\x00`\xe0\x010" + // 0x00049 0x00307: 0x00130
+ "\x00\x01(\x00`@\x014" + // 0x0004A 0x00302: 0x00134
+ "\x00\x01\xa8\x00`@\x015" + // 0x0006A 0x00302: 0x00135
+ "\x00\x01,\x00d\xe0\x016" + // 0x0004B 0x00327: 0x00136
+ "\x00\x01\xac\x00d\xe0\x017" + // 0x0006B 0x00327: 0x00137
+ "\x00\x010\x00` \x019" + // 0x0004C 0x00301: 0x00139
+ "\x00\x01\xb0\x00` \x01:" + // 0x0006C 0x00301: 0x0013A
+ "\x00\x010\x00d\xe0\x01;" + // 0x0004C 0x00327: 0x0013B
+ "\x00\x01\xb0\x00d\xe0\x01<" + // 0x0006C 0x00327: 0x0013C
+ "\x00\x010\x00a\x80\x01=" + // 0x0004C 0x0030C: 0x0013D
+ "\x00\x01\xb0\x00a\x80\x01>" + // 0x0006C 0x0030C: 0x0013E
+ "\x00\x018\x00` \x01C" + // 0x0004E 0x00301: 0x00143
+ "\x00\x01\xb8\x00` \x01D" + // 0x0006E 0x00301: 0x00144
+ "\x00\x018\x00d\xe0\x01E" + // 0x0004E 0x00327: 0x00145
+ "\x00\x01\xb8\x00d\xe0\x01F" + // 0x0006E 0x00327: 0x00146
+ "\x00\x018\x00a\x80\x01G" + // 0x0004E 0x0030C: 0x00147
+ "\x00\x01\xb8\x00a\x80\x01H" + // 0x0006E 0x0030C: 0x00148
+ "\x00\x01<\x00`\x80\x01L" + // 0x0004F 0x00304: 0x0014C
+ "\x00\x01\xbc\x00`\x80\x01M" + // 0x0006F 0x00304: 0x0014D
+ "\x00\x01<\x00`\xc0\x01N" + // 0x0004F 0x00306: 0x0014E
+ "\x00\x01\xbc\x00`\xc0\x01O" + // 0x0006F 0x00306: 0x0014F
+ "\x00\x01<\x00a`\x01P" + // 0x0004F 0x0030B: 0x00150
+ "\x00\x01\xbc\x00a`\x01Q" + // 0x0006F 0x0030B: 0x00151
+ "\x00\x01H\x00` \x01T" + // 0x00052 0x00301: 0x00154
+ "\x00\x01\xc8\x00` \x01U" + // 0x00072 0x00301: 0x00155
+ "\x00\x01H\x00d\xe0\x01V" + // 0x00052 0x00327: 0x00156
+ "\x00\x01\xc8\x00d\xe0\x01W" + // 0x00072 0x00327: 0x00157
+ "\x00\x01H\x00a\x80\x01X" + // 0x00052 0x0030C: 0x00158
+ "\x00\x01\xc8\x00a\x80\x01Y" + // 0x00072 0x0030C: 0x00159
+ "\x00\x01L\x00` \x01Z" + // 0x00053 0x00301: 0x0015A
+ "\x00\x01\xcc\x00` \x01[" + // 0x00073 0x00301: 0x0015B
+ "\x00\x01L\x00`@\x01\\" + // 0x00053 0x00302: 0x0015C
+ "\x00\x01\xcc\x00`@\x01]" + // 0x00073 0x00302: 0x0015D
+ "\x00\x01L\x00d\xe0\x01^" + // 0x00053 0x00327: 0x0015E
+ "\x00\x01\xcc\x00d\xe0\x01_" + // 0x00073 0x00327: 0x0015F
+ "\x00\x01L\x00a\x80\x01`" + // 0x00053 0x0030C: 0x00160
+ "\x00\x01\xcc\x00a\x80\x01a" + // 0x00073 0x0030C: 0x00161
+ "\x00\x01P\x00d\xe0\x01b" + // 0x00054 0x00327: 0x00162
+ "\x00\x01\xd0\x00d\xe0\x01c" + // 0x00074 0x00327: 0x00163
+ "\x00\x01P\x00a\x80\x01d" + // 0x00054 0x0030C: 0x00164
+ "\x00\x01\xd0\x00a\x80\x01e" + // 0x00074 0x0030C: 0x00165
+ "\x00\x01T\x00``\x01h" + // 0x00055 0x00303: 0x00168
+ "\x00\x01\xd4\x00``\x01i" + // 0x00075 0x00303: 0x00169
+ "\x00\x01T\x00`\x80\x01j" + // 0x00055 0x00304: 0x0016A
+ "\x00\x01\xd4\x00`\x80\x01k" + // 0x00075 0x00304: 0x0016B
+ "\x00\x01T\x00`\xc0\x01l" + // 0x00055 0x00306: 0x0016C
+ "\x00\x01\xd4\x00`\xc0\x01m" + // 0x00075 0x00306: 0x0016D
+ "\x00\x01T\x00a@\x01n" + // 0x00055 0x0030A: 0x0016E
+ "\x00\x01\xd4\x00a@\x01o" + // 0x00075 0x0030A: 0x0016F
+ "\x00\x01T\x00a`\x01p" + // 0x00055 0x0030B: 0x00170
+ "\x00\x01\xd4\x00a`\x01q" + // 0x00075 0x0030B: 0x00171
+ "\x00\x01T\x00e\x00\x01r" + // 0x00055 0x00328: 0x00172
+ "\x00\x01\xd4\x00e\x00\x01s" + // 0x00075 0x00328: 0x00173
+ "\x00\x01\\\x00`@\x01t" + // 0x00057 0x00302: 0x00174
+ "\x00\x01\xdc\x00`@\x01u" + // 0x00077 0x00302: 0x00175
+ "\x00\x01d\x00`@\x01v" + // 0x00059 0x00302: 0x00176
+ "\x00\x01\xe4\x00`@\x01w" + // 0x00079 0x00302: 0x00177
+ "\x00\x01d\x00a\x00\x01x" + // 0x00059 0x00308: 0x00178
+ "\x00\x01h\x00` \x01y" + // 0x0005A 0x00301: 0x00179
+ "\x00\x01\xe8\x00` \x01z" + // 0x0007A 0x00301: 0x0017A
+ "\x00\x01h\x00`\xe0\x01{" + // 0x0005A 0x00307: 0x0017B
+ "\x00\x01\xe8\x00`\xe0\x01|" + // 0x0007A 0x00307: 0x0017C
+ "\x00\x01h\x00a\x80\x01}" + // 0x0005A 0x0030C: 0x0017D
+ "\x00\x01\xe8\x00a\x80\x01~" + // 0x0007A 0x0030C: 0x0017E
+ "\x00\x01<\x00c`\x01\xa0" + // 0x0004F 0x0031B: 0x001A0
+ "\x00\x01\xbc\x00c`\x01\xa1" + // 0x0006F 0x0031B: 0x001A1
+ "\x00\x01T\x00c`\x01\xaf" + // 0x00055 0x0031B: 0x001AF
+ "\x00\x01\xd4\x00c`\x01\xb0" + // 0x00075 0x0031B: 0x001B0
+ "\x00\x01\x04\x00a\x80\x01\xcd" + // 0x00041 0x0030C: 0x001CD
+ "\x00\x01\x84\x00a\x80\x01\xce" + // 0x00061 0x0030C: 0x001CE
+ "\x00\x01$\x00a\x80\x01\xcf" + // 0x00049 0x0030C: 0x001CF
+ "\x00\x01\xa4\x00a\x80\x01\xd0" + // 0x00069 0x0030C: 0x001D0
+ "\x00\x01<\x00a\x80\x01\xd1" + // 0x0004F 0x0030C: 0x001D1
+ "\x00\x01\xbc\x00a\x80\x01\xd2" + // 0x0006F 0x0030C: 0x001D2
+ "\x00\x01T\x00a\x80\x01\xd3" + // 0x00055 0x0030C: 0x001D3
+ "\x00\x01\xd4\x00a\x80\x01\xd4" + // 0x00075 0x0030C: 0x001D4
+ "\x00\x03p\x00`\x80\x01\xd5" + // 0x000DC 0x00304: 0x001D5
+ "\x00\x03\xf0\x00`\x80\x01\xd6" + // 0x000FC 0x00304: 0x001D6
+ "\x00\x03p\x00` \x01\xd7" + // 0x000DC 0x00301: 0x001D7
+ "\x00\x03\xf0\x00` \x01\xd8" + // 0x000FC 0x00301: 0x001D8
+ "\x00\x03p\x00a\x80\x01\xd9" + // 0x000DC 0x0030C: 0x001D9
+ "\x00\x03\xf0\x00a\x80\x01\xda" + // 0x000FC 0x0030C: 0x001DA
+ "\x00\x03p\x00`\x00\x01\xdb" + // 0x000DC 0x00300: 0x001DB
+ "\x00\x03\xf0\x00`\x00\x01\xdc" + // 0x000FC 0x00300: 0x001DC
+ "\x00\x03\x10\x00`\x80\x01\xde" + // 0x000C4 0x00304: 0x001DE
+ "\x00\x03\x90\x00`\x80\x01\xdf" + // 0x000E4 0x00304: 0x001DF
+ "\x00\b\x98\x00`\x80\x01\xe0" + // 0x00226 0x00304: 0x001E0
+ "\x00\b\x9c\x00`\x80\x01\xe1" + // 0x00227 0x00304: 0x001E1
+ "\x00\x03\x18\x00`\x80\x01\xe2" + // 0x000C6 0x00304: 0x001E2
+ "\x00\x03\x98\x00`\x80\x01\xe3" + // 0x000E6 0x00304: 0x001E3
+ "\x00\x01\x1c\x00a\x80\x01\xe6" + // 0x00047 0x0030C: 0x001E6
+ "\x00\x01\x9c\x00a\x80\x01\xe7" + // 0x00067 0x0030C: 0x001E7
+ "\x00\x01,\x00a\x80\x01\xe8" + // 0x0004B 0x0030C: 0x001E8
+ "\x00\x01\xac\x00a\x80\x01\xe9" + // 0x0006B 0x0030C: 0x001E9
+ "\x00\x01<\x00e\x00\x01\xea" + // 0x0004F 0x00328: 0x001EA
+ "\x00\x01\xbc\x00e\x00\x01\xeb" + // 0x0006F 0x00328: 0x001EB
+ "\x00\a\xa8\x00`\x80\x01\xec" + // 0x001EA 0x00304: 0x001EC
+ "\x00\a\xac\x00`\x80\x01\xed" + // 0x001EB 0x00304: 0x001ED
+ "\x00\x06\xdc\x00a\x80\x01\xee" + // 0x001B7 0x0030C: 0x001EE
+ "\x00\nH\x00a\x80\x01\xef" + // 0x00292 0x0030C: 0x001EF
+ "\x00\x01\xa8\x00a\x80\x01\xf0" + // 0x0006A 0x0030C: 0x001F0
+ "\x00\x01\x1c\x00` \x01\xf4" + // 0x00047 0x00301: 0x001F4
+ "\x00\x01\x9c\x00` \x01\xf5" + // 0x00067 0x00301: 0x001F5
+ "\x00\x018\x00`\x00\x01\xf8" + // 0x0004E 0x00300: 0x001F8
+ "\x00\x01\xb8\x00`\x00\x01\xf9" + // 0x0006E 0x00300: 0x001F9
+ "\x00\x03\x14\x00` \x01\xfa" + // 0x000C5 0x00301: 0x001FA
+ "\x00\x03\x94\x00` \x01\xfb" + // 0x000E5 0x00301: 0x001FB
+ "\x00\x03\x18\x00` \x01\xfc" + // 0x000C6 0x00301: 0x001FC
+ "\x00\x03\x98\x00` \x01\xfd" + // 0x000E6 0x00301: 0x001FD
+ "\x00\x03`\x00` \x01\xfe" + // 0x000D8 0x00301: 0x001FE
+ "\x00\x03\xe0\x00` \x01\xff" + // 0x000F8 0x00301: 0x001FF
+ "\x00\x01\x04\x00a\xe0\x02\x00" + // 0x00041 0x0030F: 0x00200
+ "\x00\x01\x84\x00a\xe0\x02\x01" + // 0x00061 0x0030F: 0x00201
+ "\x00\x01\x04\x00b \x02\x02" + // 0x00041 0x00311: 0x00202
+ "\x00\x01\x84\x00b \x02\x03" + // 0x00061 0x00311: 0x00203
+ "\x00\x01\x14\x00a\xe0\x02\x04" + // 0x00045 0x0030F: 0x00204
+ "\x00\x01\x94\x00a\xe0\x02\x05" + // 0x00065 0x0030F: 0x00205
+ "\x00\x01\x14\x00b \x02\x06" + // 0x00045 0x00311: 0x00206
+ "\x00\x01\x94\x00b \x02\a" + // 0x00065 0x00311: 0x00207
+ "\x00\x01$\x00a\xe0\x02\b" + // 0x00049 0x0030F: 0x00208
+ "\x00\x01\xa4\x00a\xe0\x02\t" + // 0x00069 0x0030F: 0x00209
+ "\x00\x01$\x00b \x02\n" + // 0x00049 0x00311: 0x0020A
+ "\x00\x01\xa4\x00b \x02\v" + // 0x00069 0x00311: 0x0020B
+ "\x00\x01<\x00a\xe0\x02\f" + // 0x0004F 0x0030F: 0x0020C
+ "\x00\x01\xbc\x00a\xe0\x02\r" + // 0x0006F 0x0030F: 0x0020D
+ "\x00\x01<\x00b \x02\x0e" + // 0x0004F 0x00311: 0x0020E
+ "\x00\x01\xbc\x00b \x02\x0f" + // 0x0006F 0x00311: 0x0020F
+ "\x00\x01H\x00a\xe0\x02\x10" + // 0x00052 0x0030F: 0x00210
+ "\x00\x01\xc8\x00a\xe0\x02\x11" + // 0x00072 0x0030F: 0x00211
+ "\x00\x01H\x00b \x02\x12" + // 0x00052 0x00311: 0x00212
+ "\x00\x01\xc8\x00b \x02\x13" + // 0x00072 0x00311: 0x00213
+ "\x00\x01T\x00a\xe0\x02\x14" + // 0x00055 0x0030F: 0x00214
+ "\x00\x01\xd4\x00a\xe0\x02\x15" + // 0x00075 0x0030F: 0x00215
+ "\x00\x01T\x00b \x02\x16" + // 0x00055 0x00311: 0x00216
+ "\x00\x01\xd4\x00b \x02\x17" + // 0x00075 0x00311: 0x00217
+ "\x00\x01L\x00d\xc0\x02\x18" + // 0x00053 0x00326: 0x00218
+ "\x00\x01\xcc\x00d\xc0\x02\x19" + // 0x00073 0x00326: 0x00219
+ "\x00\x01P\x00d\xc0\x02\x1a" + // 0x00054 0x00326: 0x0021A
+ "\x00\x01\xd0\x00d\xc0\x02\x1b" + // 0x00074 0x00326: 0x0021B
+ "\x00\x01 \x00a\x80\x02\x1e" + // 0x00048 0x0030C: 0x0021E
+ "\x00\x01\xa0\x00a\x80\x02\x1f" + // 0x00068 0x0030C: 0x0021F
+ "\x00\x01\x04\x00`\xe0\x02&" + // 0x00041 0x00307: 0x00226
+ "\x00\x01\x84\x00`\xe0\x02'" + // 0x00061 0x00307: 0x00227
+ "\x00\x01\x14\x00d\xe0\x02(" + // 0x00045 0x00327: 0x00228
+ "\x00\x01\x94\x00d\xe0\x02)" + // 0x00065 0x00327: 0x00229
+ "\x00\x03X\x00`\x80\x02*" + // 0x000D6 0x00304: 0x0022A
+ "\x00\x03\xd8\x00`\x80\x02+" + // 0x000F6 0x00304: 0x0022B
+ "\x00\x03T\x00`\x80\x02," + // 0x000D5 0x00304: 0x0022C
+ "\x00\x03\xd4\x00`\x80\x02-" + // 0x000F5 0x00304: 0x0022D
+ "\x00\x01<\x00`\xe0\x02." + // 0x0004F 0x00307: 0x0022E
+ "\x00\x01\xbc\x00`\xe0\x02/" + // 0x0006F 0x00307: 0x0022F
+ "\x00\b\xb8\x00`\x80\x020" + // 0x0022E 0x00304: 0x00230
+ "\x00\b\xbc\x00`\x80\x021" + // 0x0022F 0x00304: 0x00231
+ "\x00\x01d\x00`\x80\x022" + // 0x00059 0x00304: 0x00232
+ "\x00\x01\xe4\x00`\x80\x023" + // 0x00079 0x00304: 0x00233
+ "\x00\x02\xa0\x00` \x03\x85" + // 0x000A8 0x00301: 0x00385
+ "\x00\x0eD\x00` \x03\x86" + // 0x00391 0x00301: 0x00386
+ "\x00\x0eT\x00` \x03\x88" + // 0x00395 0x00301: 0x00388
+ "\x00\x0e\\\x00` \x03\x89" + // 0x00397 0x00301: 0x00389
+ "\x00\x0ed\x00` \x03\x8a" + // 0x00399 0x00301: 0x0038A
+ "\x00\x0e|\x00` \x03\x8c" + // 0x0039F 0x00301: 0x0038C
+ "\x00\x0e\x94\x00` \x03\x8e" + // 0x003A5 0x00301: 0x0038E
+ "\x00\x0e\xa4\x00` \x03\x8f" + // 0x003A9 0x00301: 0x0038F
+ "\x00\x0f(\x00` \x03\x90" + // 0x003CA 0x00301: 0x00390
+ "\x00\x0ed\x00a\x00\x03\xaa" + // 0x00399 0x00308: 0x003AA
+ "\x00\x0e\x94\x00a\x00\x03\xab" + // 0x003A5 0x00308: 0x003AB
+ "\x00\x0e\xc4\x00` \x03\xac" + // 0x003B1 0x00301: 0x003AC
+ "\x00\x0e\xd4\x00` \x03\xad" + // 0x003B5 0x00301: 0x003AD
+ "\x00\x0e\xdc\x00` \x03\xae" + // 0x003B7 0x00301: 0x003AE
+ "\x00\x0e\xe4\x00` \x03\xaf" + // 0x003B9 0x00301: 0x003AF
+ "\x00\x0f,\x00` \x03\xb0" + // 0x003CB 0x00301: 0x003B0
+ "\x00\x0e\xe4\x00a\x00\x03\xca" + // 0x003B9 0x00308: 0x003CA
+ "\x00\x0f\x14\x00a\x00\x03\xcb" + // 0x003C5 0x00308: 0x003CB
+ "\x00\x0e\xfc\x00` \x03\xcc" + // 0x003BF 0x00301: 0x003CC
+ "\x00\x0f\x14\x00` \x03\xcd" + // 0x003C5 0x00301: 0x003CD
+ "\x00\x0f$\x00` \x03\xce" + // 0x003C9 0x00301: 0x003CE
+ "\x00\x0fH\x00` \x03\xd3" + // 0x003D2 0x00301: 0x003D3
+ "\x00\x0fH\x00a\x00\x03\xd4" + // 0x003D2 0x00308: 0x003D4
+ "\x00\x10T\x00`\x00\x04\x00" + // 0x00415 0x00300: 0x00400
+ "\x00\x10T\x00a\x00\x04\x01" + // 0x00415 0x00308: 0x00401
+ "\x00\x10L\x00` \x04\x03" + // 0x00413 0x00301: 0x00403
+ "\x00\x10\x18\x00a\x00\x04\a" + // 0x00406 0x00308: 0x00407
+ "\x00\x10h\x00` \x04\f" + // 0x0041A 0x00301: 0x0040C
+ "\x00\x10`\x00`\x00\x04\r" + // 0x00418 0x00300: 0x0040D
+ "\x00\x10\x8c\x00`\xc0\x04\x0e" + // 0x00423 0x00306: 0x0040E
+ "\x00\x10`\x00`\xc0\x04\x19" + // 0x00418 0x00306: 0x00419
+ "\x00\x10\xe0\x00`\xc0\x049" + // 0x00438 0x00306: 0x00439
+ "\x00\x10\xd4\x00`\x00\x04P" + // 0x00435 0x00300: 0x00450
+ "\x00\x10\xd4\x00a\x00\x04Q" + // 0x00435 0x00308: 0x00451
+ "\x00\x10\xcc\x00` \x04S" + // 0x00433 0x00301: 0x00453
+ "\x00\x11X\x00a\x00\x04W" + // 0x00456 0x00308: 0x00457
+ "\x00\x10\xe8\x00` \x04\\" + // 0x0043A 0x00301: 0x0045C
+ "\x00\x10\xe0\x00`\x00\x04]" + // 0x00438 0x00300: 0x0045D
+ "\x00\x11\f\x00`\xc0\x04^" + // 0x00443 0x00306: 0x0045E
+ "\x00\x11\xd0\x00a\xe0\x04v" + // 0x00474 0x0030F: 0x00476
+ "\x00\x11\xd4\x00a\xe0\x04w" + // 0x00475 0x0030F: 0x00477
+ "\x00\x10X\x00`\xc0\x04\xc1" + // 0x00416 0x00306: 0x004C1
+ "\x00\x10\xd8\x00`\xc0\x04\xc2" + // 0x00436 0x00306: 0x004C2
+ "\x00\x10@\x00`\xc0\x04\xd0" + // 0x00410 0x00306: 0x004D0
+ "\x00\x10\xc0\x00`\xc0\x04\xd1" + // 0x00430 0x00306: 0x004D1
+ "\x00\x10@\x00a\x00\x04\xd2" + // 0x00410 0x00308: 0x004D2
+ "\x00\x10\xc0\x00a\x00\x04\xd3" + // 0x00430 0x00308: 0x004D3
+ "\x00\x10T\x00`\xc0\x04\xd6" + // 0x00415 0x00306: 0x004D6
+ "\x00\x10\xd4\x00`\xc0\x04\xd7" + // 0x00435 0x00306: 0x004D7
+ "\x00\x13`\x00a\x00\x04\xda" + // 0x004D8 0x00308: 0x004DA
+ "\x00\x13d\x00a\x00\x04\xdb" + // 0x004D9 0x00308: 0x004DB
+ "\x00\x10X\x00a\x00\x04\xdc" + // 0x00416 0x00308: 0x004DC
+ "\x00\x10\xd8\x00a\x00\x04\xdd" + // 0x00436 0x00308: 0x004DD
+ "\x00\x10\\\x00a\x00\x04\xde" + // 0x00417 0x00308: 0x004DE
+ "\x00\x10\xdc\x00a\x00\x04\xdf" + // 0x00437 0x00308: 0x004DF
+ "\x00\x10`\x00`\x80\x04\xe2" + // 0x00418 0x00304: 0x004E2
+ "\x00\x10\xe0\x00`\x80\x04\xe3" + // 0x00438 0x00304: 0x004E3
+ "\x00\x10`\x00a\x00\x04\xe4" + // 0x00418 0x00308: 0x004E4
+ "\x00\x10\xe0\x00a\x00\x04\xe5" + // 0x00438 0x00308: 0x004E5
+ "\x00\x10x\x00a\x00\x04\xe6" + // 0x0041E 0x00308: 0x004E6
+ "\x00\x10\xf8\x00a\x00\x04\xe7" + // 0x0043E 0x00308: 0x004E7
+ "\x00\x13\xa0\x00a\x00\x04\xea" + // 0x004E8 0x00308: 0x004EA
+ "\x00\x13\xa4\x00a\x00\x04\xeb" + // 0x004E9 0x00308: 0x004EB
+ "\x00\x10\xb4\x00a\x00\x04\xec" + // 0x0042D 0x00308: 0x004EC
+ "\x00\x114\x00a\x00\x04\xed" + // 0x0044D 0x00308: 0x004ED
+ "\x00\x10\x8c\x00`\x80\x04\xee" + // 0x00423 0x00304: 0x004EE
+ "\x00\x11\f\x00`\x80\x04\xef" + // 0x00443 0x00304: 0x004EF
+ "\x00\x10\x8c\x00a\x00\x04\xf0" + // 0x00423 0x00308: 0x004F0
+ "\x00\x11\f\x00a\x00\x04\xf1" + // 0x00443 0x00308: 0x004F1
+ "\x00\x10\x8c\x00a`\x04\xf2" + // 0x00423 0x0030B: 0x004F2
+ "\x00\x11\f\x00a`\x04\xf3" + // 0x00443 0x0030B: 0x004F3
+ "\x00\x10\x9c\x00a\x00\x04\xf4" + // 0x00427 0x00308: 0x004F4
+ "\x00\x11\x1c\x00a\x00\x04\xf5" + // 0x00447 0x00308: 0x004F5
+ "\x00\x10\xac\x00a\x00\x04\xf8" + // 0x0042B 0x00308: 0x004F8
+ "\x00\x11,\x00a\x00\x04\xf9" + // 0x0044B 0x00308: 0x004F9
+ "\x00\x18\x9c\x00\xca`\x06\"" + // 0x00627 0x00653: 0x00622
+ "\x00\x18\x9c\x00ʀ\x06#" + // 0x00627 0x00654: 0x00623
+ "\x00\x19 \x00ʀ\x06$" + // 0x00648 0x00654: 0x00624
+ "\x00\x18\x9c\x00ʠ\x06%" + // 0x00627 0x00655: 0x00625
+ "\x00\x19(\x00ʀ\x06&" + // 0x0064A 0x00654: 0x00626
+ "\x00\x1bT\x00ʀ\x06\xc0" + // 0x006D5 0x00654: 0x006C0
+ "\x00\x1b\x04\x00ʀ\x06\xc2" + // 0x006C1 0x00654: 0x006C2
+ "\x00\x1bH\x00ʀ\x06\xd3" + // 0x006D2 0x00654: 0x006D3
+ "\x00$\xa0\x01'\x80\t)" + // 0x00928 0x0093C: 0x00929
+ "\x00$\xc0\x01'\x80\t1" + // 0x00930 0x0093C: 0x00931
+ "\x00$\xcc\x01'\x80\t4" + // 0x00933 0x0093C: 0x00934
+ "\x00'\x1c\x017\xc0\t\xcb" + // 0x009C7 0x009BE: 0x009CB
+ "\x00'\x1c\x01:\xe0\t\xcc" + // 0x009C7 0x009D7: 0x009CC
+ "\x00-\x1c\x01j\xc0\vH" + // 0x00B47 0x00B56: 0x00B48
+ "\x00-\x1c\x01g\xc0\vK" + // 0x00B47 0x00B3E: 0x00B4B
+ "\x00-\x1c\x01j\xe0\vL" + // 0x00B47 0x00B57: 0x00B4C
+ "\x00.H\x01z\xe0\v\x94" + // 0x00B92 0x00BD7: 0x00B94
+ "\x00/\x18\x01w\xc0\v\xca" + // 0x00BC6 0x00BBE: 0x00BCA
+ "\x00/\x1c\x01w\xc0\v\xcb" + // 0x00BC7 0x00BBE: 0x00BCB
+ "\x00/\x18\x01z\xe0\v\xcc" + // 0x00BC6 0x00BD7: 0x00BCC
+ "\x001\x18\x01\x8a\xc0\fH" + // 0x00C46 0x00C56: 0x00C48
+ "\x002\xfc\x01\x9a\xa0\f\xc0" + // 0x00CBF 0x00CD5: 0x00CC0
+ "\x003\x18\x01\x9a\xa0\f\xc7" + // 0x00CC6 0x00CD5: 0x00CC7
+ "\x003\x18\x01\x9a\xc0\f\xc8" + // 0x00CC6 0x00CD6: 0x00CC8
+ "\x003\x18\x01\x98@\f\xca" + // 0x00CC6 0x00CC2: 0x00CCA
+ "\x003(\x01\x9a\xa0\f\xcb" + // 0x00CCA 0x00CD5: 0x00CCB
+ "\x005\x18\x01\xa7\xc0\rJ" + // 0x00D46 0x00D3E: 0x00D4A
+ "\x005\x1c\x01\xa7\xc0\rK" + // 0x00D47 0x00D3E: 0x00D4B
+ "\x005\x18\x01\xaa\xe0\rL" + // 0x00D46 0x00D57: 0x00D4C
+ "\x007d\x01\xb9@\r\xda" + // 0x00DD9 0x00DCA: 0x00DDA
+ "\x007d\x01\xb9\xe0\r\xdc" + // 0x00DD9 0x00DCF: 0x00DDC
+ "\x007p\x01\xb9@\r\xdd" + // 0x00DDC 0x00DCA: 0x00DDD
+ "\x007d\x01\xbb\xe0\r\xde" + // 0x00DD9 0x00DDF: 0x00DDE
+ "\x00@\x94\x02\x05\xc0\x10&" + // 0x01025 0x0102E: 0x01026
+ "\x00l\x14\x03f\xa0\x1b\x06" + // 0x01B05 0x01B35: 0x01B06
+ "\x00l\x1c\x03f\xa0\x1b\b" + // 0x01B07 0x01B35: 0x01B08
+ "\x00l$\x03f\xa0\x1b\n" + // 0x01B09 0x01B35: 0x01B0A
+ "\x00l,\x03f\xa0\x1b\f" + // 0x01B0B 0x01B35: 0x01B0C
+ "\x00l4\x03f\xa0\x1b\x0e" + // 0x01B0D 0x01B35: 0x01B0E
+ "\x00lD\x03f\xa0\x1b\x12" + // 0x01B11 0x01B35: 0x01B12
+ "\x00l\xe8\x03f\xa0\x1b;" + // 0x01B3A 0x01B35: 0x01B3B
+ "\x00l\xf0\x03f\xa0\x1b=" + // 0x01B3C 0x01B35: 0x01B3D
+ "\x00l\xf8\x03f\xa0\x1b@" + // 0x01B3E 0x01B35: 0x01B40
+ "\x00l\xfc\x03f\xa0\x1bA" + // 0x01B3F 0x01B35: 0x01B41
+ "\x00m\b\x03f\xa0\x1bC" + // 0x01B42 0x01B35: 0x01B43
+ "\x00\x01\x04\x00d\xa0\x1e\x00" + // 0x00041 0x00325: 0x01E00
+ "\x00\x01\x84\x00d\xa0\x1e\x01" + // 0x00061 0x00325: 0x01E01
+ "\x00\x01\b\x00`\xe0\x1e\x02" + // 0x00042 0x00307: 0x01E02
+ "\x00\x01\x88\x00`\xe0\x1e\x03" + // 0x00062 0x00307: 0x01E03
+ "\x00\x01\b\x00d`\x1e\x04" + // 0x00042 0x00323: 0x01E04
+ "\x00\x01\x88\x00d`\x1e\x05" + // 0x00062 0x00323: 0x01E05
+ "\x00\x01\b\x00f \x1e\x06" + // 0x00042 0x00331: 0x01E06
+ "\x00\x01\x88\x00f \x1e\a" + // 0x00062 0x00331: 0x01E07
+ "\x00\x03\x1c\x00` \x1e\b" + // 0x000C7 0x00301: 0x01E08
+ "\x00\x03\x9c\x00` \x1e\t" + // 0x000E7 0x00301: 0x01E09
+ "\x00\x01\x10\x00`\xe0\x1e\n" + // 0x00044 0x00307: 0x01E0A
+ "\x00\x01\x90\x00`\xe0\x1e\v" + // 0x00064 0x00307: 0x01E0B
+ "\x00\x01\x10\x00d`\x1e\f" + // 0x00044 0x00323: 0x01E0C
+ "\x00\x01\x90\x00d`\x1e\r" + // 0x00064 0x00323: 0x01E0D
+ "\x00\x01\x10\x00f \x1e\x0e" + // 0x00044 0x00331: 0x01E0E
+ "\x00\x01\x90\x00f \x1e\x0f" + // 0x00064 0x00331: 0x01E0F
+ "\x00\x01\x10\x00d\xe0\x1e\x10" + // 0x00044 0x00327: 0x01E10
+ "\x00\x01\x90\x00d\xe0\x1e\x11" + // 0x00064 0x00327: 0x01E11
+ "\x00\x01\x10\x00e\xa0\x1e\x12" + // 0x00044 0x0032D: 0x01E12
+ "\x00\x01\x90\x00e\xa0\x1e\x13" + // 0x00064 0x0032D: 0x01E13
+ "\x00\x04H\x00`\x00\x1e\x14" + // 0x00112 0x00300: 0x01E14
+ "\x00\x04L\x00`\x00\x1e\x15" + // 0x00113 0x00300: 0x01E15
+ "\x00\x04H\x00` \x1e\x16" + // 0x00112 0x00301: 0x01E16
+ "\x00\x04L\x00` \x1e\x17" + // 0x00113 0x00301: 0x01E17
+ "\x00\x01\x14\x00e\xa0\x1e\x18" + // 0x00045 0x0032D: 0x01E18
+ "\x00\x01\x94\x00e\xa0\x1e\x19" + // 0x00065 0x0032D: 0x01E19
+ "\x00\x01\x14\x00f\x00\x1e\x1a" + // 0x00045 0x00330: 0x01E1A
+ "\x00\x01\x94\x00f\x00\x1e\x1b" + // 0x00065 0x00330: 0x01E1B
+ "\x00\b\xa0\x00`\xc0\x1e\x1c" + // 0x00228 0x00306: 0x01E1C
+ "\x00\b\xa4\x00`\xc0\x1e\x1d" + // 0x00229 0x00306: 0x01E1D
+ "\x00\x01\x18\x00`\xe0\x1e\x1e" + // 0x00046 0x00307: 0x01E1E
+ "\x00\x01\x98\x00`\xe0\x1e\x1f" + // 0x00066 0x00307: 0x01E1F
+ "\x00\x01\x1c\x00`\x80\x1e " + // 0x00047 0x00304: 0x01E20
+ "\x00\x01\x9c\x00`\x80\x1e!" + // 0x00067 0x00304: 0x01E21
+ "\x00\x01 \x00`\xe0\x1e\"" + // 0x00048 0x00307: 0x01E22
+ "\x00\x01\xa0\x00`\xe0\x1e#" + // 0x00068 0x00307: 0x01E23
+ "\x00\x01 \x00d`\x1e$" + // 0x00048 0x00323: 0x01E24
+ "\x00\x01\xa0\x00d`\x1e%" + // 0x00068 0x00323: 0x01E25
+ "\x00\x01 \x00a\x00\x1e&" + // 0x00048 0x00308: 0x01E26
+ "\x00\x01\xa0\x00a\x00\x1e'" + // 0x00068 0x00308: 0x01E27
+ "\x00\x01 \x00d\xe0\x1e(" + // 0x00048 0x00327: 0x01E28
+ "\x00\x01\xa0\x00d\xe0\x1e)" + // 0x00068 0x00327: 0x01E29
+ "\x00\x01 \x00e\xc0\x1e*" + // 0x00048 0x0032E: 0x01E2A
+ "\x00\x01\xa0\x00e\xc0\x1e+" + // 0x00068 0x0032E: 0x01E2B
+ "\x00\x01$\x00f\x00\x1e," + // 0x00049 0x00330: 0x01E2C
+ "\x00\x01\xa4\x00f\x00\x1e-" + // 0x00069 0x00330: 0x01E2D
+ "\x00\x03<\x00` \x1e." + // 0x000CF 0x00301: 0x01E2E
+ "\x00\x03\xbc\x00` \x1e/" + // 0x000EF 0x00301: 0x01E2F
+ "\x00\x01,\x00` \x1e0" + // 0x0004B 0x00301: 0x01E30
+ "\x00\x01\xac\x00` \x1e1" + // 0x0006B 0x00301: 0x01E31
+ "\x00\x01,\x00d`\x1e2" + // 0x0004B 0x00323: 0x01E32
+ "\x00\x01\xac\x00d`\x1e3" + // 0x0006B 0x00323: 0x01E33
+ "\x00\x01,\x00f \x1e4" + // 0x0004B 0x00331: 0x01E34
+ "\x00\x01\xac\x00f \x1e5" + // 0x0006B 0x00331: 0x01E35
+ "\x00\x010\x00d`\x1e6" + // 0x0004C 0x00323: 0x01E36
+ "\x00\x01\xb0\x00d`\x1e7" + // 0x0006C 0x00323: 0x01E37
+ "\x00x\xd8\x00`\x80\x1e8" + // 0x01E36 0x00304: 0x01E38
+ "\x00x\xdc\x00`\x80\x1e9" + // 0x01E37 0x00304: 0x01E39
+ "\x00\x010\x00f \x1e:" + // 0x0004C 0x00331: 0x01E3A
+ "\x00\x01\xb0\x00f \x1e;" + // 0x0006C 0x00331: 0x01E3B
+ "\x00\x010\x00e\xa0\x1e<" + // 0x0004C 0x0032D: 0x01E3C
+ "\x00\x01\xb0\x00e\xa0\x1e=" + // 0x0006C 0x0032D: 0x01E3D
+ "\x00\x014\x00` \x1e>" + // 0x0004D 0x00301: 0x01E3E
+ "\x00\x01\xb4\x00` \x1e?" + // 0x0006D 0x00301: 0x01E3F
+ "\x00\x014\x00`\xe0\x1e@" + // 0x0004D 0x00307: 0x01E40
+ "\x00\x01\xb4\x00`\xe0\x1eA" + // 0x0006D 0x00307: 0x01E41
+ "\x00\x014\x00d`\x1eB" + // 0x0004D 0x00323: 0x01E42
+ "\x00\x01\xb4\x00d`\x1eC" + // 0x0006D 0x00323: 0x01E43
+ "\x00\x018\x00`\xe0\x1eD" + // 0x0004E 0x00307: 0x01E44
+ "\x00\x01\xb8\x00`\xe0\x1eE" + // 0x0006E 0x00307: 0x01E45
+ "\x00\x018\x00d`\x1eF" + // 0x0004E 0x00323: 0x01E46
+ "\x00\x01\xb8\x00d`\x1eG" + // 0x0006E 0x00323: 0x01E47
+ "\x00\x018\x00f \x1eH" + // 0x0004E 0x00331: 0x01E48
+ "\x00\x01\xb8\x00f \x1eI" + // 0x0006E 0x00331: 0x01E49
+ "\x00\x018\x00e\xa0\x1eJ" + // 0x0004E 0x0032D: 0x01E4A
+ "\x00\x01\xb8\x00e\xa0\x1eK" + // 0x0006E 0x0032D: 0x01E4B
+ "\x00\x03T\x00` \x1eL" + // 0x000D5 0x00301: 0x01E4C
+ "\x00\x03\xd4\x00` \x1eM" + // 0x000F5 0x00301: 0x01E4D
+ "\x00\x03T\x00a\x00\x1eN" + // 0x000D5 0x00308: 0x01E4E
+ "\x00\x03\xd4\x00a\x00\x1eO" + // 0x000F5 0x00308: 0x01E4F
+ "\x00\x050\x00`\x00\x1eP" + // 0x0014C 0x00300: 0x01E50
+ "\x00\x054\x00`\x00\x1eQ" + // 0x0014D 0x00300: 0x01E51
+ "\x00\x050\x00` \x1eR" + // 0x0014C 0x00301: 0x01E52
+ "\x00\x054\x00` \x1eS" + // 0x0014D 0x00301: 0x01E53
+ "\x00\x01@\x00` \x1eT" + // 0x00050 0x00301: 0x01E54
+ "\x00\x01\xc0\x00` \x1eU" + // 0x00070 0x00301: 0x01E55
+ "\x00\x01@\x00`\xe0\x1eV" + // 0x00050 0x00307: 0x01E56
+ "\x00\x01\xc0\x00`\xe0\x1eW" + // 0x00070 0x00307: 0x01E57
+ "\x00\x01H\x00`\xe0\x1eX" + // 0x00052 0x00307: 0x01E58
+ "\x00\x01\xc8\x00`\xe0\x1eY" + // 0x00072 0x00307: 0x01E59
+ "\x00\x01H\x00d`\x1eZ" + // 0x00052 0x00323: 0x01E5A
+ "\x00\x01\xc8\x00d`\x1e[" + // 0x00072 0x00323: 0x01E5B
+ "\x00yh\x00`\x80\x1e\\" + // 0x01E5A 0x00304: 0x01E5C
+ "\x00yl\x00`\x80\x1e]" + // 0x01E5B 0x00304: 0x01E5D
+ "\x00\x01H\x00f \x1e^" + // 0x00052 0x00331: 0x01E5E
+ "\x00\x01\xc8\x00f \x1e_" + // 0x00072 0x00331: 0x01E5F
+ "\x00\x01L\x00`\xe0\x1e`" + // 0x00053 0x00307: 0x01E60
+ "\x00\x01\xcc\x00`\xe0\x1ea" + // 0x00073 0x00307: 0x01E61
+ "\x00\x01L\x00d`\x1eb" + // 0x00053 0x00323: 0x01E62
+ "\x00\x01\xcc\x00d`\x1ec" + // 0x00073 0x00323: 0x01E63
+ "\x00\x05h\x00`\xe0\x1ed" + // 0x0015A 0x00307: 0x01E64
+ "\x00\x05l\x00`\xe0\x1ee" + // 0x0015B 0x00307: 0x01E65
+ "\x00\x05\x80\x00`\xe0\x1ef" + // 0x00160 0x00307: 0x01E66
+ "\x00\x05\x84\x00`\xe0\x1eg" + // 0x00161 0x00307: 0x01E67
+ "\x00y\x88\x00`\xe0\x1eh" + // 0x01E62 0x00307: 0x01E68
+ "\x00y\x8c\x00`\xe0\x1ei" + // 0x01E63 0x00307: 0x01E69
+ "\x00\x01P\x00`\xe0\x1ej" + // 0x00054 0x00307: 0x01E6A
+ "\x00\x01\xd0\x00`\xe0\x1ek" + // 0x00074 0x00307: 0x01E6B
+ "\x00\x01P\x00d`\x1el" + // 0x00054 0x00323: 0x01E6C
+ "\x00\x01\xd0\x00d`\x1em" + // 0x00074 0x00323: 0x01E6D
+ "\x00\x01P\x00f \x1en" + // 0x00054 0x00331: 0x01E6E
+ "\x00\x01\xd0\x00f \x1eo" + // 0x00074 0x00331: 0x01E6F
+ "\x00\x01P\x00e\xa0\x1ep" + // 0x00054 0x0032D: 0x01E70
+ "\x00\x01\xd0\x00e\xa0\x1eq" + // 0x00074 0x0032D: 0x01E71
+ "\x00\x01T\x00d\x80\x1er" + // 0x00055 0x00324: 0x01E72
+ "\x00\x01\xd4\x00d\x80\x1es" + // 0x00075 0x00324: 0x01E73
+ "\x00\x01T\x00f\x00\x1et" + // 0x00055 0x00330: 0x01E74
+ "\x00\x01\xd4\x00f\x00\x1eu" + // 0x00075 0x00330: 0x01E75
+ "\x00\x01T\x00e\xa0\x1ev" + // 0x00055 0x0032D: 0x01E76
+ "\x00\x01\xd4\x00e\xa0\x1ew" + // 0x00075 0x0032D: 0x01E77
+ "\x00\x05\xa0\x00` \x1ex" + // 0x00168 0x00301: 0x01E78
+ "\x00\x05\xa4\x00` \x1ey" + // 0x00169 0x00301: 0x01E79
+ "\x00\x05\xa8\x00a\x00\x1ez" + // 0x0016A 0x00308: 0x01E7A
+ "\x00\x05\xac\x00a\x00\x1e{" + // 0x0016B 0x00308: 0x01E7B
+ "\x00\x01X\x00``\x1e|" + // 0x00056 0x00303: 0x01E7C
+ "\x00\x01\xd8\x00``\x1e}" + // 0x00076 0x00303: 0x01E7D
+ "\x00\x01X\x00d`\x1e~" + // 0x00056 0x00323: 0x01E7E
+ "\x00\x01\xd8\x00d`\x1e\x7f" + // 0x00076 0x00323: 0x01E7F
+ "\x00\x01\\\x00`\x00\x1e\x80" + // 0x00057 0x00300: 0x01E80
+ "\x00\x01\xdc\x00`\x00\x1e\x81" + // 0x00077 0x00300: 0x01E81
+ "\x00\x01\\\x00` \x1e\x82" + // 0x00057 0x00301: 0x01E82
+ "\x00\x01\xdc\x00` \x1e\x83" + // 0x00077 0x00301: 0x01E83
+ "\x00\x01\\\x00a\x00\x1e\x84" + // 0x00057 0x00308: 0x01E84
+ "\x00\x01\xdc\x00a\x00\x1e\x85" + // 0x00077 0x00308: 0x01E85
+ "\x00\x01\\\x00`\xe0\x1e\x86" + // 0x00057 0x00307: 0x01E86
+ "\x00\x01\xdc\x00`\xe0\x1e\x87" + // 0x00077 0x00307: 0x01E87
+ "\x00\x01\\\x00d`\x1e\x88" + // 0x00057 0x00323: 0x01E88
+ "\x00\x01\xdc\x00d`\x1e\x89" + // 0x00077 0x00323: 0x01E89
+ "\x00\x01`\x00`\xe0\x1e\x8a" + // 0x00058 0x00307: 0x01E8A
+ "\x00\x01\xe0\x00`\xe0\x1e\x8b" + // 0x00078 0x00307: 0x01E8B
+ "\x00\x01`\x00a\x00\x1e\x8c" + // 0x00058 0x00308: 0x01E8C
+ "\x00\x01\xe0\x00a\x00\x1e\x8d" + // 0x00078 0x00308: 0x01E8D
+ "\x00\x01d\x00`\xe0\x1e\x8e" + // 0x00059 0x00307: 0x01E8E
+ "\x00\x01\xe4\x00`\xe0\x1e\x8f" + // 0x00079 0x00307: 0x01E8F
+ "\x00\x01h\x00`@\x1e\x90" + // 0x0005A 0x00302: 0x01E90
+ "\x00\x01\xe8\x00`@\x1e\x91" + // 0x0007A 0x00302: 0x01E91
+ "\x00\x01h\x00d`\x1e\x92" + // 0x0005A 0x00323: 0x01E92
+ "\x00\x01\xe8\x00d`\x1e\x93" + // 0x0007A 0x00323: 0x01E93
+ "\x00\x01h\x00f \x1e\x94" + // 0x0005A 0x00331: 0x01E94
+ "\x00\x01\xe8\x00f \x1e\x95" + // 0x0007A 0x00331: 0x01E95
+ "\x00\x01\xa0\x00f \x1e\x96" + // 0x00068 0x00331: 0x01E96
+ "\x00\x01\xd0\x00a\x00\x1e\x97" + // 0x00074 0x00308: 0x01E97
+ "\x00\x01\xdc\x00a@\x1e\x98" + // 0x00077 0x0030A: 0x01E98
+ "\x00\x01\xe4\x00a@\x1e\x99" + // 0x00079 0x0030A: 0x01E99
+ "\x00\x05\xfc\x00`\xe0\x1e\x9b" + // 0x0017F 0x00307: 0x01E9B
+ "\x00\x01\x04\x00d`\x1e\xa0" + // 0x00041 0x00323: 0x01EA0
+ "\x00\x01\x84\x00d`\x1e\xa1" + // 0x00061 0x00323: 0x01EA1
+ "\x00\x01\x04\x00a \x1e\xa2" + // 0x00041 0x00309: 0x01EA2
+ "\x00\x01\x84\x00a \x1e\xa3" + // 0x00061 0x00309: 0x01EA3
+ "\x00\x03\b\x00` \x1e\xa4" + // 0x000C2 0x00301: 0x01EA4
+ "\x00\x03\x88\x00` \x1e\xa5" + // 0x000E2 0x00301: 0x01EA5
+ "\x00\x03\b\x00`\x00\x1e\xa6" + // 0x000C2 0x00300: 0x01EA6
+ "\x00\x03\x88\x00`\x00\x1e\xa7" + // 0x000E2 0x00300: 0x01EA7
+ "\x00\x03\b\x00a \x1e\xa8" + // 0x000C2 0x00309: 0x01EA8
+ "\x00\x03\x88\x00a \x1e\xa9" + // 0x000E2 0x00309: 0x01EA9
+ "\x00\x03\b\x00``\x1e\xaa" + // 0x000C2 0x00303: 0x01EAA
+ "\x00\x03\x88\x00``\x1e\xab" + // 0x000E2 0x00303: 0x01EAB
+ "\x00z\x80\x00`@\x1e\xac" + // 0x01EA0 0x00302: 0x01EAC
+ "\x00z\x84\x00`@\x1e\xad" + // 0x01EA1 0x00302: 0x01EAD
+ "\x00\x04\b\x00` \x1e\xae" + // 0x00102 0x00301: 0x01EAE
+ "\x00\x04\f\x00` \x1e\xaf" + // 0x00103 0x00301: 0x01EAF
+ "\x00\x04\b\x00`\x00\x1e\xb0" + // 0x00102 0x00300: 0x01EB0
+ "\x00\x04\f\x00`\x00\x1e\xb1" + // 0x00103 0x00300: 0x01EB1
+ "\x00\x04\b\x00a \x1e\xb2" + // 0x00102 0x00309: 0x01EB2
+ "\x00\x04\f\x00a \x1e\xb3" + // 0x00103 0x00309: 0x01EB3
+ "\x00\x04\b\x00``\x1e\xb4" + // 0x00102 0x00303: 0x01EB4
+ "\x00\x04\f\x00``\x1e\xb5" + // 0x00103 0x00303: 0x01EB5
+ "\x00z\x80\x00`\xc0\x1e\xb6" + // 0x01EA0 0x00306: 0x01EB6
+ "\x00z\x84\x00`\xc0\x1e\xb7" + // 0x01EA1 0x00306: 0x01EB7
+ "\x00\x01\x14\x00d`\x1e\xb8" + // 0x00045 0x00323: 0x01EB8
+ "\x00\x01\x94\x00d`\x1e\xb9" + // 0x00065 0x00323: 0x01EB9
+ "\x00\x01\x14\x00a \x1e\xba" + // 0x00045 0x00309: 0x01EBA
+ "\x00\x01\x94\x00a \x1e\xbb" + // 0x00065 0x00309: 0x01EBB
+ "\x00\x01\x14\x00``\x1e\xbc" + // 0x00045 0x00303: 0x01EBC
+ "\x00\x01\x94\x00``\x1e\xbd" + // 0x00065 0x00303: 0x01EBD
+ "\x00\x03(\x00` \x1e\xbe" + // 0x000CA 0x00301: 0x01EBE
+ "\x00\x03\xa8\x00` \x1e\xbf" + // 0x000EA 0x00301: 0x01EBF
+ "\x00\x03(\x00`\x00\x1e\xc0" + // 0x000CA 0x00300: 0x01EC0
+ "\x00\x03\xa8\x00`\x00\x1e\xc1" + // 0x000EA 0x00300: 0x01EC1
+ "\x00\x03(\x00a \x1e\xc2" + // 0x000CA 0x00309: 0x01EC2
+ "\x00\x03\xa8\x00a \x1e\xc3" + // 0x000EA 0x00309: 0x01EC3
+ "\x00\x03(\x00``\x1e\xc4" + // 0x000CA 0x00303: 0x01EC4
+ "\x00\x03\xa8\x00``\x1e\xc5" + // 0x000EA 0x00303: 0x01EC5
+ "\x00z\xe0\x00`@\x1e\xc6" + // 0x01EB8 0x00302: 0x01EC6
+ "\x00z\xe4\x00`@\x1e\xc7" + // 0x01EB9 0x00302: 0x01EC7
+ "\x00\x01$\x00a \x1e\xc8" + // 0x00049 0x00309: 0x01EC8
+ "\x00\x01\xa4\x00a \x1e\xc9" + // 0x00069 0x00309: 0x01EC9
+ "\x00\x01$\x00d`\x1e\xca" + // 0x00049 0x00323: 0x01ECA
+ "\x00\x01\xa4\x00d`\x1e\xcb" + // 0x00069 0x00323: 0x01ECB
+ "\x00\x01<\x00d`\x1e\xcc" + // 0x0004F 0x00323: 0x01ECC
+ "\x00\x01\xbc\x00d`\x1e\xcd" + // 0x0006F 0x00323: 0x01ECD
+ "\x00\x01<\x00a \x1e\xce" + // 0x0004F 0x00309: 0x01ECE
+ "\x00\x01\xbc\x00a \x1e\xcf" + // 0x0006F 0x00309: 0x01ECF
+ "\x00\x03P\x00` \x1e\xd0" + // 0x000D4 0x00301: 0x01ED0
+ "\x00\x03\xd0\x00` \x1e\xd1" + // 0x000F4 0x00301: 0x01ED1
+ "\x00\x03P\x00`\x00\x1e\xd2" + // 0x000D4 0x00300: 0x01ED2
+ "\x00\x03\xd0\x00`\x00\x1e\xd3" + // 0x000F4 0x00300: 0x01ED3
+ "\x00\x03P\x00a \x1e\xd4" + // 0x000D4 0x00309: 0x01ED4
+ "\x00\x03\xd0\x00a \x1e\xd5" + // 0x000F4 0x00309: 0x01ED5
+ "\x00\x03P\x00``\x1e\xd6" + // 0x000D4 0x00303: 0x01ED6
+ "\x00\x03\xd0\x00``\x1e\xd7" + // 0x000F4 0x00303: 0x01ED7
+ "\x00{0\x00`@\x1e\xd8" + // 0x01ECC 0x00302: 0x01ED8
+ "\x00{4\x00`@\x1e\xd9" + // 0x01ECD 0x00302: 0x01ED9
+ "\x00\x06\x80\x00` \x1e\xda" + // 0x001A0 0x00301: 0x01EDA
+ "\x00\x06\x84\x00` \x1e\xdb" + // 0x001A1 0x00301: 0x01EDB
+ "\x00\x06\x80\x00`\x00\x1e\xdc" + // 0x001A0 0x00300: 0x01EDC
+ "\x00\x06\x84\x00`\x00\x1e\xdd" + // 0x001A1 0x00300: 0x01EDD
+ "\x00\x06\x80\x00a \x1e\xde" + // 0x001A0 0x00309: 0x01EDE
+ "\x00\x06\x84\x00a \x1e\xdf" + // 0x001A1 0x00309: 0x01EDF
+ "\x00\x06\x80\x00``\x1e\xe0" + // 0x001A0 0x00303: 0x01EE0
+ "\x00\x06\x84\x00``\x1e\xe1" + // 0x001A1 0x00303: 0x01EE1
+ "\x00\x06\x80\x00d`\x1e\xe2" + // 0x001A0 0x00323: 0x01EE2
+ "\x00\x06\x84\x00d`\x1e\xe3" + // 0x001A1 0x00323: 0x01EE3
+ "\x00\x01T\x00d`\x1e\xe4" + // 0x00055 0x00323: 0x01EE4
+ "\x00\x01\xd4\x00d`\x1e\xe5" + // 0x00075 0x00323: 0x01EE5
+ "\x00\x01T\x00a \x1e\xe6" + // 0x00055 0x00309: 0x01EE6
+ "\x00\x01\xd4\x00a \x1e\xe7" + // 0x00075 0x00309: 0x01EE7
+ "\x00\x06\xbc\x00` \x1e\xe8" + // 0x001AF 0x00301: 0x01EE8
+ "\x00\x06\xc0\x00` \x1e\xe9" + // 0x001B0 0x00301: 0x01EE9
+ "\x00\x06\xbc\x00`\x00\x1e\xea" + // 0x001AF 0x00300: 0x01EEA
+ "\x00\x06\xc0\x00`\x00\x1e\xeb" + // 0x001B0 0x00300: 0x01EEB
+ "\x00\x06\xbc\x00a \x1e\xec" + // 0x001AF 0x00309: 0x01EEC
+ "\x00\x06\xc0\x00a \x1e\xed" + // 0x001B0 0x00309: 0x01EED
+ "\x00\x06\xbc\x00``\x1e\xee" + // 0x001AF 0x00303: 0x01EEE
+ "\x00\x06\xc0\x00``\x1e\xef" + // 0x001B0 0x00303: 0x01EEF
+ "\x00\x06\xbc\x00d`\x1e\xf0" + // 0x001AF 0x00323: 0x01EF0
+ "\x00\x06\xc0\x00d`\x1e\xf1" + // 0x001B0 0x00323: 0x01EF1
+ "\x00\x01d\x00`\x00\x1e\xf2" + // 0x00059 0x00300: 0x01EF2
+ "\x00\x01\xe4\x00`\x00\x1e\xf3" + // 0x00079 0x00300: 0x01EF3
+ "\x00\x01d\x00d`\x1e\xf4" + // 0x00059 0x00323: 0x01EF4
+ "\x00\x01\xe4\x00d`\x1e\xf5" + // 0x00079 0x00323: 0x01EF5
+ "\x00\x01d\x00a \x1e\xf6" + // 0x00059 0x00309: 0x01EF6
+ "\x00\x01\xe4\x00a \x1e\xf7" + // 0x00079 0x00309: 0x01EF7
+ "\x00\x01d\x00``\x1e\xf8" + // 0x00059 0x00303: 0x01EF8
+ "\x00\x01\xe4\x00``\x1e\xf9" + // 0x00079 0x00303: 0x01EF9
+ "\x00\x0e\xc4\x00b`\x1f\x00" + // 0x003B1 0x00313: 0x01F00
+ "\x00\x0e\xc4\x00b\x80\x1f\x01" + // 0x003B1 0x00314: 0x01F01
+ "\x00|\x00\x00`\x00\x1f\x02" + // 0x01F00 0x00300: 0x01F02
+ "\x00|\x04\x00`\x00\x1f\x03" + // 0x01F01 0x00300: 0x01F03
+ "\x00|\x00\x00` \x1f\x04" + // 0x01F00 0x00301: 0x01F04
+ "\x00|\x04\x00` \x1f\x05" + // 0x01F01 0x00301: 0x01F05
+ "\x00|\x00\x00h@\x1f\x06" + // 0x01F00 0x00342: 0x01F06
+ "\x00|\x04\x00h@\x1f\a" + // 0x01F01 0x00342: 0x01F07
+ "\x00\x0eD\x00b`\x1f\b" + // 0x00391 0x00313: 0x01F08
+ "\x00\x0eD\x00b\x80\x1f\t" + // 0x00391 0x00314: 0x01F09
+ "\x00| \x00`\x00\x1f\n" + // 0x01F08 0x00300: 0x01F0A
+ "\x00|$\x00`\x00\x1f\v" + // 0x01F09 0x00300: 0x01F0B
+ "\x00| \x00` \x1f\f" + // 0x01F08 0x00301: 0x01F0C
+ "\x00|$\x00` \x1f\r" + // 0x01F09 0x00301: 0x01F0D
+ "\x00| \x00h@\x1f\x0e" + // 0x01F08 0x00342: 0x01F0E
+ "\x00|$\x00h@\x1f\x0f" + // 0x01F09 0x00342: 0x01F0F
+ "\x00\x0e\xd4\x00b`\x1f\x10" + // 0x003B5 0x00313: 0x01F10
+ "\x00\x0e\xd4\x00b\x80\x1f\x11" + // 0x003B5 0x00314: 0x01F11
+ "\x00|@\x00`\x00\x1f\x12" + // 0x01F10 0x00300: 0x01F12
+ "\x00|D\x00`\x00\x1f\x13" + // 0x01F11 0x00300: 0x01F13
+ "\x00|@\x00` \x1f\x14" + // 0x01F10 0x00301: 0x01F14
+ "\x00|D\x00` \x1f\x15" + // 0x01F11 0x00301: 0x01F15
+ "\x00\x0eT\x00b`\x1f\x18" + // 0x00395 0x00313: 0x01F18
+ "\x00\x0eT\x00b\x80\x1f\x19" + // 0x00395 0x00314: 0x01F19
+ "\x00|`\x00`\x00\x1f\x1a" + // 0x01F18 0x00300: 0x01F1A
+ "\x00|d\x00`\x00\x1f\x1b" + // 0x01F19 0x00300: 0x01F1B
+ "\x00|`\x00` \x1f\x1c" + // 0x01F18 0x00301: 0x01F1C
+ "\x00|d\x00` \x1f\x1d" + // 0x01F19 0x00301: 0x01F1D
+ "\x00\x0e\xdc\x00b`\x1f " + // 0x003B7 0x00313: 0x01F20
+ "\x00\x0e\xdc\x00b\x80\x1f!" + // 0x003B7 0x00314: 0x01F21
+ "\x00|\x80\x00`\x00\x1f\"" + // 0x01F20 0x00300: 0x01F22
+ "\x00|\x84\x00`\x00\x1f#" + // 0x01F21 0x00300: 0x01F23
+ "\x00|\x80\x00` \x1f$" + // 0x01F20 0x00301: 0x01F24
+ "\x00|\x84\x00` \x1f%" + // 0x01F21 0x00301: 0x01F25
+ "\x00|\x80\x00h@\x1f&" + // 0x01F20 0x00342: 0x01F26
+ "\x00|\x84\x00h@\x1f'" + // 0x01F21 0x00342: 0x01F27
+ "\x00\x0e\\\x00b`\x1f(" + // 0x00397 0x00313: 0x01F28
+ "\x00\x0e\\\x00b\x80\x1f)" + // 0x00397 0x00314: 0x01F29
+ "\x00|\xa0\x00`\x00\x1f*" + // 0x01F28 0x00300: 0x01F2A
+ "\x00|\xa4\x00`\x00\x1f+" + // 0x01F29 0x00300: 0x01F2B
+ "\x00|\xa0\x00` \x1f," + // 0x01F28 0x00301: 0x01F2C
+ "\x00|\xa4\x00` \x1f-" + // 0x01F29 0x00301: 0x01F2D
+ "\x00|\xa0\x00h@\x1f." + // 0x01F28 0x00342: 0x01F2E
+ "\x00|\xa4\x00h@\x1f/" + // 0x01F29 0x00342: 0x01F2F
+ "\x00\x0e\xe4\x00b`\x1f0" + // 0x003B9 0x00313: 0x01F30
+ "\x00\x0e\xe4\x00b\x80\x1f1" + // 0x003B9 0x00314: 0x01F31
+ "\x00|\xc0\x00`\x00\x1f2" + // 0x01F30 0x00300: 0x01F32
+ "\x00|\xc4\x00`\x00\x1f3" + // 0x01F31 0x00300: 0x01F33
+ "\x00|\xc0\x00` \x1f4" + // 0x01F30 0x00301: 0x01F34
+ "\x00|\xc4\x00` \x1f5" + // 0x01F31 0x00301: 0x01F35
+ "\x00|\xc0\x00h@\x1f6" + // 0x01F30 0x00342: 0x01F36
+ "\x00|\xc4\x00h@\x1f7" + // 0x01F31 0x00342: 0x01F37
+ "\x00\x0ed\x00b`\x1f8" + // 0x00399 0x00313: 0x01F38
+ "\x00\x0ed\x00b\x80\x1f9" + // 0x00399 0x00314: 0x01F39
+ "\x00|\xe0\x00`\x00\x1f:" + // 0x01F38 0x00300: 0x01F3A
+ "\x00|\xe4\x00`\x00\x1f;" + // 0x01F39 0x00300: 0x01F3B
+ "\x00|\xe0\x00` \x1f<" + // 0x01F38 0x00301: 0x01F3C
+ "\x00|\xe4\x00` \x1f=" + // 0x01F39 0x00301: 0x01F3D
+ "\x00|\xe0\x00h@\x1f>" + // 0x01F38 0x00342: 0x01F3E
+ "\x00|\xe4\x00h@\x1f?" + // 0x01F39 0x00342: 0x01F3F
+ "\x00\x0e\xfc\x00b`\x1f@" + // 0x003BF 0x00313: 0x01F40
+ "\x00\x0e\xfc\x00b\x80\x1fA" + // 0x003BF 0x00314: 0x01F41
+ "\x00}\x00\x00`\x00\x1fB" + // 0x01F40 0x00300: 0x01F42
+ "\x00}\x04\x00`\x00\x1fC" + // 0x01F41 0x00300: 0x01F43
+ "\x00}\x00\x00` \x1fD" + // 0x01F40 0x00301: 0x01F44
+ "\x00}\x04\x00` \x1fE" + // 0x01F41 0x00301: 0x01F45
+ "\x00\x0e|\x00b`\x1fH" + // 0x0039F 0x00313: 0x01F48
+ "\x00\x0e|\x00b\x80\x1fI" + // 0x0039F 0x00314: 0x01F49
+ "\x00} \x00`\x00\x1fJ" + // 0x01F48 0x00300: 0x01F4A
+ "\x00}$\x00`\x00\x1fK" + // 0x01F49 0x00300: 0x01F4B
+ "\x00} \x00` \x1fL" + // 0x01F48 0x00301: 0x01F4C
+ "\x00}$\x00` \x1fM" + // 0x01F49 0x00301: 0x01F4D
+ "\x00\x0f\x14\x00b`\x1fP" + // 0x003C5 0x00313: 0x01F50
+ "\x00\x0f\x14\x00b\x80\x1fQ" + // 0x003C5 0x00314: 0x01F51
+ "\x00}@\x00`\x00\x1fR" + // 0x01F50 0x00300: 0x01F52
+ "\x00}D\x00`\x00\x1fS" + // 0x01F51 0x00300: 0x01F53
+ "\x00}@\x00` \x1fT" + // 0x01F50 0x00301: 0x01F54
+ "\x00}D\x00` \x1fU" + // 0x01F51 0x00301: 0x01F55
+ "\x00}@\x00h@\x1fV" + // 0x01F50 0x00342: 0x01F56
+ "\x00}D\x00h@\x1fW" + // 0x01F51 0x00342: 0x01F57
+ "\x00\x0e\x94\x00b\x80\x1fY" + // 0x003A5 0x00314: 0x01F59
+ "\x00}d\x00`\x00\x1f[" + // 0x01F59 0x00300: 0x01F5B
+ "\x00}d\x00` \x1f]" + // 0x01F59 0x00301: 0x01F5D
+ "\x00}d\x00h@\x1f_" + // 0x01F59 0x00342: 0x01F5F
+ "\x00\x0f$\x00b`\x1f`" + // 0x003C9 0x00313: 0x01F60
+ "\x00\x0f$\x00b\x80\x1fa" + // 0x003C9 0x00314: 0x01F61
+ "\x00}\x80\x00`\x00\x1fb" + // 0x01F60 0x00300: 0x01F62
+ "\x00}\x84\x00`\x00\x1fc" + // 0x01F61 0x00300: 0x01F63
+ "\x00}\x80\x00` \x1fd" + // 0x01F60 0x00301: 0x01F64
+ "\x00}\x84\x00` \x1fe" + // 0x01F61 0x00301: 0x01F65
+ "\x00}\x80\x00h@\x1ff" + // 0x01F60 0x00342: 0x01F66
+ "\x00}\x84\x00h@\x1fg" + // 0x01F61 0x00342: 0x01F67
+ "\x00\x0e\xa4\x00b`\x1fh" + // 0x003A9 0x00313: 0x01F68
+ "\x00\x0e\xa4\x00b\x80\x1fi" + // 0x003A9 0x00314: 0x01F69
+ "\x00}\xa0\x00`\x00\x1fj" + // 0x01F68 0x00300: 0x01F6A
+ "\x00}\xa4\x00`\x00\x1fk" + // 0x01F69 0x00300: 0x01F6B
+ "\x00}\xa0\x00` \x1fl" + // 0x01F68 0x00301: 0x01F6C
+ "\x00}\xa4\x00` \x1fm" + // 0x01F69 0x00301: 0x01F6D
+ "\x00}\xa0\x00h@\x1fn" + // 0x01F68 0x00342: 0x01F6E
+ "\x00}\xa4\x00h@\x1fo" + // 0x01F69 0x00342: 0x01F6F
+ "\x00\x0e\xc4\x00`\x00\x1fp" + // 0x003B1 0x00300: 0x01F70
+ "\x00\x0e\xd4\x00`\x00\x1fr" + // 0x003B5 0x00300: 0x01F72
+ "\x00\x0e\xdc\x00`\x00\x1ft" + // 0x003B7 0x00300: 0x01F74
+ "\x00\x0e\xe4\x00`\x00\x1fv" + // 0x003B9 0x00300: 0x01F76
+ "\x00\x0e\xfc\x00`\x00\x1fx" + // 0x003BF 0x00300: 0x01F78
+ "\x00\x0f\x14\x00`\x00\x1fz" + // 0x003C5 0x00300: 0x01F7A
+ "\x00\x0f$\x00`\x00\x1f|" + // 0x003C9 0x00300: 0x01F7C
+ "\x00|\x00\x00h\xa0\x1f\x80" + // 0x01F00 0x00345: 0x01F80
+ "\x00|\x04\x00h\xa0\x1f\x81" + // 0x01F01 0x00345: 0x01F81
+ "\x00|\b\x00h\xa0\x1f\x82" + // 0x01F02 0x00345: 0x01F82
+ "\x00|\f\x00h\xa0\x1f\x83" + // 0x01F03 0x00345: 0x01F83
+ "\x00|\x10\x00h\xa0\x1f\x84" + // 0x01F04 0x00345: 0x01F84
+ "\x00|\x14\x00h\xa0\x1f\x85" + // 0x01F05 0x00345: 0x01F85
+ "\x00|\x18\x00h\xa0\x1f\x86" + // 0x01F06 0x00345: 0x01F86
+ "\x00|\x1c\x00h\xa0\x1f\x87" + // 0x01F07 0x00345: 0x01F87
+ "\x00| \x00h\xa0\x1f\x88" + // 0x01F08 0x00345: 0x01F88
+ "\x00|$\x00h\xa0\x1f\x89" + // 0x01F09 0x00345: 0x01F89
+ "\x00|(\x00h\xa0\x1f\x8a" + // 0x01F0A 0x00345: 0x01F8A
+ "\x00|,\x00h\xa0\x1f\x8b" + // 0x01F0B 0x00345: 0x01F8B
+ "\x00|0\x00h\xa0\x1f\x8c" + // 0x01F0C 0x00345: 0x01F8C
+ "\x00|4\x00h\xa0\x1f\x8d" + // 0x01F0D 0x00345: 0x01F8D
+ "\x00|8\x00h\xa0\x1f\x8e" + // 0x01F0E 0x00345: 0x01F8E
+ "\x00|<\x00h\xa0\x1f\x8f" + // 0x01F0F 0x00345: 0x01F8F
+ "\x00|\x80\x00h\xa0\x1f\x90" + // 0x01F20 0x00345: 0x01F90
+ "\x00|\x84\x00h\xa0\x1f\x91" + // 0x01F21 0x00345: 0x01F91
+ "\x00|\x88\x00h\xa0\x1f\x92" + // 0x01F22 0x00345: 0x01F92
+ "\x00|\x8c\x00h\xa0\x1f\x93" + // 0x01F23 0x00345: 0x01F93
+ "\x00|\x90\x00h\xa0\x1f\x94" + // 0x01F24 0x00345: 0x01F94
+ "\x00|\x94\x00h\xa0\x1f\x95" + // 0x01F25 0x00345: 0x01F95
+ "\x00|\x98\x00h\xa0\x1f\x96" + // 0x01F26 0x00345: 0x01F96
+ "\x00|\x9c\x00h\xa0\x1f\x97" + // 0x01F27 0x00345: 0x01F97
+ "\x00|\xa0\x00h\xa0\x1f\x98" + // 0x01F28 0x00345: 0x01F98
+ "\x00|\xa4\x00h\xa0\x1f\x99" + // 0x01F29 0x00345: 0x01F99
+ "\x00|\xa8\x00h\xa0\x1f\x9a" + // 0x01F2A 0x00345: 0x01F9A
+ "\x00|\xac\x00h\xa0\x1f\x9b" + // 0x01F2B 0x00345: 0x01F9B
+ "\x00|\xb0\x00h\xa0\x1f\x9c" + // 0x01F2C 0x00345: 0x01F9C
+ "\x00|\xb4\x00h\xa0\x1f\x9d" + // 0x01F2D 0x00345: 0x01F9D
+ "\x00|\xb8\x00h\xa0\x1f\x9e" + // 0x01F2E 0x00345: 0x01F9E
+ "\x00|\xbc\x00h\xa0\x1f\x9f" + // 0x01F2F 0x00345: 0x01F9F
+ "\x00}\x80\x00h\xa0\x1f\xa0" + // 0x01F60 0x00345: 0x01FA0
+ "\x00}\x84\x00h\xa0\x1f\xa1" + // 0x01F61 0x00345: 0x01FA1
+ "\x00}\x88\x00h\xa0\x1f\xa2" + // 0x01F62 0x00345: 0x01FA2
+ "\x00}\x8c\x00h\xa0\x1f\xa3" + // 0x01F63 0x00345: 0x01FA3
+ "\x00}\x90\x00h\xa0\x1f\xa4" + // 0x01F64 0x00345: 0x01FA4
+ "\x00}\x94\x00h\xa0\x1f\xa5" + // 0x01F65 0x00345: 0x01FA5
+ "\x00}\x98\x00h\xa0\x1f\xa6" + // 0x01F66 0x00345: 0x01FA6
+ "\x00}\x9c\x00h\xa0\x1f\xa7" + // 0x01F67 0x00345: 0x01FA7
+ "\x00}\xa0\x00h\xa0\x1f\xa8" + // 0x01F68 0x00345: 0x01FA8
+ "\x00}\xa4\x00h\xa0\x1f\xa9" + // 0x01F69 0x00345: 0x01FA9
+ "\x00}\xa8\x00h\xa0\x1f\xaa" + // 0x01F6A 0x00345: 0x01FAA
+ "\x00}\xac\x00h\xa0\x1f\xab" + // 0x01F6B 0x00345: 0x01FAB
+ "\x00}\xb0\x00h\xa0\x1f\xac" + // 0x01F6C 0x00345: 0x01FAC
+ "\x00}\xb4\x00h\xa0\x1f\xad" + // 0x01F6D 0x00345: 0x01FAD
+ "\x00}\xb8\x00h\xa0\x1f\xae" + // 0x01F6E 0x00345: 0x01FAE
+ "\x00}\xbc\x00h\xa0\x1f\xaf" + // 0x01F6F 0x00345: 0x01FAF
+ "\x00\x0e\xc4\x00`\xc0\x1f\xb0" + // 0x003B1 0x00306: 0x01FB0
+ "\x00\x0e\xc4\x00`\x80\x1f\xb1" + // 0x003B1 0x00304: 0x01FB1
+ "\x00}\xc0\x00h\xa0\x1f\xb2" + // 0x01F70 0x00345: 0x01FB2
+ "\x00\x0e\xc4\x00h\xa0\x1f\xb3" + // 0x003B1 0x00345: 0x01FB3
+ "\x00\x0e\xb0\x00h\xa0\x1f\xb4" + // 0x003AC 0x00345: 0x01FB4
+ "\x00\x0e\xc4\x00h@\x1f\xb6" + // 0x003B1 0x00342: 0x01FB6
+ "\x00~\xd8\x00h\xa0\x1f\xb7" + // 0x01FB6 0x00345: 0x01FB7
+ "\x00\x0eD\x00`\xc0\x1f\xb8" + // 0x00391 0x00306: 0x01FB8
+ "\x00\x0eD\x00`\x80\x1f\xb9" + // 0x00391 0x00304: 0x01FB9
+ "\x00\x0eD\x00`\x00\x1f\xba" + // 0x00391 0x00300: 0x01FBA
+ "\x00\x0eD\x00h\xa0\x1f\xbc" + // 0x00391 0x00345: 0x01FBC
+ "\x00\x02\xa0\x00h@\x1f\xc1" + // 0x000A8 0x00342: 0x01FC1
+ "\x00}\xd0\x00h\xa0\x1f\xc2" + // 0x01F74 0x00345: 0x01FC2
+ "\x00\x0e\xdc\x00h\xa0\x1f\xc3" + // 0x003B7 0x00345: 0x01FC3
+ "\x00\x0e\xb8\x00h\xa0\x1f\xc4" + // 0x003AE 0x00345: 0x01FC4
+ "\x00\x0e\xdc\x00h@\x1f\xc6" + // 0x003B7 0x00342: 0x01FC6
+ "\x00\x7f\x18\x00h\xa0\x1f\xc7" + // 0x01FC6 0x00345: 0x01FC7
+ "\x00\x0eT\x00`\x00\x1f\xc8" + // 0x00395 0x00300: 0x01FC8
+ "\x00\x0e\\\x00`\x00\x1f\xca" + // 0x00397 0x00300: 0x01FCA
+ "\x00\x0e\\\x00h\xa0\x1f\xcc" + // 0x00397 0x00345: 0x01FCC
+ "\x00~\xfc\x00`\x00\x1f\xcd" + // 0x01FBF 0x00300: 0x01FCD
+ "\x00~\xfc\x00` \x1f\xce" + // 0x01FBF 0x00301: 0x01FCE
+ "\x00~\xfc\x00h@\x1f\xcf" + // 0x01FBF 0x00342: 0x01FCF
+ "\x00\x0e\xe4\x00`\xc0\x1f\xd0" + // 0x003B9 0x00306: 0x01FD0
+ "\x00\x0e\xe4\x00`\x80\x1f\xd1" + // 0x003B9 0x00304: 0x01FD1
+ "\x00\x0f(\x00`\x00\x1f\xd2" + // 0x003CA 0x00300: 0x01FD2
+ "\x00\x0e\xe4\x00h@\x1f\xd6" + // 0x003B9 0x00342: 0x01FD6
+ "\x00\x0f(\x00h@\x1f\xd7" + // 0x003CA 0x00342: 0x01FD7
+ "\x00\x0ed\x00`\xc0\x1f\xd8" + // 0x00399 0x00306: 0x01FD8
+ "\x00\x0ed\x00`\x80\x1f\xd9" + // 0x00399 0x00304: 0x01FD9
+ "\x00\x0ed\x00`\x00\x1f\xda" + // 0x00399 0x00300: 0x01FDA
+ "\x00\x7f\xf8\x00`\x00\x1f\xdd" + // 0x01FFE 0x00300: 0x01FDD
+ "\x00\x7f\xf8\x00` \x1f\xde" + // 0x01FFE 0x00301: 0x01FDE
+ "\x00\x7f\xf8\x00h@\x1f\xdf" + // 0x01FFE 0x00342: 0x01FDF
+ "\x00\x0f\x14\x00`\xc0\x1f\xe0" + // 0x003C5 0x00306: 0x01FE0
+ "\x00\x0f\x14\x00`\x80\x1f\xe1" + // 0x003C5 0x00304: 0x01FE1
+ "\x00\x0f,\x00`\x00\x1f\xe2" + // 0x003CB 0x00300: 0x01FE2
+ "\x00\x0f\x04\x00b`\x1f\xe4" + // 0x003C1 0x00313: 0x01FE4
+ "\x00\x0f\x04\x00b\x80\x1f\xe5" + // 0x003C1 0x00314: 0x01FE5
+ "\x00\x0f\x14\x00h@\x1f\xe6" + // 0x003C5 0x00342: 0x01FE6
+ "\x00\x0f,\x00h@\x1f\xe7" + // 0x003CB 0x00342: 0x01FE7
+ "\x00\x0e\x94\x00`\xc0\x1f\xe8" + // 0x003A5 0x00306: 0x01FE8
+ "\x00\x0e\x94\x00`\x80\x1f\xe9" + // 0x003A5 0x00304: 0x01FE9
+ "\x00\x0e\x94\x00`\x00\x1f\xea" + // 0x003A5 0x00300: 0x01FEA
+ "\x00\x0e\x84\x00b\x80\x1f\xec" + // 0x003A1 0x00314: 0x01FEC
+ "\x00\x02\xa0\x00`\x00\x1f\xed" + // 0x000A8 0x00300: 0x01FED
+ "\x00}\xf0\x00h\xa0\x1f\xf2" + // 0x01F7C 0x00345: 0x01FF2
+ "\x00\x0f$\x00h\xa0\x1f\xf3" + // 0x003C9 0x00345: 0x01FF3
+ "\x00\x0f8\x00h\xa0\x1f\xf4" + // 0x003CE 0x00345: 0x01FF4
+ "\x00\x0f$\x00h@\x1f\xf6" + // 0x003C9 0x00342: 0x01FF6
+ "\x00\x7f\xd8\x00h\xa0\x1f\xf7" + // 0x01FF6 0x00345: 0x01FF7
+ "\x00\x0e|\x00`\x00\x1f\xf8" + // 0x0039F 0x00300: 0x01FF8
+ "\x00\x0e\xa4\x00`\x00\x1f\xfa" + // 0x003A9 0x00300: 0x01FFA
+ "\x00\x0e\xa4\x00h\xa0\x1f\xfc" + // 0x003A9 0x00345: 0x01FFC
+ "\x00\x86@\x00g\x00!\x9a" + // 0x02190 0x00338: 0x0219A
+ "\x00\x86H\x00g\x00!\x9b" + // 0x02192 0x00338: 0x0219B
+ "\x00\x86P\x00g\x00!\xae" + // 0x02194 0x00338: 0x021AE
+ "\x00\x87@\x00g\x00!\xcd" + // 0x021D0 0x00338: 0x021CD
+ "\x00\x87P\x00g\x00!\xce" + // 0x021D4 0x00338: 0x021CE
+ "\x00\x87H\x00g\x00!\xcf" + // 0x021D2 0x00338: 0x021CF
+ "\x00\x88\f\x00g\x00\"\x04" + // 0x02203 0x00338: 0x02204
+ "\x00\x88 \x00g\x00\"\t" + // 0x02208 0x00338: 0x02209
+ "\x00\x88,\x00g\x00\"\f" + // 0x0220B 0x00338: 0x0220C
+ "\x00\x88\x8c\x00g\x00\"$" + // 0x02223 0x00338: 0x02224
+ "\x00\x88\x94\x00g\x00\"&" + // 0x02225 0x00338: 0x02226
+ "\x00\x88\xf0\x00g\x00\"A" + // 0x0223C 0x00338: 0x02241
+ "\x00\x89\f\x00g\x00\"D" + // 0x02243 0x00338: 0x02244
+ "\x00\x89\x14\x00g\x00\"G" + // 0x02245 0x00338: 0x02247
+ "\x00\x89 \x00g\x00\"I" + // 0x02248 0x00338: 0x02249
+ "\x00\x00\xf4\x00g\x00\"`" + // 0x0003D 0x00338: 0x02260
+ "\x00\x89\x84\x00g\x00\"b" + // 0x02261 0x00338: 0x02262
+ "\x00\x894\x00g\x00\"m" + // 0x0224D 0x00338: 0x0226D
+ "\x00\x00\xf0\x00g\x00\"n" + // 0x0003C 0x00338: 0x0226E
+ "\x00\x00\xf8\x00g\x00\"o" + // 0x0003E 0x00338: 0x0226F
+ "\x00\x89\x90\x00g\x00\"p" + // 0x02264 0x00338: 0x02270
+ "\x00\x89\x94\x00g\x00\"q" + // 0x02265 0x00338: 0x02271
+ "\x00\x89\xc8\x00g\x00\"t" + // 0x02272 0x00338: 0x02274
+ "\x00\x89\xcc\x00g\x00\"u" + // 0x02273 0x00338: 0x02275
+ "\x00\x89\xd8\x00g\x00\"x" + // 0x02276 0x00338: 0x02278
+ "\x00\x89\xdc\x00g\x00\"y" + // 0x02277 0x00338: 0x02279
+ "\x00\x89\xe8\x00g\x00\"\x80" + // 0x0227A 0x00338: 0x02280
+ "\x00\x89\xec\x00g\x00\"\x81" + // 0x0227B 0x00338: 0x02281
+ "\x00\x8a\b\x00g\x00\"\x84" + // 0x02282 0x00338: 0x02284
+ "\x00\x8a\f\x00g\x00\"\x85" + // 0x02283 0x00338: 0x02285
+ "\x00\x8a\x18\x00g\x00\"\x88" + // 0x02286 0x00338: 0x02288
+ "\x00\x8a\x1c\x00g\x00\"\x89" + // 0x02287 0x00338: 0x02289
+ "\x00\x8a\x88\x00g\x00\"\xac" + // 0x022A2 0x00338: 0x022AC
+ "\x00\x8a\xa0\x00g\x00\"\xad" + // 0x022A8 0x00338: 0x022AD
+ "\x00\x8a\xa4\x00g\x00\"\xae" + // 0x022A9 0x00338: 0x022AE
+ "\x00\x8a\xac\x00g\x00\"\xaf" + // 0x022AB 0x00338: 0x022AF
+ "\x00\x89\xf0\x00g\x00\"\xe0" + // 0x0227C 0x00338: 0x022E0
+ "\x00\x89\xf4\x00g\x00\"\xe1" + // 0x0227D 0x00338: 0x022E1
+ "\x00\x8aD\x00g\x00\"\xe2" + // 0x02291 0x00338: 0x022E2
+ "\x00\x8aH\x00g\x00\"\xe3" + // 0x02292 0x00338: 0x022E3
+ "\x00\x8a\xc8\x00g\x00\"\xea" + // 0x022B2 0x00338: 0x022EA
+ "\x00\x8a\xcc\x00g\x00\"\xeb" + // 0x022B3 0x00338: 0x022EB
+ "\x00\x8a\xd0\x00g\x00\"\xec" + // 0x022B4 0x00338: 0x022EC
+ "\x00\x8a\xd4\x00g\x00\"\xed" + // 0x022B5 0x00338: 0x022ED
+ "\x00\xc1,\x06\x13 0L" + // 0x0304B 0x03099: 0x0304C
+ "\x00\xc14\x06\x13 0N" + // 0x0304D 0x03099: 0x0304E
+ "\x00\xc1<\x06\x13 0P" + // 0x0304F 0x03099: 0x03050
+ "\x00\xc1D\x06\x13 0R" + // 0x03051 0x03099: 0x03052
+ "\x00\xc1L\x06\x13 0T" + // 0x03053 0x03099: 0x03054
+ "\x00\xc1T\x06\x13 0V" + // 0x03055 0x03099: 0x03056
+ "\x00\xc1\\\x06\x13 0X" + // 0x03057 0x03099: 0x03058
+ "\x00\xc1d\x06\x13 0Z" + // 0x03059 0x03099: 0x0305A
+ "\x00\xc1l\x06\x13 0\\" + // 0x0305B 0x03099: 0x0305C
+ "\x00\xc1t\x06\x13 0^" + // 0x0305D 0x03099: 0x0305E
+ "\x00\xc1|\x06\x13 0`" + // 0x0305F 0x03099: 0x03060
+ "\x00\xc1\x84\x06\x13 0b" + // 0x03061 0x03099: 0x03062
+ "\x00\xc1\x90\x06\x13 0e" + // 0x03064 0x03099: 0x03065
+ "\x00\xc1\x98\x06\x13 0g" + // 0x03066 0x03099: 0x03067
+ "\x00\xc1\xa0\x06\x13 0i" + // 0x03068 0x03099: 0x03069
+ "\x00\xc1\xbc\x06\x13 0p" + // 0x0306F 0x03099: 0x03070
+ "\x00\xc1\xbc\x06\x13@0q" + // 0x0306F 0x0309A: 0x03071
+ "\x00\xc1\xc8\x06\x13 0s" + // 0x03072 0x03099: 0x03073
+ "\x00\xc1\xc8\x06\x13@0t" + // 0x03072 0x0309A: 0x03074
+ "\x00\xc1\xd4\x06\x13 0v" + // 0x03075 0x03099: 0x03076
+ "\x00\xc1\xd4\x06\x13@0w" + // 0x03075 0x0309A: 0x03077
+ "\x00\xc1\xe0\x06\x13 0y" + // 0x03078 0x03099: 0x03079
+ "\x00\xc1\xe0\x06\x13@0z" + // 0x03078 0x0309A: 0x0307A
+ "\x00\xc1\xec\x06\x13 0|" + // 0x0307B 0x03099: 0x0307C
+ "\x00\xc1\xec\x06\x13@0}" + // 0x0307B 0x0309A: 0x0307D
+ "\x00\xc1\x18\x06\x13 0\x94" + // 0x03046 0x03099: 0x03094
+ "\x00\xc2t\x06\x13 0\x9e" + // 0x0309D 0x03099: 0x0309E
+ "\x00¬\x06\x13 0\xac" + // 0x030AB 0x03099: 0x030AC
+ "\x00´\x06\x13 0\xae" + // 0x030AD 0x03099: 0x030AE
+ "\x00¼\x06\x13 0\xb0" + // 0x030AF 0x03099: 0x030B0
+ "\x00\xc2\xc4\x06\x13 0\xb2" + // 0x030B1 0x03099: 0x030B2
+ "\x00\xc2\xcc\x06\x13 0\xb4" + // 0x030B3 0x03099: 0x030B4
+ "\x00\xc2\xd4\x06\x13 0\xb6" + // 0x030B5 0x03099: 0x030B6
+ "\x00\xc2\xdc\x06\x13 0\xb8" + // 0x030B7 0x03099: 0x030B8
+ "\x00\xc2\xe4\x06\x13 0\xba" + // 0x030B9 0x03099: 0x030BA
+ "\x00\xc2\xec\x06\x13 0\xbc" + // 0x030BB 0x03099: 0x030BC
+ "\x00\xc2\xf4\x06\x13 0\xbe" + // 0x030BD 0x03099: 0x030BE
+ "\x00\xc2\xfc\x06\x13 0\xc0" + // 0x030BF 0x03099: 0x030C0
+ "\x00\xc3\x04\x06\x13 0\xc2" + // 0x030C1 0x03099: 0x030C2
+ "\x00\xc3\x10\x06\x13 0\xc5" + // 0x030C4 0x03099: 0x030C5
+ "\x00\xc3\x18\x06\x13 0\xc7" + // 0x030C6 0x03099: 0x030C7
+ "\x00\xc3 \x06\x13 0\xc9" + // 0x030C8 0x03099: 0x030C9
+ "\x00\xc3<\x06\x13 0\xd0" + // 0x030CF 0x03099: 0x030D0
+ "\x00\xc3<\x06\x13@0\xd1" + // 0x030CF 0x0309A: 0x030D1
+ "\x00\xc3H\x06\x13 0\xd3" + // 0x030D2 0x03099: 0x030D3
+ "\x00\xc3H\x06\x13@0\xd4" + // 0x030D2 0x0309A: 0x030D4
+ "\x00\xc3T\x06\x13 0\xd6" + // 0x030D5 0x03099: 0x030D6
+ "\x00\xc3T\x06\x13@0\xd7" + // 0x030D5 0x0309A: 0x030D7
+ "\x00\xc3`\x06\x13 0\xd9" + // 0x030D8 0x03099: 0x030D9
+ "\x00\xc3`\x06\x13@0\xda" + // 0x030D8 0x0309A: 0x030DA
+ "\x00\xc3l\x06\x13 0\xdc" + // 0x030DB 0x03099: 0x030DC
+ "\x00\xc3l\x06\x13@0\xdd" + // 0x030DB 0x0309A: 0x030DD
+ "\x00\u0098\x06\x13 0\xf4" + // 0x030A6 0x03099: 0x030F4
+ "\x00ü\x06\x13 0\xf7" + // 0x030EF 0x03099: 0x030F7
+ "\x00\xc3\xc0\x06\x13 0\xf8" + // 0x030F0 0x03099: 0x030F8
+ "\x00\xc3\xc4\x06\x13 0\xf9" + // 0x030F1 0x03099: 0x030F9
+ "\x00\xc3\xc8\x06\x13 0\xfa" + // 0x030F2 0x03099: 0x030FA
+ "\x00\xc3\xf4\x06\x13 0\xfe" + // 0x030FD 0x03099: 0x030FE
+ "\x04Bd\"\x17A\x10\x9a" + // 0x11099 0x110BA: 0x1109A
+ "\x04Bl\"\x17A\x10\x9c" + // 0x1109B 0x110BA: 0x1109C
+ "\x04B\x94\"\x17A\x10\xab" + // 0x110A5 0x110BA: 0x110AB
+ "\x04D\xc4\"$\xe1\x11." + // 0x11131 0x11127: 0x1112E
+ "\x04D\xc8\"$\xe1\x11/" + // 0x11132 0x11127: 0x1112F
+ "\x04M\x1c\"g\xc1\x13K" + // 0x11347 0x1133E: 0x1134B
+ "\x04M\x1c\"j\xe1\x13L" + // 0x11347 0x11357: 0x1134C
+ "\x04R\xe4\"\x97A\x14\xbb" + // 0x114B9 0x114BA: 0x114BB
+ "\x04R\xe4\"\x96\x01\x14\xbc" + // 0x114B9 0x114B0: 0x114BC
+ "\x04R\xe4\"\x97\xa1\x14\xbe" + // 0x114B9 0x114BD: 0x114BE
+ "\x04V\xe0\"\xb5\xe1\x15\xba" + // 0x115B8 0x115AF: 0x115BA
+ "\x04V\xe4\"\xb5\xe1\x15\xbb" + // 0x115B9 0x115AF: 0x115BB
+ "\x04d\xd4#&\x01\x198" + // 0x11935 0x11930: 0x11938
""
// Total size of tables: 56KB (57068 bytes)
diff --git a/vendor/golang.org/x/text/unicode/norm/tables17.0.0.go b/vendor/golang.org/x/text/unicode/norm/tables17.0.0.go
index dfd555f..c323189 100644
--- a/vendor/golang.org/x/text/unicode/norm/tables17.0.0.go
+++ b/vendor/golang.org/x/text/unicode/norm/tables17.0.0.go
@@ -7135,970 +7135,970 @@ var nfkcSparseValues = [980]valueRange{
}
// recompMap: 7688 bytes (entries only)
-var recompMap map[uint32]rune
+var recompMap map[uint64]rune
var recompMapOnce sync.Once
const recompMapPacked = "" +
- "\x00A\x03\x00\x00\x00\x00\xc0" + // 0x00410300: 0x000000C0
- "\x00A\x03\x01\x00\x00\x00\xc1" + // 0x00410301: 0x000000C1
- "\x00A\x03\x02\x00\x00\x00\xc2" + // 0x00410302: 0x000000C2
- "\x00A\x03\x03\x00\x00\x00\xc3" + // 0x00410303: 0x000000C3
- "\x00A\x03\b\x00\x00\x00\xc4" + // 0x00410308: 0x000000C4
- "\x00A\x03\n\x00\x00\x00\xc5" + // 0x0041030A: 0x000000C5
- "\x00C\x03'\x00\x00\x00\xc7" + // 0x00430327: 0x000000C7
- "\x00E\x03\x00\x00\x00\x00\xc8" + // 0x00450300: 0x000000C8
- "\x00E\x03\x01\x00\x00\x00\xc9" + // 0x00450301: 0x000000C9
- "\x00E\x03\x02\x00\x00\x00\xca" + // 0x00450302: 0x000000CA
- "\x00E\x03\b\x00\x00\x00\xcb" + // 0x00450308: 0x000000CB
- "\x00I\x03\x00\x00\x00\x00\xcc" + // 0x00490300: 0x000000CC
- "\x00I\x03\x01\x00\x00\x00\xcd" + // 0x00490301: 0x000000CD
- "\x00I\x03\x02\x00\x00\x00\xce" + // 0x00490302: 0x000000CE
- "\x00I\x03\b\x00\x00\x00\xcf" + // 0x00490308: 0x000000CF
- "\x00N\x03\x03\x00\x00\x00\xd1" + // 0x004E0303: 0x000000D1
- "\x00O\x03\x00\x00\x00\x00\xd2" + // 0x004F0300: 0x000000D2
- "\x00O\x03\x01\x00\x00\x00\xd3" + // 0x004F0301: 0x000000D3
- "\x00O\x03\x02\x00\x00\x00\xd4" + // 0x004F0302: 0x000000D4
- "\x00O\x03\x03\x00\x00\x00\xd5" + // 0x004F0303: 0x000000D5
- "\x00O\x03\b\x00\x00\x00\xd6" + // 0x004F0308: 0x000000D6
- "\x00U\x03\x00\x00\x00\x00\xd9" + // 0x00550300: 0x000000D9
- "\x00U\x03\x01\x00\x00\x00\xda" + // 0x00550301: 0x000000DA
- "\x00U\x03\x02\x00\x00\x00\xdb" + // 0x00550302: 0x000000DB
- "\x00U\x03\b\x00\x00\x00\xdc" + // 0x00550308: 0x000000DC
- "\x00Y\x03\x01\x00\x00\x00\xdd" + // 0x00590301: 0x000000DD
- "\x00a\x03\x00\x00\x00\x00\xe0" + // 0x00610300: 0x000000E0
- "\x00a\x03\x01\x00\x00\x00\xe1" + // 0x00610301: 0x000000E1
- "\x00a\x03\x02\x00\x00\x00\xe2" + // 0x00610302: 0x000000E2
- "\x00a\x03\x03\x00\x00\x00\xe3" + // 0x00610303: 0x000000E3
- "\x00a\x03\b\x00\x00\x00\xe4" + // 0x00610308: 0x000000E4
- "\x00a\x03\n\x00\x00\x00\xe5" + // 0x0061030A: 0x000000E5
- "\x00c\x03'\x00\x00\x00\xe7" + // 0x00630327: 0x000000E7
- "\x00e\x03\x00\x00\x00\x00\xe8" + // 0x00650300: 0x000000E8
- "\x00e\x03\x01\x00\x00\x00\xe9" + // 0x00650301: 0x000000E9
- "\x00e\x03\x02\x00\x00\x00\xea" + // 0x00650302: 0x000000EA
- "\x00e\x03\b\x00\x00\x00\xeb" + // 0x00650308: 0x000000EB
- "\x00i\x03\x00\x00\x00\x00\xec" + // 0x00690300: 0x000000EC
- "\x00i\x03\x01\x00\x00\x00\xed" + // 0x00690301: 0x000000ED
- "\x00i\x03\x02\x00\x00\x00\xee" + // 0x00690302: 0x000000EE
- "\x00i\x03\b\x00\x00\x00\xef" + // 0x00690308: 0x000000EF
- "\x00n\x03\x03\x00\x00\x00\xf1" + // 0x006E0303: 0x000000F1
- "\x00o\x03\x00\x00\x00\x00\xf2" + // 0x006F0300: 0x000000F2
- "\x00o\x03\x01\x00\x00\x00\xf3" + // 0x006F0301: 0x000000F3
- "\x00o\x03\x02\x00\x00\x00\xf4" + // 0x006F0302: 0x000000F4
- "\x00o\x03\x03\x00\x00\x00\xf5" + // 0x006F0303: 0x000000F5
- "\x00o\x03\b\x00\x00\x00\xf6" + // 0x006F0308: 0x000000F6
- "\x00u\x03\x00\x00\x00\x00\xf9" + // 0x00750300: 0x000000F9
- "\x00u\x03\x01\x00\x00\x00\xfa" + // 0x00750301: 0x000000FA
- "\x00u\x03\x02\x00\x00\x00\xfb" + // 0x00750302: 0x000000FB
- "\x00u\x03\b\x00\x00\x00\xfc" + // 0x00750308: 0x000000FC
- "\x00y\x03\x01\x00\x00\x00\xfd" + // 0x00790301: 0x000000FD
- "\x00y\x03\b\x00\x00\x00\xff" + // 0x00790308: 0x000000FF
- "\x00A\x03\x04\x00\x00\x01\x00" + // 0x00410304: 0x00000100
- "\x00a\x03\x04\x00\x00\x01\x01" + // 0x00610304: 0x00000101
- "\x00A\x03\x06\x00\x00\x01\x02" + // 0x00410306: 0x00000102
- "\x00a\x03\x06\x00\x00\x01\x03" + // 0x00610306: 0x00000103
- "\x00A\x03(\x00\x00\x01\x04" + // 0x00410328: 0x00000104
- "\x00a\x03(\x00\x00\x01\x05" + // 0x00610328: 0x00000105
- "\x00C\x03\x01\x00\x00\x01\x06" + // 0x00430301: 0x00000106
- "\x00c\x03\x01\x00\x00\x01\a" + // 0x00630301: 0x00000107
- "\x00C\x03\x02\x00\x00\x01\b" + // 0x00430302: 0x00000108
- "\x00c\x03\x02\x00\x00\x01\t" + // 0x00630302: 0x00000109
- "\x00C\x03\a\x00\x00\x01\n" + // 0x00430307: 0x0000010A
- "\x00c\x03\a\x00\x00\x01\v" + // 0x00630307: 0x0000010B
- "\x00C\x03\f\x00\x00\x01\f" + // 0x0043030C: 0x0000010C
- "\x00c\x03\f\x00\x00\x01\r" + // 0x0063030C: 0x0000010D
- "\x00D\x03\f\x00\x00\x01\x0e" + // 0x0044030C: 0x0000010E
- "\x00d\x03\f\x00\x00\x01\x0f" + // 0x0064030C: 0x0000010F
- "\x00E\x03\x04\x00\x00\x01\x12" + // 0x00450304: 0x00000112
- "\x00e\x03\x04\x00\x00\x01\x13" + // 0x00650304: 0x00000113
- "\x00E\x03\x06\x00\x00\x01\x14" + // 0x00450306: 0x00000114
- "\x00e\x03\x06\x00\x00\x01\x15" + // 0x00650306: 0x00000115
- "\x00E\x03\a\x00\x00\x01\x16" + // 0x00450307: 0x00000116
- "\x00e\x03\a\x00\x00\x01\x17" + // 0x00650307: 0x00000117
- "\x00E\x03(\x00\x00\x01\x18" + // 0x00450328: 0x00000118
- "\x00e\x03(\x00\x00\x01\x19" + // 0x00650328: 0x00000119
- "\x00E\x03\f\x00\x00\x01\x1a" + // 0x0045030C: 0x0000011A
- "\x00e\x03\f\x00\x00\x01\x1b" + // 0x0065030C: 0x0000011B
- "\x00G\x03\x02\x00\x00\x01\x1c" + // 0x00470302: 0x0000011C
- "\x00g\x03\x02\x00\x00\x01\x1d" + // 0x00670302: 0x0000011D
- "\x00G\x03\x06\x00\x00\x01\x1e" + // 0x00470306: 0x0000011E
- "\x00g\x03\x06\x00\x00\x01\x1f" + // 0x00670306: 0x0000011F
- "\x00G\x03\a\x00\x00\x01 " + // 0x00470307: 0x00000120
- "\x00g\x03\a\x00\x00\x01!" + // 0x00670307: 0x00000121
- "\x00G\x03'\x00\x00\x01\"" + // 0x00470327: 0x00000122
- "\x00g\x03'\x00\x00\x01#" + // 0x00670327: 0x00000123
- "\x00H\x03\x02\x00\x00\x01$" + // 0x00480302: 0x00000124
- "\x00h\x03\x02\x00\x00\x01%" + // 0x00680302: 0x00000125
- "\x00I\x03\x03\x00\x00\x01(" + // 0x00490303: 0x00000128
- "\x00i\x03\x03\x00\x00\x01)" + // 0x00690303: 0x00000129
- "\x00I\x03\x04\x00\x00\x01*" + // 0x00490304: 0x0000012A
- "\x00i\x03\x04\x00\x00\x01+" + // 0x00690304: 0x0000012B
- "\x00I\x03\x06\x00\x00\x01," + // 0x00490306: 0x0000012C
- "\x00i\x03\x06\x00\x00\x01-" + // 0x00690306: 0x0000012D
- "\x00I\x03(\x00\x00\x01." + // 0x00490328: 0x0000012E
- "\x00i\x03(\x00\x00\x01/" + // 0x00690328: 0x0000012F
- "\x00I\x03\a\x00\x00\x010" + // 0x00490307: 0x00000130
- "\x00J\x03\x02\x00\x00\x014" + // 0x004A0302: 0x00000134
- "\x00j\x03\x02\x00\x00\x015" + // 0x006A0302: 0x00000135
- "\x00K\x03'\x00\x00\x016" + // 0x004B0327: 0x00000136
- "\x00k\x03'\x00\x00\x017" + // 0x006B0327: 0x00000137
- "\x00L\x03\x01\x00\x00\x019" + // 0x004C0301: 0x00000139
- "\x00l\x03\x01\x00\x00\x01:" + // 0x006C0301: 0x0000013A
- "\x00L\x03'\x00\x00\x01;" + // 0x004C0327: 0x0000013B
- "\x00l\x03'\x00\x00\x01<" + // 0x006C0327: 0x0000013C
- "\x00L\x03\f\x00\x00\x01=" + // 0x004C030C: 0x0000013D
- "\x00l\x03\f\x00\x00\x01>" + // 0x006C030C: 0x0000013E
- "\x00N\x03\x01\x00\x00\x01C" + // 0x004E0301: 0x00000143
- "\x00n\x03\x01\x00\x00\x01D" + // 0x006E0301: 0x00000144
- "\x00N\x03'\x00\x00\x01E" + // 0x004E0327: 0x00000145
- "\x00n\x03'\x00\x00\x01F" + // 0x006E0327: 0x00000146
- "\x00N\x03\f\x00\x00\x01G" + // 0x004E030C: 0x00000147
- "\x00n\x03\f\x00\x00\x01H" + // 0x006E030C: 0x00000148
- "\x00O\x03\x04\x00\x00\x01L" + // 0x004F0304: 0x0000014C
- "\x00o\x03\x04\x00\x00\x01M" + // 0x006F0304: 0x0000014D
- "\x00O\x03\x06\x00\x00\x01N" + // 0x004F0306: 0x0000014E
- "\x00o\x03\x06\x00\x00\x01O" + // 0x006F0306: 0x0000014F
- "\x00O\x03\v\x00\x00\x01P" + // 0x004F030B: 0x00000150
- "\x00o\x03\v\x00\x00\x01Q" + // 0x006F030B: 0x00000151
- "\x00R\x03\x01\x00\x00\x01T" + // 0x00520301: 0x00000154
- "\x00r\x03\x01\x00\x00\x01U" + // 0x00720301: 0x00000155
- "\x00R\x03'\x00\x00\x01V" + // 0x00520327: 0x00000156
- "\x00r\x03'\x00\x00\x01W" + // 0x00720327: 0x00000157
- "\x00R\x03\f\x00\x00\x01X" + // 0x0052030C: 0x00000158
- "\x00r\x03\f\x00\x00\x01Y" + // 0x0072030C: 0x00000159
- "\x00S\x03\x01\x00\x00\x01Z" + // 0x00530301: 0x0000015A
- "\x00s\x03\x01\x00\x00\x01[" + // 0x00730301: 0x0000015B
- "\x00S\x03\x02\x00\x00\x01\\" + // 0x00530302: 0x0000015C
- "\x00s\x03\x02\x00\x00\x01]" + // 0x00730302: 0x0000015D
- "\x00S\x03'\x00\x00\x01^" + // 0x00530327: 0x0000015E
- "\x00s\x03'\x00\x00\x01_" + // 0x00730327: 0x0000015F
- "\x00S\x03\f\x00\x00\x01`" + // 0x0053030C: 0x00000160
- "\x00s\x03\f\x00\x00\x01a" + // 0x0073030C: 0x00000161
- "\x00T\x03'\x00\x00\x01b" + // 0x00540327: 0x00000162
- "\x00t\x03'\x00\x00\x01c" + // 0x00740327: 0x00000163
- "\x00T\x03\f\x00\x00\x01d" + // 0x0054030C: 0x00000164
- "\x00t\x03\f\x00\x00\x01e" + // 0x0074030C: 0x00000165
- "\x00U\x03\x03\x00\x00\x01h" + // 0x00550303: 0x00000168
- "\x00u\x03\x03\x00\x00\x01i" + // 0x00750303: 0x00000169
- "\x00U\x03\x04\x00\x00\x01j" + // 0x00550304: 0x0000016A
- "\x00u\x03\x04\x00\x00\x01k" + // 0x00750304: 0x0000016B
- "\x00U\x03\x06\x00\x00\x01l" + // 0x00550306: 0x0000016C
- "\x00u\x03\x06\x00\x00\x01m" + // 0x00750306: 0x0000016D
- "\x00U\x03\n\x00\x00\x01n" + // 0x0055030A: 0x0000016E
- "\x00u\x03\n\x00\x00\x01o" + // 0x0075030A: 0x0000016F
- "\x00U\x03\v\x00\x00\x01p" + // 0x0055030B: 0x00000170
- "\x00u\x03\v\x00\x00\x01q" + // 0x0075030B: 0x00000171
- "\x00U\x03(\x00\x00\x01r" + // 0x00550328: 0x00000172
- "\x00u\x03(\x00\x00\x01s" + // 0x00750328: 0x00000173
- "\x00W\x03\x02\x00\x00\x01t" + // 0x00570302: 0x00000174
- "\x00w\x03\x02\x00\x00\x01u" + // 0x00770302: 0x00000175
- "\x00Y\x03\x02\x00\x00\x01v" + // 0x00590302: 0x00000176
- "\x00y\x03\x02\x00\x00\x01w" + // 0x00790302: 0x00000177
- "\x00Y\x03\b\x00\x00\x01x" + // 0x00590308: 0x00000178
- "\x00Z\x03\x01\x00\x00\x01y" + // 0x005A0301: 0x00000179
- "\x00z\x03\x01\x00\x00\x01z" + // 0x007A0301: 0x0000017A
- "\x00Z\x03\a\x00\x00\x01{" + // 0x005A0307: 0x0000017B
- "\x00z\x03\a\x00\x00\x01|" + // 0x007A0307: 0x0000017C
- "\x00Z\x03\f\x00\x00\x01}" + // 0x005A030C: 0x0000017D
- "\x00z\x03\f\x00\x00\x01~" + // 0x007A030C: 0x0000017E
- "\x00O\x03\x1b\x00\x00\x01\xa0" + // 0x004F031B: 0x000001A0
- "\x00o\x03\x1b\x00\x00\x01\xa1" + // 0x006F031B: 0x000001A1
- "\x00U\x03\x1b\x00\x00\x01\xaf" + // 0x0055031B: 0x000001AF
- "\x00u\x03\x1b\x00\x00\x01\xb0" + // 0x0075031B: 0x000001B0
- "\x00A\x03\f\x00\x00\x01\xcd" + // 0x0041030C: 0x000001CD
- "\x00a\x03\f\x00\x00\x01\xce" + // 0x0061030C: 0x000001CE
- "\x00I\x03\f\x00\x00\x01\xcf" + // 0x0049030C: 0x000001CF
- "\x00i\x03\f\x00\x00\x01\xd0" + // 0x0069030C: 0x000001D0
- "\x00O\x03\f\x00\x00\x01\xd1" + // 0x004F030C: 0x000001D1
- "\x00o\x03\f\x00\x00\x01\xd2" + // 0x006F030C: 0x000001D2
- "\x00U\x03\f\x00\x00\x01\xd3" + // 0x0055030C: 0x000001D3
- "\x00u\x03\f\x00\x00\x01\xd4" + // 0x0075030C: 0x000001D4
- "\x00\xdc\x03\x04\x00\x00\x01\xd5" + // 0x00DC0304: 0x000001D5
- "\x00\xfc\x03\x04\x00\x00\x01\xd6" + // 0x00FC0304: 0x000001D6
- "\x00\xdc\x03\x01\x00\x00\x01\xd7" + // 0x00DC0301: 0x000001D7
- "\x00\xfc\x03\x01\x00\x00\x01\xd8" + // 0x00FC0301: 0x000001D8
- "\x00\xdc\x03\f\x00\x00\x01\xd9" + // 0x00DC030C: 0x000001D9
- "\x00\xfc\x03\f\x00\x00\x01\xda" + // 0x00FC030C: 0x000001DA
- "\x00\xdc\x03\x00\x00\x00\x01\xdb" + // 0x00DC0300: 0x000001DB
- "\x00\xfc\x03\x00\x00\x00\x01\xdc" + // 0x00FC0300: 0x000001DC
- "\x00\xc4\x03\x04\x00\x00\x01\xde" + // 0x00C40304: 0x000001DE
- "\x00\xe4\x03\x04\x00\x00\x01\xdf" + // 0x00E40304: 0x000001DF
- "\x02&\x03\x04\x00\x00\x01\xe0" + // 0x02260304: 0x000001E0
- "\x02'\x03\x04\x00\x00\x01\xe1" + // 0x02270304: 0x000001E1
- "\x00\xc6\x03\x04\x00\x00\x01\xe2" + // 0x00C60304: 0x000001E2
- "\x00\xe6\x03\x04\x00\x00\x01\xe3" + // 0x00E60304: 0x000001E3
- "\x00G\x03\f\x00\x00\x01\xe6" + // 0x0047030C: 0x000001E6
- "\x00g\x03\f\x00\x00\x01\xe7" + // 0x0067030C: 0x000001E7
- "\x00K\x03\f\x00\x00\x01\xe8" + // 0x004B030C: 0x000001E8
- "\x00k\x03\f\x00\x00\x01\xe9" + // 0x006B030C: 0x000001E9
- "\x00O\x03(\x00\x00\x01\xea" + // 0x004F0328: 0x000001EA
- "\x00o\x03(\x00\x00\x01\xeb" + // 0x006F0328: 0x000001EB
- "\x01\xea\x03\x04\x00\x00\x01\xec" + // 0x01EA0304: 0x000001EC
- "\x01\xeb\x03\x04\x00\x00\x01\xed" + // 0x01EB0304: 0x000001ED
- "\x01\xb7\x03\f\x00\x00\x01\xee" + // 0x01B7030C: 0x000001EE
- "\x02\x92\x03\f\x00\x00\x01\xef" + // 0x0292030C: 0x000001EF
- "\x00j\x03\f\x00\x00\x01\xf0" + // 0x006A030C: 0x000001F0
- "\x00G\x03\x01\x00\x00\x01\xf4" + // 0x00470301: 0x000001F4
- "\x00g\x03\x01\x00\x00\x01\xf5" + // 0x00670301: 0x000001F5
- "\x00N\x03\x00\x00\x00\x01\xf8" + // 0x004E0300: 0x000001F8
- "\x00n\x03\x00\x00\x00\x01\xf9" + // 0x006E0300: 0x000001F9
- "\x00\xc5\x03\x01\x00\x00\x01\xfa" + // 0x00C50301: 0x000001FA
- "\x00\xe5\x03\x01\x00\x00\x01\xfb" + // 0x00E50301: 0x000001FB
- "\x00\xc6\x03\x01\x00\x00\x01\xfc" + // 0x00C60301: 0x000001FC
- "\x00\xe6\x03\x01\x00\x00\x01\xfd" + // 0x00E60301: 0x000001FD
- "\x00\xd8\x03\x01\x00\x00\x01\xfe" + // 0x00D80301: 0x000001FE
- "\x00\xf8\x03\x01\x00\x00\x01\xff" + // 0x00F80301: 0x000001FF
- "\x00A\x03\x0f\x00\x00\x02\x00" + // 0x0041030F: 0x00000200
- "\x00a\x03\x0f\x00\x00\x02\x01" + // 0x0061030F: 0x00000201
- "\x00A\x03\x11\x00\x00\x02\x02" + // 0x00410311: 0x00000202
- "\x00a\x03\x11\x00\x00\x02\x03" + // 0x00610311: 0x00000203
- "\x00E\x03\x0f\x00\x00\x02\x04" + // 0x0045030F: 0x00000204
- "\x00e\x03\x0f\x00\x00\x02\x05" + // 0x0065030F: 0x00000205
- "\x00E\x03\x11\x00\x00\x02\x06" + // 0x00450311: 0x00000206
- "\x00e\x03\x11\x00\x00\x02\a" + // 0x00650311: 0x00000207
- "\x00I\x03\x0f\x00\x00\x02\b" + // 0x0049030F: 0x00000208
- "\x00i\x03\x0f\x00\x00\x02\t" + // 0x0069030F: 0x00000209
- "\x00I\x03\x11\x00\x00\x02\n" + // 0x00490311: 0x0000020A
- "\x00i\x03\x11\x00\x00\x02\v" + // 0x00690311: 0x0000020B
- "\x00O\x03\x0f\x00\x00\x02\f" + // 0x004F030F: 0x0000020C
- "\x00o\x03\x0f\x00\x00\x02\r" + // 0x006F030F: 0x0000020D
- "\x00O\x03\x11\x00\x00\x02\x0e" + // 0x004F0311: 0x0000020E
- "\x00o\x03\x11\x00\x00\x02\x0f" + // 0x006F0311: 0x0000020F
- "\x00R\x03\x0f\x00\x00\x02\x10" + // 0x0052030F: 0x00000210
- "\x00r\x03\x0f\x00\x00\x02\x11" + // 0x0072030F: 0x00000211
- "\x00R\x03\x11\x00\x00\x02\x12" + // 0x00520311: 0x00000212
- "\x00r\x03\x11\x00\x00\x02\x13" + // 0x00720311: 0x00000213
- "\x00U\x03\x0f\x00\x00\x02\x14" + // 0x0055030F: 0x00000214
- "\x00u\x03\x0f\x00\x00\x02\x15" + // 0x0075030F: 0x00000215
- "\x00U\x03\x11\x00\x00\x02\x16" + // 0x00550311: 0x00000216
- "\x00u\x03\x11\x00\x00\x02\x17" + // 0x00750311: 0x00000217
- "\x00S\x03&\x00\x00\x02\x18" + // 0x00530326: 0x00000218
- "\x00s\x03&\x00\x00\x02\x19" + // 0x00730326: 0x00000219
- "\x00T\x03&\x00\x00\x02\x1a" + // 0x00540326: 0x0000021A
- "\x00t\x03&\x00\x00\x02\x1b" + // 0x00740326: 0x0000021B
- "\x00H\x03\f\x00\x00\x02\x1e" + // 0x0048030C: 0x0000021E
- "\x00h\x03\f\x00\x00\x02\x1f" + // 0x0068030C: 0x0000021F
- "\x00A\x03\a\x00\x00\x02&" + // 0x00410307: 0x00000226
- "\x00a\x03\a\x00\x00\x02'" + // 0x00610307: 0x00000227
- "\x00E\x03'\x00\x00\x02(" + // 0x00450327: 0x00000228
- "\x00e\x03'\x00\x00\x02)" + // 0x00650327: 0x00000229
- "\x00\xd6\x03\x04\x00\x00\x02*" + // 0x00D60304: 0x0000022A
- "\x00\xf6\x03\x04\x00\x00\x02+" + // 0x00F60304: 0x0000022B
- "\x00\xd5\x03\x04\x00\x00\x02," + // 0x00D50304: 0x0000022C
- "\x00\xf5\x03\x04\x00\x00\x02-" + // 0x00F50304: 0x0000022D
- "\x00O\x03\a\x00\x00\x02." + // 0x004F0307: 0x0000022E
- "\x00o\x03\a\x00\x00\x02/" + // 0x006F0307: 0x0000022F
- "\x02.\x03\x04\x00\x00\x020" + // 0x022E0304: 0x00000230
- "\x02/\x03\x04\x00\x00\x021" + // 0x022F0304: 0x00000231
- "\x00Y\x03\x04\x00\x00\x022" + // 0x00590304: 0x00000232
- "\x00y\x03\x04\x00\x00\x023" + // 0x00790304: 0x00000233
- "\x00\xa8\x03\x01\x00\x00\x03\x85" + // 0x00A80301: 0x00000385
- "\x03\x91\x03\x01\x00\x00\x03\x86" + // 0x03910301: 0x00000386
- "\x03\x95\x03\x01\x00\x00\x03\x88" + // 0x03950301: 0x00000388
- "\x03\x97\x03\x01\x00\x00\x03\x89" + // 0x03970301: 0x00000389
- "\x03\x99\x03\x01\x00\x00\x03\x8a" + // 0x03990301: 0x0000038A
- "\x03\x9f\x03\x01\x00\x00\x03\x8c" + // 0x039F0301: 0x0000038C
- "\x03\xa5\x03\x01\x00\x00\x03\x8e" + // 0x03A50301: 0x0000038E
- "\x03\xa9\x03\x01\x00\x00\x03\x8f" + // 0x03A90301: 0x0000038F
- "\x03\xca\x03\x01\x00\x00\x03\x90" + // 0x03CA0301: 0x00000390
- "\x03\x99\x03\b\x00\x00\x03\xaa" + // 0x03990308: 0x000003AA
- "\x03\xa5\x03\b\x00\x00\x03\xab" + // 0x03A50308: 0x000003AB
- "\x03\xb1\x03\x01\x00\x00\x03\xac" + // 0x03B10301: 0x000003AC
- "\x03\xb5\x03\x01\x00\x00\x03\xad" + // 0x03B50301: 0x000003AD
- "\x03\xb7\x03\x01\x00\x00\x03\xae" + // 0x03B70301: 0x000003AE
- "\x03\xb9\x03\x01\x00\x00\x03\xaf" + // 0x03B90301: 0x000003AF
- "\x03\xcb\x03\x01\x00\x00\x03\xb0" + // 0x03CB0301: 0x000003B0
- "\x03\xb9\x03\b\x00\x00\x03\xca" + // 0x03B90308: 0x000003CA
- "\x03\xc5\x03\b\x00\x00\x03\xcb" + // 0x03C50308: 0x000003CB
- "\x03\xbf\x03\x01\x00\x00\x03\xcc" + // 0x03BF0301: 0x000003CC
- "\x03\xc5\x03\x01\x00\x00\x03\xcd" + // 0x03C50301: 0x000003CD
- "\x03\xc9\x03\x01\x00\x00\x03\xce" + // 0x03C90301: 0x000003CE
- "\x03\xd2\x03\x01\x00\x00\x03\xd3" + // 0x03D20301: 0x000003D3
- "\x03\xd2\x03\b\x00\x00\x03\xd4" + // 0x03D20308: 0x000003D4
- "\x04\x15\x03\x00\x00\x00\x04\x00" + // 0x04150300: 0x00000400
- "\x04\x15\x03\b\x00\x00\x04\x01" + // 0x04150308: 0x00000401
- "\x04\x13\x03\x01\x00\x00\x04\x03" + // 0x04130301: 0x00000403
- "\x04\x06\x03\b\x00\x00\x04\a" + // 0x04060308: 0x00000407
- "\x04\x1a\x03\x01\x00\x00\x04\f" + // 0x041A0301: 0x0000040C
- "\x04\x18\x03\x00\x00\x00\x04\r" + // 0x04180300: 0x0000040D
- "\x04#\x03\x06\x00\x00\x04\x0e" + // 0x04230306: 0x0000040E
- "\x04\x18\x03\x06\x00\x00\x04\x19" + // 0x04180306: 0x00000419
- "\x048\x03\x06\x00\x00\x049" + // 0x04380306: 0x00000439
- "\x045\x03\x00\x00\x00\x04P" + // 0x04350300: 0x00000450
- "\x045\x03\b\x00\x00\x04Q" + // 0x04350308: 0x00000451
- "\x043\x03\x01\x00\x00\x04S" + // 0x04330301: 0x00000453
- "\x04V\x03\b\x00\x00\x04W" + // 0x04560308: 0x00000457
- "\x04:\x03\x01\x00\x00\x04\\" + // 0x043A0301: 0x0000045C
- "\x048\x03\x00\x00\x00\x04]" + // 0x04380300: 0x0000045D
- "\x04C\x03\x06\x00\x00\x04^" + // 0x04430306: 0x0000045E
- "\x04t\x03\x0f\x00\x00\x04v" + // 0x0474030F: 0x00000476
- "\x04u\x03\x0f\x00\x00\x04w" + // 0x0475030F: 0x00000477
- "\x04\x16\x03\x06\x00\x00\x04\xc1" + // 0x04160306: 0x000004C1
- "\x046\x03\x06\x00\x00\x04\xc2" + // 0x04360306: 0x000004C2
- "\x04\x10\x03\x06\x00\x00\x04\xd0" + // 0x04100306: 0x000004D0
- "\x040\x03\x06\x00\x00\x04\xd1" + // 0x04300306: 0x000004D1
- "\x04\x10\x03\b\x00\x00\x04\xd2" + // 0x04100308: 0x000004D2
- "\x040\x03\b\x00\x00\x04\xd3" + // 0x04300308: 0x000004D3
- "\x04\x15\x03\x06\x00\x00\x04\xd6" + // 0x04150306: 0x000004D6
- "\x045\x03\x06\x00\x00\x04\xd7" + // 0x04350306: 0x000004D7
- "\x04\xd8\x03\b\x00\x00\x04\xda" + // 0x04D80308: 0x000004DA
- "\x04\xd9\x03\b\x00\x00\x04\xdb" + // 0x04D90308: 0x000004DB
- "\x04\x16\x03\b\x00\x00\x04\xdc" + // 0x04160308: 0x000004DC
- "\x046\x03\b\x00\x00\x04\xdd" + // 0x04360308: 0x000004DD
- "\x04\x17\x03\b\x00\x00\x04\xde" + // 0x04170308: 0x000004DE
- "\x047\x03\b\x00\x00\x04\xdf" + // 0x04370308: 0x000004DF
- "\x04\x18\x03\x04\x00\x00\x04\xe2" + // 0x04180304: 0x000004E2
- "\x048\x03\x04\x00\x00\x04\xe3" + // 0x04380304: 0x000004E3
- "\x04\x18\x03\b\x00\x00\x04\xe4" + // 0x04180308: 0x000004E4
- "\x048\x03\b\x00\x00\x04\xe5" + // 0x04380308: 0x000004E5
- "\x04\x1e\x03\b\x00\x00\x04\xe6" + // 0x041E0308: 0x000004E6
- "\x04>\x03\b\x00\x00\x04\xe7" + // 0x043E0308: 0x000004E7
- "\x04\xe8\x03\b\x00\x00\x04\xea" + // 0x04E80308: 0x000004EA
- "\x04\xe9\x03\b\x00\x00\x04\xeb" + // 0x04E90308: 0x000004EB
- "\x04-\x03\b\x00\x00\x04\xec" + // 0x042D0308: 0x000004EC
- "\x04M\x03\b\x00\x00\x04\xed" + // 0x044D0308: 0x000004ED
- "\x04#\x03\x04\x00\x00\x04\xee" + // 0x04230304: 0x000004EE
- "\x04C\x03\x04\x00\x00\x04\xef" + // 0x04430304: 0x000004EF
- "\x04#\x03\b\x00\x00\x04\xf0" + // 0x04230308: 0x000004F0
- "\x04C\x03\b\x00\x00\x04\xf1" + // 0x04430308: 0x000004F1
- "\x04#\x03\v\x00\x00\x04\xf2" + // 0x0423030B: 0x000004F2
- "\x04C\x03\v\x00\x00\x04\xf3" + // 0x0443030B: 0x000004F3
- "\x04'\x03\b\x00\x00\x04\xf4" + // 0x04270308: 0x000004F4
- "\x04G\x03\b\x00\x00\x04\xf5" + // 0x04470308: 0x000004F5
- "\x04+\x03\b\x00\x00\x04\xf8" + // 0x042B0308: 0x000004F8
- "\x04K\x03\b\x00\x00\x04\xf9" + // 0x044B0308: 0x000004F9
- "\x06'\x06S\x00\x00\x06\"" + // 0x06270653: 0x00000622
- "\x06'\x06T\x00\x00\x06#" + // 0x06270654: 0x00000623
- "\x06H\x06T\x00\x00\x06$" + // 0x06480654: 0x00000624
- "\x06'\x06U\x00\x00\x06%" + // 0x06270655: 0x00000625
- "\x06J\x06T\x00\x00\x06&" + // 0x064A0654: 0x00000626
- "\x06\xd5\x06T\x00\x00\x06\xc0" + // 0x06D50654: 0x000006C0
- "\x06\xc1\x06T\x00\x00\x06\xc2" + // 0x06C10654: 0x000006C2
- "\x06\xd2\x06T\x00\x00\x06\xd3" + // 0x06D20654: 0x000006D3
- "\t(\t<\x00\x00\t)" + // 0x0928093C: 0x00000929
- "\t0\t<\x00\x00\t1" + // 0x0930093C: 0x00000931
- "\t3\t<\x00\x00\t4" + // 0x0933093C: 0x00000934
- "\t\xc7\t\xbe\x00\x00\t\xcb" + // 0x09C709BE: 0x000009CB
- "\t\xc7\t\xd7\x00\x00\t\xcc" + // 0x09C709D7: 0x000009CC
- "\vG\vV\x00\x00\vH" + // 0x0B470B56: 0x00000B48
- "\vG\v>\x00\x00\vK" + // 0x0B470B3E: 0x00000B4B
- "\vG\vW\x00\x00\vL" + // 0x0B470B57: 0x00000B4C
- "\v\x92\v\xd7\x00\x00\v\x94" + // 0x0B920BD7: 0x00000B94
- "\v\xc6\v\xbe\x00\x00\v\xca" + // 0x0BC60BBE: 0x00000BCA
- "\v\xc7\v\xbe\x00\x00\v\xcb" + // 0x0BC70BBE: 0x00000BCB
- "\v\xc6\v\xd7\x00\x00\v\xcc" + // 0x0BC60BD7: 0x00000BCC
- "\fF\fV\x00\x00\fH" + // 0x0C460C56: 0x00000C48
- "\f\xbf\f\xd5\x00\x00\f\xc0" + // 0x0CBF0CD5: 0x00000CC0
- "\f\xc6\f\xd5\x00\x00\f\xc7" + // 0x0CC60CD5: 0x00000CC7
- "\f\xc6\f\xd6\x00\x00\f\xc8" + // 0x0CC60CD6: 0x00000CC8
- "\f\xc6\f\xc2\x00\x00\f\xca" + // 0x0CC60CC2: 0x00000CCA
- "\f\xca\f\xd5\x00\x00\f\xcb" + // 0x0CCA0CD5: 0x00000CCB
- "\rF\r>\x00\x00\rJ" + // 0x0D460D3E: 0x00000D4A
- "\rG\r>\x00\x00\rK" + // 0x0D470D3E: 0x00000D4B
- "\rF\rW\x00\x00\rL" + // 0x0D460D57: 0x00000D4C
- "\r\xd9\r\xca\x00\x00\r\xda" + // 0x0DD90DCA: 0x00000DDA
- "\r\xd9\r\xcf\x00\x00\r\xdc" + // 0x0DD90DCF: 0x00000DDC
- "\r\xdc\r\xca\x00\x00\r\xdd" + // 0x0DDC0DCA: 0x00000DDD
- "\r\xd9\r\xdf\x00\x00\r\xde" + // 0x0DD90DDF: 0x00000DDE
- "\x10%\x10.\x00\x00\x10&" + // 0x1025102E: 0x00001026
- "\x1b\x05\x1b5\x00\x00\x1b\x06" + // 0x1B051B35: 0x00001B06
- "\x1b\a\x1b5\x00\x00\x1b\b" + // 0x1B071B35: 0x00001B08
- "\x1b\t\x1b5\x00\x00\x1b\n" + // 0x1B091B35: 0x00001B0A
- "\x1b\v\x1b5\x00\x00\x1b\f" + // 0x1B0B1B35: 0x00001B0C
- "\x1b\r\x1b5\x00\x00\x1b\x0e" + // 0x1B0D1B35: 0x00001B0E
- "\x1b\x11\x1b5\x00\x00\x1b\x12" + // 0x1B111B35: 0x00001B12
- "\x1b:\x1b5\x00\x00\x1b;" + // 0x1B3A1B35: 0x00001B3B
- "\x1b<\x1b5\x00\x00\x1b=" + // 0x1B3C1B35: 0x00001B3D
- "\x1b>\x1b5\x00\x00\x1b@" + // 0x1B3E1B35: 0x00001B40
- "\x1b?\x1b5\x00\x00\x1bA" + // 0x1B3F1B35: 0x00001B41
- "\x1bB\x1b5\x00\x00\x1bC" + // 0x1B421B35: 0x00001B43
- "\x00A\x03%\x00\x00\x1e\x00" + // 0x00410325: 0x00001E00
- "\x00a\x03%\x00\x00\x1e\x01" + // 0x00610325: 0x00001E01
- "\x00B\x03\a\x00\x00\x1e\x02" + // 0x00420307: 0x00001E02
- "\x00b\x03\a\x00\x00\x1e\x03" + // 0x00620307: 0x00001E03
- "\x00B\x03#\x00\x00\x1e\x04" + // 0x00420323: 0x00001E04
- "\x00b\x03#\x00\x00\x1e\x05" + // 0x00620323: 0x00001E05
- "\x00B\x031\x00\x00\x1e\x06" + // 0x00420331: 0x00001E06
- "\x00b\x031\x00\x00\x1e\a" + // 0x00620331: 0x00001E07
- "\x00\xc7\x03\x01\x00\x00\x1e\b" + // 0x00C70301: 0x00001E08
- "\x00\xe7\x03\x01\x00\x00\x1e\t" + // 0x00E70301: 0x00001E09
- "\x00D\x03\a\x00\x00\x1e\n" + // 0x00440307: 0x00001E0A
- "\x00d\x03\a\x00\x00\x1e\v" + // 0x00640307: 0x00001E0B
- "\x00D\x03#\x00\x00\x1e\f" + // 0x00440323: 0x00001E0C
- "\x00d\x03#\x00\x00\x1e\r" + // 0x00640323: 0x00001E0D
- "\x00D\x031\x00\x00\x1e\x0e" + // 0x00440331: 0x00001E0E
- "\x00d\x031\x00\x00\x1e\x0f" + // 0x00640331: 0x00001E0F
- "\x00D\x03'\x00\x00\x1e\x10" + // 0x00440327: 0x00001E10
- "\x00d\x03'\x00\x00\x1e\x11" + // 0x00640327: 0x00001E11
- "\x00D\x03-\x00\x00\x1e\x12" + // 0x0044032D: 0x00001E12
- "\x00d\x03-\x00\x00\x1e\x13" + // 0x0064032D: 0x00001E13
- "\x01\x12\x03\x00\x00\x00\x1e\x14" + // 0x01120300: 0x00001E14
- "\x01\x13\x03\x00\x00\x00\x1e\x15" + // 0x01130300: 0x00001E15
- "\x01\x12\x03\x01\x00\x00\x1e\x16" + // 0x01120301: 0x00001E16
- "\x01\x13\x03\x01\x00\x00\x1e\x17" + // 0x01130301: 0x00001E17
- "\x00E\x03-\x00\x00\x1e\x18" + // 0x0045032D: 0x00001E18
- "\x00e\x03-\x00\x00\x1e\x19" + // 0x0065032D: 0x00001E19
- "\x00E\x030\x00\x00\x1e\x1a" + // 0x00450330: 0x00001E1A
- "\x00e\x030\x00\x00\x1e\x1b" + // 0x00650330: 0x00001E1B
- "\x02(\x03\x06\x00\x00\x1e\x1c" + // 0x02280306: 0x00001E1C
- "\x02)\x03\x06\x00\x00\x1e\x1d" + // 0x02290306: 0x00001E1D
- "\x00F\x03\a\x00\x00\x1e\x1e" + // 0x00460307: 0x00001E1E
- "\x00f\x03\a\x00\x00\x1e\x1f" + // 0x00660307: 0x00001E1F
- "\x00G\x03\x04\x00\x00\x1e " + // 0x00470304: 0x00001E20
- "\x00g\x03\x04\x00\x00\x1e!" + // 0x00670304: 0x00001E21
- "\x00H\x03\a\x00\x00\x1e\"" + // 0x00480307: 0x00001E22
- "\x00h\x03\a\x00\x00\x1e#" + // 0x00680307: 0x00001E23
- "\x00H\x03#\x00\x00\x1e$" + // 0x00480323: 0x00001E24
- "\x00h\x03#\x00\x00\x1e%" + // 0x00680323: 0x00001E25
- "\x00H\x03\b\x00\x00\x1e&" + // 0x00480308: 0x00001E26
- "\x00h\x03\b\x00\x00\x1e'" + // 0x00680308: 0x00001E27
- "\x00H\x03'\x00\x00\x1e(" + // 0x00480327: 0x00001E28
- "\x00h\x03'\x00\x00\x1e)" + // 0x00680327: 0x00001E29
- "\x00H\x03.\x00\x00\x1e*" + // 0x0048032E: 0x00001E2A
- "\x00h\x03.\x00\x00\x1e+" + // 0x0068032E: 0x00001E2B
- "\x00I\x030\x00\x00\x1e," + // 0x00490330: 0x00001E2C
- "\x00i\x030\x00\x00\x1e-" + // 0x00690330: 0x00001E2D
- "\x00\xcf\x03\x01\x00\x00\x1e." + // 0x00CF0301: 0x00001E2E
- "\x00\xef\x03\x01\x00\x00\x1e/" + // 0x00EF0301: 0x00001E2F
- "\x00K\x03\x01\x00\x00\x1e0" + // 0x004B0301: 0x00001E30
- "\x00k\x03\x01\x00\x00\x1e1" + // 0x006B0301: 0x00001E31
- "\x00K\x03#\x00\x00\x1e2" + // 0x004B0323: 0x00001E32
- "\x00k\x03#\x00\x00\x1e3" + // 0x006B0323: 0x00001E33
- "\x00K\x031\x00\x00\x1e4" + // 0x004B0331: 0x00001E34
- "\x00k\x031\x00\x00\x1e5" + // 0x006B0331: 0x00001E35
- "\x00L\x03#\x00\x00\x1e6" + // 0x004C0323: 0x00001E36
- "\x00l\x03#\x00\x00\x1e7" + // 0x006C0323: 0x00001E37
- "\x1e6\x03\x04\x00\x00\x1e8" + // 0x1E360304: 0x00001E38
- "\x1e7\x03\x04\x00\x00\x1e9" + // 0x1E370304: 0x00001E39
- "\x00L\x031\x00\x00\x1e:" + // 0x004C0331: 0x00001E3A
- "\x00l\x031\x00\x00\x1e;" + // 0x006C0331: 0x00001E3B
- "\x00L\x03-\x00\x00\x1e<" + // 0x004C032D: 0x00001E3C
- "\x00l\x03-\x00\x00\x1e=" + // 0x006C032D: 0x00001E3D
- "\x00M\x03\x01\x00\x00\x1e>" + // 0x004D0301: 0x00001E3E
- "\x00m\x03\x01\x00\x00\x1e?" + // 0x006D0301: 0x00001E3F
- "\x00M\x03\a\x00\x00\x1e@" + // 0x004D0307: 0x00001E40
- "\x00m\x03\a\x00\x00\x1eA" + // 0x006D0307: 0x00001E41
- "\x00M\x03#\x00\x00\x1eB" + // 0x004D0323: 0x00001E42
- "\x00m\x03#\x00\x00\x1eC" + // 0x006D0323: 0x00001E43
- "\x00N\x03\a\x00\x00\x1eD" + // 0x004E0307: 0x00001E44
- "\x00n\x03\a\x00\x00\x1eE" + // 0x006E0307: 0x00001E45
- "\x00N\x03#\x00\x00\x1eF" + // 0x004E0323: 0x00001E46
- "\x00n\x03#\x00\x00\x1eG" + // 0x006E0323: 0x00001E47
- "\x00N\x031\x00\x00\x1eH" + // 0x004E0331: 0x00001E48
- "\x00n\x031\x00\x00\x1eI" + // 0x006E0331: 0x00001E49
- "\x00N\x03-\x00\x00\x1eJ" + // 0x004E032D: 0x00001E4A
- "\x00n\x03-\x00\x00\x1eK" + // 0x006E032D: 0x00001E4B
- "\x00\xd5\x03\x01\x00\x00\x1eL" + // 0x00D50301: 0x00001E4C
- "\x00\xf5\x03\x01\x00\x00\x1eM" + // 0x00F50301: 0x00001E4D
- "\x00\xd5\x03\b\x00\x00\x1eN" + // 0x00D50308: 0x00001E4E
- "\x00\xf5\x03\b\x00\x00\x1eO" + // 0x00F50308: 0x00001E4F
- "\x01L\x03\x00\x00\x00\x1eP" + // 0x014C0300: 0x00001E50
- "\x01M\x03\x00\x00\x00\x1eQ" + // 0x014D0300: 0x00001E51
- "\x01L\x03\x01\x00\x00\x1eR" + // 0x014C0301: 0x00001E52
- "\x01M\x03\x01\x00\x00\x1eS" + // 0x014D0301: 0x00001E53
- "\x00P\x03\x01\x00\x00\x1eT" + // 0x00500301: 0x00001E54
- "\x00p\x03\x01\x00\x00\x1eU" + // 0x00700301: 0x00001E55
- "\x00P\x03\a\x00\x00\x1eV" + // 0x00500307: 0x00001E56
- "\x00p\x03\a\x00\x00\x1eW" + // 0x00700307: 0x00001E57
- "\x00R\x03\a\x00\x00\x1eX" + // 0x00520307: 0x00001E58
- "\x00r\x03\a\x00\x00\x1eY" + // 0x00720307: 0x00001E59
- "\x00R\x03#\x00\x00\x1eZ" + // 0x00520323: 0x00001E5A
- "\x00r\x03#\x00\x00\x1e[" + // 0x00720323: 0x00001E5B
- "\x1eZ\x03\x04\x00\x00\x1e\\" + // 0x1E5A0304: 0x00001E5C
- "\x1e[\x03\x04\x00\x00\x1e]" + // 0x1E5B0304: 0x00001E5D
- "\x00R\x031\x00\x00\x1e^" + // 0x00520331: 0x00001E5E
- "\x00r\x031\x00\x00\x1e_" + // 0x00720331: 0x00001E5F
- "\x00S\x03\a\x00\x00\x1e`" + // 0x00530307: 0x00001E60
- "\x00s\x03\a\x00\x00\x1ea" + // 0x00730307: 0x00001E61
- "\x00S\x03#\x00\x00\x1eb" + // 0x00530323: 0x00001E62
- "\x00s\x03#\x00\x00\x1ec" + // 0x00730323: 0x00001E63
- "\x01Z\x03\a\x00\x00\x1ed" + // 0x015A0307: 0x00001E64
- "\x01[\x03\a\x00\x00\x1ee" + // 0x015B0307: 0x00001E65
- "\x01`\x03\a\x00\x00\x1ef" + // 0x01600307: 0x00001E66
- "\x01a\x03\a\x00\x00\x1eg" + // 0x01610307: 0x00001E67
- "\x1eb\x03\a\x00\x00\x1eh" + // 0x1E620307: 0x00001E68
- "\x1ec\x03\a\x00\x00\x1ei" + // 0x1E630307: 0x00001E69
- "\x00T\x03\a\x00\x00\x1ej" + // 0x00540307: 0x00001E6A
- "\x00t\x03\a\x00\x00\x1ek" + // 0x00740307: 0x00001E6B
- "\x00T\x03#\x00\x00\x1el" + // 0x00540323: 0x00001E6C
- "\x00t\x03#\x00\x00\x1em" + // 0x00740323: 0x00001E6D
- "\x00T\x031\x00\x00\x1en" + // 0x00540331: 0x00001E6E
- "\x00t\x031\x00\x00\x1eo" + // 0x00740331: 0x00001E6F
- "\x00T\x03-\x00\x00\x1ep" + // 0x0054032D: 0x00001E70
- "\x00t\x03-\x00\x00\x1eq" + // 0x0074032D: 0x00001E71
- "\x00U\x03$\x00\x00\x1er" + // 0x00550324: 0x00001E72
- "\x00u\x03$\x00\x00\x1es" + // 0x00750324: 0x00001E73
- "\x00U\x030\x00\x00\x1et" + // 0x00550330: 0x00001E74
- "\x00u\x030\x00\x00\x1eu" + // 0x00750330: 0x00001E75
- "\x00U\x03-\x00\x00\x1ev" + // 0x0055032D: 0x00001E76
- "\x00u\x03-\x00\x00\x1ew" + // 0x0075032D: 0x00001E77
- "\x01h\x03\x01\x00\x00\x1ex" + // 0x01680301: 0x00001E78
- "\x01i\x03\x01\x00\x00\x1ey" + // 0x01690301: 0x00001E79
- "\x01j\x03\b\x00\x00\x1ez" + // 0x016A0308: 0x00001E7A
- "\x01k\x03\b\x00\x00\x1e{" + // 0x016B0308: 0x00001E7B
- "\x00V\x03\x03\x00\x00\x1e|" + // 0x00560303: 0x00001E7C
- "\x00v\x03\x03\x00\x00\x1e}" + // 0x00760303: 0x00001E7D
- "\x00V\x03#\x00\x00\x1e~" + // 0x00560323: 0x00001E7E
- "\x00v\x03#\x00\x00\x1e\x7f" + // 0x00760323: 0x00001E7F
- "\x00W\x03\x00\x00\x00\x1e\x80" + // 0x00570300: 0x00001E80
- "\x00w\x03\x00\x00\x00\x1e\x81" + // 0x00770300: 0x00001E81
- "\x00W\x03\x01\x00\x00\x1e\x82" + // 0x00570301: 0x00001E82
- "\x00w\x03\x01\x00\x00\x1e\x83" + // 0x00770301: 0x00001E83
- "\x00W\x03\b\x00\x00\x1e\x84" + // 0x00570308: 0x00001E84
- "\x00w\x03\b\x00\x00\x1e\x85" + // 0x00770308: 0x00001E85
- "\x00W\x03\a\x00\x00\x1e\x86" + // 0x00570307: 0x00001E86
- "\x00w\x03\a\x00\x00\x1e\x87" + // 0x00770307: 0x00001E87
- "\x00W\x03#\x00\x00\x1e\x88" + // 0x00570323: 0x00001E88
- "\x00w\x03#\x00\x00\x1e\x89" + // 0x00770323: 0x00001E89
- "\x00X\x03\a\x00\x00\x1e\x8a" + // 0x00580307: 0x00001E8A
- "\x00x\x03\a\x00\x00\x1e\x8b" + // 0x00780307: 0x00001E8B
- "\x00X\x03\b\x00\x00\x1e\x8c" + // 0x00580308: 0x00001E8C
- "\x00x\x03\b\x00\x00\x1e\x8d" + // 0x00780308: 0x00001E8D
- "\x00Y\x03\a\x00\x00\x1e\x8e" + // 0x00590307: 0x00001E8E
- "\x00y\x03\a\x00\x00\x1e\x8f" + // 0x00790307: 0x00001E8F
- "\x00Z\x03\x02\x00\x00\x1e\x90" + // 0x005A0302: 0x00001E90
- "\x00z\x03\x02\x00\x00\x1e\x91" + // 0x007A0302: 0x00001E91
- "\x00Z\x03#\x00\x00\x1e\x92" + // 0x005A0323: 0x00001E92
- "\x00z\x03#\x00\x00\x1e\x93" + // 0x007A0323: 0x00001E93
- "\x00Z\x031\x00\x00\x1e\x94" + // 0x005A0331: 0x00001E94
- "\x00z\x031\x00\x00\x1e\x95" + // 0x007A0331: 0x00001E95
- "\x00h\x031\x00\x00\x1e\x96" + // 0x00680331: 0x00001E96
- "\x00t\x03\b\x00\x00\x1e\x97" + // 0x00740308: 0x00001E97
- "\x00w\x03\n\x00\x00\x1e\x98" + // 0x0077030A: 0x00001E98
- "\x00y\x03\n\x00\x00\x1e\x99" + // 0x0079030A: 0x00001E99
- "\x01\x7f\x03\a\x00\x00\x1e\x9b" + // 0x017F0307: 0x00001E9B
- "\x00A\x03#\x00\x00\x1e\xa0" + // 0x00410323: 0x00001EA0
- "\x00a\x03#\x00\x00\x1e\xa1" + // 0x00610323: 0x00001EA1
- "\x00A\x03\t\x00\x00\x1e\xa2" + // 0x00410309: 0x00001EA2
- "\x00a\x03\t\x00\x00\x1e\xa3" + // 0x00610309: 0x00001EA3
- "\x00\xc2\x03\x01\x00\x00\x1e\xa4" + // 0x00C20301: 0x00001EA4
- "\x00\xe2\x03\x01\x00\x00\x1e\xa5" + // 0x00E20301: 0x00001EA5
- "\x00\xc2\x03\x00\x00\x00\x1e\xa6" + // 0x00C20300: 0x00001EA6
- "\x00\xe2\x03\x00\x00\x00\x1e\xa7" + // 0x00E20300: 0x00001EA7
- "\x00\xc2\x03\t\x00\x00\x1e\xa8" + // 0x00C20309: 0x00001EA8
- "\x00\xe2\x03\t\x00\x00\x1e\xa9" + // 0x00E20309: 0x00001EA9
- "\x00\xc2\x03\x03\x00\x00\x1e\xaa" + // 0x00C20303: 0x00001EAA
- "\x00\xe2\x03\x03\x00\x00\x1e\xab" + // 0x00E20303: 0x00001EAB
- "\x1e\xa0\x03\x02\x00\x00\x1e\xac" + // 0x1EA00302: 0x00001EAC
- "\x1e\xa1\x03\x02\x00\x00\x1e\xad" + // 0x1EA10302: 0x00001EAD
- "\x01\x02\x03\x01\x00\x00\x1e\xae" + // 0x01020301: 0x00001EAE
- "\x01\x03\x03\x01\x00\x00\x1e\xaf" + // 0x01030301: 0x00001EAF
- "\x01\x02\x03\x00\x00\x00\x1e\xb0" + // 0x01020300: 0x00001EB0
- "\x01\x03\x03\x00\x00\x00\x1e\xb1" + // 0x01030300: 0x00001EB1
- "\x01\x02\x03\t\x00\x00\x1e\xb2" + // 0x01020309: 0x00001EB2
- "\x01\x03\x03\t\x00\x00\x1e\xb3" + // 0x01030309: 0x00001EB3
- "\x01\x02\x03\x03\x00\x00\x1e\xb4" + // 0x01020303: 0x00001EB4
- "\x01\x03\x03\x03\x00\x00\x1e\xb5" + // 0x01030303: 0x00001EB5
- "\x1e\xa0\x03\x06\x00\x00\x1e\xb6" + // 0x1EA00306: 0x00001EB6
- "\x1e\xa1\x03\x06\x00\x00\x1e\xb7" + // 0x1EA10306: 0x00001EB7
- "\x00E\x03#\x00\x00\x1e\xb8" + // 0x00450323: 0x00001EB8
- "\x00e\x03#\x00\x00\x1e\xb9" + // 0x00650323: 0x00001EB9
- "\x00E\x03\t\x00\x00\x1e\xba" + // 0x00450309: 0x00001EBA
- "\x00e\x03\t\x00\x00\x1e\xbb" + // 0x00650309: 0x00001EBB
- "\x00E\x03\x03\x00\x00\x1e\xbc" + // 0x00450303: 0x00001EBC
- "\x00e\x03\x03\x00\x00\x1e\xbd" + // 0x00650303: 0x00001EBD
- "\x00\xca\x03\x01\x00\x00\x1e\xbe" + // 0x00CA0301: 0x00001EBE
- "\x00\xea\x03\x01\x00\x00\x1e\xbf" + // 0x00EA0301: 0x00001EBF
- "\x00\xca\x03\x00\x00\x00\x1e\xc0" + // 0x00CA0300: 0x00001EC0
- "\x00\xea\x03\x00\x00\x00\x1e\xc1" + // 0x00EA0300: 0x00001EC1
- "\x00\xca\x03\t\x00\x00\x1e\xc2" + // 0x00CA0309: 0x00001EC2
- "\x00\xea\x03\t\x00\x00\x1e\xc3" + // 0x00EA0309: 0x00001EC3
- "\x00\xca\x03\x03\x00\x00\x1e\xc4" + // 0x00CA0303: 0x00001EC4
- "\x00\xea\x03\x03\x00\x00\x1e\xc5" + // 0x00EA0303: 0x00001EC5
- "\x1e\xb8\x03\x02\x00\x00\x1e\xc6" + // 0x1EB80302: 0x00001EC6
- "\x1e\xb9\x03\x02\x00\x00\x1e\xc7" + // 0x1EB90302: 0x00001EC7
- "\x00I\x03\t\x00\x00\x1e\xc8" + // 0x00490309: 0x00001EC8
- "\x00i\x03\t\x00\x00\x1e\xc9" + // 0x00690309: 0x00001EC9
- "\x00I\x03#\x00\x00\x1e\xca" + // 0x00490323: 0x00001ECA
- "\x00i\x03#\x00\x00\x1e\xcb" + // 0x00690323: 0x00001ECB
- "\x00O\x03#\x00\x00\x1e\xcc" + // 0x004F0323: 0x00001ECC
- "\x00o\x03#\x00\x00\x1e\xcd" + // 0x006F0323: 0x00001ECD
- "\x00O\x03\t\x00\x00\x1e\xce" + // 0x004F0309: 0x00001ECE
- "\x00o\x03\t\x00\x00\x1e\xcf" + // 0x006F0309: 0x00001ECF
- "\x00\xd4\x03\x01\x00\x00\x1e\xd0" + // 0x00D40301: 0x00001ED0
- "\x00\xf4\x03\x01\x00\x00\x1e\xd1" + // 0x00F40301: 0x00001ED1
- "\x00\xd4\x03\x00\x00\x00\x1e\xd2" + // 0x00D40300: 0x00001ED2
- "\x00\xf4\x03\x00\x00\x00\x1e\xd3" + // 0x00F40300: 0x00001ED3
- "\x00\xd4\x03\t\x00\x00\x1e\xd4" + // 0x00D40309: 0x00001ED4
- "\x00\xf4\x03\t\x00\x00\x1e\xd5" + // 0x00F40309: 0x00001ED5
- "\x00\xd4\x03\x03\x00\x00\x1e\xd6" + // 0x00D40303: 0x00001ED6
- "\x00\xf4\x03\x03\x00\x00\x1e\xd7" + // 0x00F40303: 0x00001ED7
- "\x1e\xcc\x03\x02\x00\x00\x1e\xd8" + // 0x1ECC0302: 0x00001ED8
- "\x1e\xcd\x03\x02\x00\x00\x1e\xd9" + // 0x1ECD0302: 0x00001ED9
- "\x01\xa0\x03\x01\x00\x00\x1e\xda" + // 0x01A00301: 0x00001EDA
- "\x01\xa1\x03\x01\x00\x00\x1e\xdb" + // 0x01A10301: 0x00001EDB
- "\x01\xa0\x03\x00\x00\x00\x1e\xdc" + // 0x01A00300: 0x00001EDC
- "\x01\xa1\x03\x00\x00\x00\x1e\xdd" + // 0x01A10300: 0x00001EDD
- "\x01\xa0\x03\t\x00\x00\x1e\xde" + // 0x01A00309: 0x00001EDE
- "\x01\xa1\x03\t\x00\x00\x1e\xdf" + // 0x01A10309: 0x00001EDF
- "\x01\xa0\x03\x03\x00\x00\x1e\xe0" + // 0x01A00303: 0x00001EE0
- "\x01\xa1\x03\x03\x00\x00\x1e\xe1" + // 0x01A10303: 0x00001EE1
- "\x01\xa0\x03#\x00\x00\x1e\xe2" + // 0x01A00323: 0x00001EE2
- "\x01\xa1\x03#\x00\x00\x1e\xe3" + // 0x01A10323: 0x00001EE3
- "\x00U\x03#\x00\x00\x1e\xe4" + // 0x00550323: 0x00001EE4
- "\x00u\x03#\x00\x00\x1e\xe5" + // 0x00750323: 0x00001EE5
- "\x00U\x03\t\x00\x00\x1e\xe6" + // 0x00550309: 0x00001EE6
- "\x00u\x03\t\x00\x00\x1e\xe7" + // 0x00750309: 0x00001EE7
- "\x01\xaf\x03\x01\x00\x00\x1e\xe8" + // 0x01AF0301: 0x00001EE8
- "\x01\xb0\x03\x01\x00\x00\x1e\xe9" + // 0x01B00301: 0x00001EE9
- "\x01\xaf\x03\x00\x00\x00\x1e\xea" + // 0x01AF0300: 0x00001EEA
- "\x01\xb0\x03\x00\x00\x00\x1e\xeb" + // 0x01B00300: 0x00001EEB
- "\x01\xaf\x03\t\x00\x00\x1e\xec" + // 0x01AF0309: 0x00001EEC
- "\x01\xb0\x03\t\x00\x00\x1e\xed" + // 0x01B00309: 0x00001EED
- "\x01\xaf\x03\x03\x00\x00\x1e\xee" + // 0x01AF0303: 0x00001EEE
- "\x01\xb0\x03\x03\x00\x00\x1e\xef" + // 0x01B00303: 0x00001EEF
- "\x01\xaf\x03#\x00\x00\x1e\xf0" + // 0x01AF0323: 0x00001EF0
- "\x01\xb0\x03#\x00\x00\x1e\xf1" + // 0x01B00323: 0x00001EF1
- "\x00Y\x03\x00\x00\x00\x1e\xf2" + // 0x00590300: 0x00001EF2
- "\x00y\x03\x00\x00\x00\x1e\xf3" + // 0x00790300: 0x00001EF3
- "\x00Y\x03#\x00\x00\x1e\xf4" + // 0x00590323: 0x00001EF4
- "\x00y\x03#\x00\x00\x1e\xf5" + // 0x00790323: 0x00001EF5
- "\x00Y\x03\t\x00\x00\x1e\xf6" + // 0x00590309: 0x00001EF6
- "\x00y\x03\t\x00\x00\x1e\xf7" + // 0x00790309: 0x00001EF7
- "\x00Y\x03\x03\x00\x00\x1e\xf8" + // 0x00590303: 0x00001EF8
- "\x00y\x03\x03\x00\x00\x1e\xf9" + // 0x00790303: 0x00001EF9
- "\x03\xb1\x03\x13\x00\x00\x1f\x00" + // 0x03B10313: 0x00001F00
- "\x03\xb1\x03\x14\x00\x00\x1f\x01" + // 0x03B10314: 0x00001F01
- "\x1f\x00\x03\x00\x00\x00\x1f\x02" + // 0x1F000300: 0x00001F02
- "\x1f\x01\x03\x00\x00\x00\x1f\x03" + // 0x1F010300: 0x00001F03
- "\x1f\x00\x03\x01\x00\x00\x1f\x04" + // 0x1F000301: 0x00001F04
- "\x1f\x01\x03\x01\x00\x00\x1f\x05" + // 0x1F010301: 0x00001F05
- "\x1f\x00\x03B\x00\x00\x1f\x06" + // 0x1F000342: 0x00001F06
- "\x1f\x01\x03B\x00\x00\x1f\a" + // 0x1F010342: 0x00001F07
- "\x03\x91\x03\x13\x00\x00\x1f\b" + // 0x03910313: 0x00001F08
- "\x03\x91\x03\x14\x00\x00\x1f\t" + // 0x03910314: 0x00001F09
- "\x1f\b\x03\x00\x00\x00\x1f\n" + // 0x1F080300: 0x00001F0A
- "\x1f\t\x03\x00\x00\x00\x1f\v" + // 0x1F090300: 0x00001F0B
- "\x1f\b\x03\x01\x00\x00\x1f\f" + // 0x1F080301: 0x00001F0C
- "\x1f\t\x03\x01\x00\x00\x1f\r" + // 0x1F090301: 0x00001F0D
- "\x1f\b\x03B\x00\x00\x1f\x0e" + // 0x1F080342: 0x00001F0E
- "\x1f\t\x03B\x00\x00\x1f\x0f" + // 0x1F090342: 0x00001F0F
- "\x03\xb5\x03\x13\x00\x00\x1f\x10" + // 0x03B50313: 0x00001F10
- "\x03\xb5\x03\x14\x00\x00\x1f\x11" + // 0x03B50314: 0x00001F11
- "\x1f\x10\x03\x00\x00\x00\x1f\x12" + // 0x1F100300: 0x00001F12
- "\x1f\x11\x03\x00\x00\x00\x1f\x13" + // 0x1F110300: 0x00001F13
- "\x1f\x10\x03\x01\x00\x00\x1f\x14" + // 0x1F100301: 0x00001F14
- "\x1f\x11\x03\x01\x00\x00\x1f\x15" + // 0x1F110301: 0x00001F15
- "\x03\x95\x03\x13\x00\x00\x1f\x18" + // 0x03950313: 0x00001F18
- "\x03\x95\x03\x14\x00\x00\x1f\x19" + // 0x03950314: 0x00001F19
- "\x1f\x18\x03\x00\x00\x00\x1f\x1a" + // 0x1F180300: 0x00001F1A
- "\x1f\x19\x03\x00\x00\x00\x1f\x1b" + // 0x1F190300: 0x00001F1B
- "\x1f\x18\x03\x01\x00\x00\x1f\x1c" + // 0x1F180301: 0x00001F1C
- "\x1f\x19\x03\x01\x00\x00\x1f\x1d" + // 0x1F190301: 0x00001F1D
- "\x03\xb7\x03\x13\x00\x00\x1f " + // 0x03B70313: 0x00001F20
- "\x03\xb7\x03\x14\x00\x00\x1f!" + // 0x03B70314: 0x00001F21
- "\x1f \x03\x00\x00\x00\x1f\"" + // 0x1F200300: 0x00001F22
- "\x1f!\x03\x00\x00\x00\x1f#" + // 0x1F210300: 0x00001F23
- "\x1f \x03\x01\x00\x00\x1f$" + // 0x1F200301: 0x00001F24
- "\x1f!\x03\x01\x00\x00\x1f%" + // 0x1F210301: 0x00001F25
- "\x1f \x03B\x00\x00\x1f&" + // 0x1F200342: 0x00001F26
- "\x1f!\x03B\x00\x00\x1f'" + // 0x1F210342: 0x00001F27
- "\x03\x97\x03\x13\x00\x00\x1f(" + // 0x03970313: 0x00001F28
- "\x03\x97\x03\x14\x00\x00\x1f)" + // 0x03970314: 0x00001F29
- "\x1f(\x03\x00\x00\x00\x1f*" + // 0x1F280300: 0x00001F2A
- "\x1f)\x03\x00\x00\x00\x1f+" + // 0x1F290300: 0x00001F2B
- "\x1f(\x03\x01\x00\x00\x1f," + // 0x1F280301: 0x00001F2C
- "\x1f)\x03\x01\x00\x00\x1f-" + // 0x1F290301: 0x00001F2D
- "\x1f(\x03B\x00\x00\x1f." + // 0x1F280342: 0x00001F2E
- "\x1f)\x03B\x00\x00\x1f/" + // 0x1F290342: 0x00001F2F
- "\x03\xb9\x03\x13\x00\x00\x1f0" + // 0x03B90313: 0x00001F30
- "\x03\xb9\x03\x14\x00\x00\x1f1" + // 0x03B90314: 0x00001F31
- "\x1f0\x03\x00\x00\x00\x1f2" + // 0x1F300300: 0x00001F32
- "\x1f1\x03\x00\x00\x00\x1f3" + // 0x1F310300: 0x00001F33
- "\x1f0\x03\x01\x00\x00\x1f4" + // 0x1F300301: 0x00001F34
- "\x1f1\x03\x01\x00\x00\x1f5" + // 0x1F310301: 0x00001F35
- "\x1f0\x03B\x00\x00\x1f6" + // 0x1F300342: 0x00001F36
- "\x1f1\x03B\x00\x00\x1f7" + // 0x1F310342: 0x00001F37
- "\x03\x99\x03\x13\x00\x00\x1f8" + // 0x03990313: 0x00001F38
- "\x03\x99\x03\x14\x00\x00\x1f9" + // 0x03990314: 0x00001F39
- "\x1f8\x03\x00\x00\x00\x1f:" + // 0x1F380300: 0x00001F3A
- "\x1f9\x03\x00\x00\x00\x1f;" + // 0x1F390300: 0x00001F3B
- "\x1f8\x03\x01\x00\x00\x1f<" + // 0x1F380301: 0x00001F3C
- "\x1f9\x03\x01\x00\x00\x1f=" + // 0x1F390301: 0x00001F3D
- "\x1f8\x03B\x00\x00\x1f>" + // 0x1F380342: 0x00001F3E
- "\x1f9\x03B\x00\x00\x1f?" + // 0x1F390342: 0x00001F3F
- "\x03\xbf\x03\x13\x00\x00\x1f@" + // 0x03BF0313: 0x00001F40
- "\x03\xbf\x03\x14\x00\x00\x1fA" + // 0x03BF0314: 0x00001F41
- "\x1f@\x03\x00\x00\x00\x1fB" + // 0x1F400300: 0x00001F42
- "\x1fA\x03\x00\x00\x00\x1fC" + // 0x1F410300: 0x00001F43
- "\x1f@\x03\x01\x00\x00\x1fD" + // 0x1F400301: 0x00001F44
- "\x1fA\x03\x01\x00\x00\x1fE" + // 0x1F410301: 0x00001F45
- "\x03\x9f\x03\x13\x00\x00\x1fH" + // 0x039F0313: 0x00001F48
- "\x03\x9f\x03\x14\x00\x00\x1fI" + // 0x039F0314: 0x00001F49
- "\x1fH\x03\x00\x00\x00\x1fJ" + // 0x1F480300: 0x00001F4A
- "\x1fI\x03\x00\x00\x00\x1fK" + // 0x1F490300: 0x00001F4B
- "\x1fH\x03\x01\x00\x00\x1fL" + // 0x1F480301: 0x00001F4C
- "\x1fI\x03\x01\x00\x00\x1fM" + // 0x1F490301: 0x00001F4D
- "\x03\xc5\x03\x13\x00\x00\x1fP" + // 0x03C50313: 0x00001F50
- "\x03\xc5\x03\x14\x00\x00\x1fQ" + // 0x03C50314: 0x00001F51
- "\x1fP\x03\x00\x00\x00\x1fR" + // 0x1F500300: 0x00001F52
- "\x1fQ\x03\x00\x00\x00\x1fS" + // 0x1F510300: 0x00001F53
- "\x1fP\x03\x01\x00\x00\x1fT" + // 0x1F500301: 0x00001F54
- "\x1fQ\x03\x01\x00\x00\x1fU" + // 0x1F510301: 0x00001F55
- "\x1fP\x03B\x00\x00\x1fV" + // 0x1F500342: 0x00001F56
- "\x1fQ\x03B\x00\x00\x1fW" + // 0x1F510342: 0x00001F57
- "\x03\xa5\x03\x14\x00\x00\x1fY" + // 0x03A50314: 0x00001F59
- "\x1fY\x03\x00\x00\x00\x1f[" + // 0x1F590300: 0x00001F5B
- "\x1fY\x03\x01\x00\x00\x1f]" + // 0x1F590301: 0x00001F5D
- "\x1fY\x03B\x00\x00\x1f_" + // 0x1F590342: 0x00001F5F
- "\x03\xc9\x03\x13\x00\x00\x1f`" + // 0x03C90313: 0x00001F60
- "\x03\xc9\x03\x14\x00\x00\x1fa" + // 0x03C90314: 0x00001F61
- "\x1f`\x03\x00\x00\x00\x1fb" + // 0x1F600300: 0x00001F62
- "\x1fa\x03\x00\x00\x00\x1fc" + // 0x1F610300: 0x00001F63
- "\x1f`\x03\x01\x00\x00\x1fd" + // 0x1F600301: 0x00001F64
- "\x1fa\x03\x01\x00\x00\x1fe" + // 0x1F610301: 0x00001F65
- "\x1f`\x03B\x00\x00\x1ff" + // 0x1F600342: 0x00001F66
- "\x1fa\x03B\x00\x00\x1fg" + // 0x1F610342: 0x00001F67
- "\x03\xa9\x03\x13\x00\x00\x1fh" + // 0x03A90313: 0x00001F68
- "\x03\xa9\x03\x14\x00\x00\x1fi" + // 0x03A90314: 0x00001F69
- "\x1fh\x03\x00\x00\x00\x1fj" + // 0x1F680300: 0x00001F6A
- "\x1fi\x03\x00\x00\x00\x1fk" + // 0x1F690300: 0x00001F6B
- "\x1fh\x03\x01\x00\x00\x1fl" + // 0x1F680301: 0x00001F6C
- "\x1fi\x03\x01\x00\x00\x1fm" + // 0x1F690301: 0x00001F6D
- "\x1fh\x03B\x00\x00\x1fn" + // 0x1F680342: 0x00001F6E
- "\x1fi\x03B\x00\x00\x1fo" + // 0x1F690342: 0x00001F6F
- "\x03\xb1\x03\x00\x00\x00\x1fp" + // 0x03B10300: 0x00001F70
- "\x03\xb5\x03\x00\x00\x00\x1fr" + // 0x03B50300: 0x00001F72
- "\x03\xb7\x03\x00\x00\x00\x1ft" + // 0x03B70300: 0x00001F74
- "\x03\xb9\x03\x00\x00\x00\x1fv" + // 0x03B90300: 0x00001F76
- "\x03\xbf\x03\x00\x00\x00\x1fx" + // 0x03BF0300: 0x00001F78
- "\x03\xc5\x03\x00\x00\x00\x1fz" + // 0x03C50300: 0x00001F7A
- "\x03\xc9\x03\x00\x00\x00\x1f|" + // 0x03C90300: 0x00001F7C
- "\x1f\x00\x03E\x00\x00\x1f\x80" + // 0x1F000345: 0x00001F80
- "\x1f\x01\x03E\x00\x00\x1f\x81" + // 0x1F010345: 0x00001F81
- "\x1f\x02\x03E\x00\x00\x1f\x82" + // 0x1F020345: 0x00001F82
- "\x1f\x03\x03E\x00\x00\x1f\x83" + // 0x1F030345: 0x00001F83
- "\x1f\x04\x03E\x00\x00\x1f\x84" + // 0x1F040345: 0x00001F84
- "\x1f\x05\x03E\x00\x00\x1f\x85" + // 0x1F050345: 0x00001F85
- "\x1f\x06\x03E\x00\x00\x1f\x86" + // 0x1F060345: 0x00001F86
- "\x1f\a\x03E\x00\x00\x1f\x87" + // 0x1F070345: 0x00001F87
- "\x1f\b\x03E\x00\x00\x1f\x88" + // 0x1F080345: 0x00001F88
- "\x1f\t\x03E\x00\x00\x1f\x89" + // 0x1F090345: 0x00001F89
- "\x1f\n\x03E\x00\x00\x1f\x8a" + // 0x1F0A0345: 0x00001F8A
- "\x1f\v\x03E\x00\x00\x1f\x8b" + // 0x1F0B0345: 0x00001F8B
- "\x1f\f\x03E\x00\x00\x1f\x8c" + // 0x1F0C0345: 0x00001F8C
- "\x1f\r\x03E\x00\x00\x1f\x8d" + // 0x1F0D0345: 0x00001F8D
- "\x1f\x0e\x03E\x00\x00\x1f\x8e" + // 0x1F0E0345: 0x00001F8E
- "\x1f\x0f\x03E\x00\x00\x1f\x8f" + // 0x1F0F0345: 0x00001F8F
- "\x1f \x03E\x00\x00\x1f\x90" + // 0x1F200345: 0x00001F90
- "\x1f!\x03E\x00\x00\x1f\x91" + // 0x1F210345: 0x00001F91
- "\x1f\"\x03E\x00\x00\x1f\x92" + // 0x1F220345: 0x00001F92
- "\x1f#\x03E\x00\x00\x1f\x93" + // 0x1F230345: 0x00001F93
- "\x1f$\x03E\x00\x00\x1f\x94" + // 0x1F240345: 0x00001F94
- "\x1f%\x03E\x00\x00\x1f\x95" + // 0x1F250345: 0x00001F95
- "\x1f&\x03E\x00\x00\x1f\x96" + // 0x1F260345: 0x00001F96
- "\x1f'\x03E\x00\x00\x1f\x97" + // 0x1F270345: 0x00001F97
- "\x1f(\x03E\x00\x00\x1f\x98" + // 0x1F280345: 0x00001F98
- "\x1f)\x03E\x00\x00\x1f\x99" + // 0x1F290345: 0x00001F99
- "\x1f*\x03E\x00\x00\x1f\x9a" + // 0x1F2A0345: 0x00001F9A
- "\x1f+\x03E\x00\x00\x1f\x9b" + // 0x1F2B0345: 0x00001F9B
- "\x1f,\x03E\x00\x00\x1f\x9c" + // 0x1F2C0345: 0x00001F9C
- "\x1f-\x03E\x00\x00\x1f\x9d" + // 0x1F2D0345: 0x00001F9D
- "\x1f.\x03E\x00\x00\x1f\x9e" + // 0x1F2E0345: 0x00001F9E
- "\x1f/\x03E\x00\x00\x1f\x9f" + // 0x1F2F0345: 0x00001F9F
- "\x1f`\x03E\x00\x00\x1f\xa0" + // 0x1F600345: 0x00001FA0
- "\x1fa\x03E\x00\x00\x1f\xa1" + // 0x1F610345: 0x00001FA1
- "\x1fb\x03E\x00\x00\x1f\xa2" + // 0x1F620345: 0x00001FA2
- "\x1fc\x03E\x00\x00\x1f\xa3" + // 0x1F630345: 0x00001FA3
- "\x1fd\x03E\x00\x00\x1f\xa4" + // 0x1F640345: 0x00001FA4
- "\x1fe\x03E\x00\x00\x1f\xa5" + // 0x1F650345: 0x00001FA5
- "\x1ff\x03E\x00\x00\x1f\xa6" + // 0x1F660345: 0x00001FA6
- "\x1fg\x03E\x00\x00\x1f\xa7" + // 0x1F670345: 0x00001FA7
- "\x1fh\x03E\x00\x00\x1f\xa8" + // 0x1F680345: 0x00001FA8
- "\x1fi\x03E\x00\x00\x1f\xa9" + // 0x1F690345: 0x00001FA9
- "\x1fj\x03E\x00\x00\x1f\xaa" + // 0x1F6A0345: 0x00001FAA
- "\x1fk\x03E\x00\x00\x1f\xab" + // 0x1F6B0345: 0x00001FAB
- "\x1fl\x03E\x00\x00\x1f\xac" + // 0x1F6C0345: 0x00001FAC
- "\x1fm\x03E\x00\x00\x1f\xad" + // 0x1F6D0345: 0x00001FAD
- "\x1fn\x03E\x00\x00\x1f\xae" + // 0x1F6E0345: 0x00001FAE
- "\x1fo\x03E\x00\x00\x1f\xaf" + // 0x1F6F0345: 0x00001FAF
- "\x03\xb1\x03\x06\x00\x00\x1f\xb0" + // 0x03B10306: 0x00001FB0
- "\x03\xb1\x03\x04\x00\x00\x1f\xb1" + // 0x03B10304: 0x00001FB1
- "\x1fp\x03E\x00\x00\x1f\xb2" + // 0x1F700345: 0x00001FB2
- "\x03\xb1\x03E\x00\x00\x1f\xb3" + // 0x03B10345: 0x00001FB3
- "\x03\xac\x03E\x00\x00\x1f\xb4" + // 0x03AC0345: 0x00001FB4
- "\x03\xb1\x03B\x00\x00\x1f\xb6" + // 0x03B10342: 0x00001FB6
- "\x1f\xb6\x03E\x00\x00\x1f\xb7" + // 0x1FB60345: 0x00001FB7
- "\x03\x91\x03\x06\x00\x00\x1f\xb8" + // 0x03910306: 0x00001FB8
- "\x03\x91\x03\x04\x00\x00\x1f\xb9" + // 0x03910304: 0x00001FB9
- "\x03\x91\x03\x00\x00\x00\x1f\xba" + // 0x03910300: 0x00001FBA
- "\x03\x91\x03E\x00\x00\x1f\xbc" + // 0x03910345: 0x00001FBC
- "\x00\xa8\x03B\x00\x00\x1f\xc1" + // 0x00A80342: 0x00001FC1
- "\x1ft\x03E\x00\x00\x1f\xc2" + // 0x1F740345: 0x00001FC2
- "\x03\xb7\x03E\x00\x00\x1f\xc3" + // 0x03B70345: 0x00001FC3
- "\x03\xae\x03E\x00\x00\x1f\xc4" + // 0x03AE0345: 0x00001FC4
- "\x03\xb7\x03B\x00\x00\x1f\xc6" + // 0x03B70342: 0x00001FC6
- "\x1f\xc6\x03E\x00\x00\x1f\xc7" + // 0x1FC60345: 0x00001FC7
- "\x03\x95\x03\x00\x00\x00\x1f\xc8" + // 0x03950300: 0x00001FC8
- "\x03\x97\x03\x00\x00\x00\x1f\xca" + // 0x03970300: 0x00001FCA
- "\x03\x97\x03E\x00\x00\x1f\xcc" + // 0x03970345: 0x00001FCC
- "\x1f\xbf\x03\x00\x00\x00\x1f\xcd" + // 0x1FBF0300: 0x00001FCD
- "\x1f\xbf\x03\x01\x00\x00\x1f\xce" + // 0x1FBF0301: 0x00001FCE
- "\x1f\xbf\x03B\x00\x00\x1f\xcf" + // 0x1FBF0342: 0x00001FCF
- "\x03\xb9\x03\x06\x00\x00\x1f\xd0" + // 0x03B90306: 0x00001FD0
- "\x03\xb9\x03\x04\x00\x00\x1f\xd1" + // 0x03B90304: 0x00001FD1
- "\x03\xca\x03\x00\x00\x00\x1f\xd2" + // 0x03CA0300: 0x00001FD2
- "\x03\xb9\x03B\x00\x00\x1f\xd6" + // 0x03B90342: 0x00001FD6
- "\x03\xca\x03B\x00\x00\x1f\xd7" + // 0x03CA0342: 0x00001FD7
- "\x03\x99\x03\x06\x00\x00\x1f\xd8" + // 0x03990306: 0x00001FD8
- "\x03\x99\x03\x04\x00\x00\x1f\xd9" + // 0x03990304: 0x00001FD9
- "\x03\x99\x03\x00\x00\x00\x1f\xda" + // 0x03990300: 0x00001FDA
- "\x1f\xfe\x03\x00\x00\x00\x1f\xdd" + // 0x1FFE0300: 0x00001FDD
- "\x1f\xfe\x03\x01\x00\x00\x1f\xde" + // 0x1FFE0301: 0x00001FDE
- "\x1f\xfe\x03B\x00\x00\x1f\xdf" + // 0x1FFE0342: 0x00001FDF
- "\x03\xc5\x03\x06\x00\x00\x1f\xe0" + // 0x03C50306: 0x00001FE0
- "\x03\xc5\x03\x04\x00\x00\x1f\xe1" + // 0x03C50304: 0x00001FE1
- "\x03\xcb\x03\x00\x00\x00\x1f\xe2" + // 0x03CB0300: 0x00001FE2
- "\x03\xc1\x03\x13\x00\x00\x1f\xe4" + // 0x03C10313: 0x00001FE4
- "\x03\xc1\x03\x14\x00\x00\x1f\xe5" + // 0x03C10314: 0x00001FE5
- "\x03\xc5\x03B\x00\x00\x1f\xe6" + // 0x03C50342: 0x00001FE6
- "\x03\xcb\x03B\x00\x00\x1f\xe7" + // 0x03CB0342: 0x00001FE7
- "\x03\xa5\x03\x06\x00\x00\x1f\xe8" + // 0x03A50306: 0x00001FE8
- "\x03\xa5\x03\x04\x00\x00\x1f\xe9" + // 0x03A50304: 0x00001FE9
- "\x03\xa5\x03\x00\x00\x00\x1f\xea" + // 0x03A50300: 0x00001FEA
- "\x03\xa1\x03\x14\x00\x00\x1f\xec" + // 0x03A10314: 0x00001FEC
- "\x00\xa8\x03\x00\x00\x00\x1f\xed" + // 0x00A80300: 0x00001FED
- "\x1f|\x03E\x00\x00\x1f\xf2" + // 0x1F7C0345: 0x00001FF2
- "\x03\xc9\x03E\x00\x00\x1f\xf3" + // 0x03C90345: 0x00001FF3
- "\x03\xce\x03E\x00\x00\x1f\xf4" + // 0x03CE0345: 0x00001FF4
- "\x03\xc9\x03B\x00\x00\x1f\xf6" + // 0x03C90342: 0x00001FF6
- "\x1f\xf6\x03E\x00\x00\x1f\xf7" + // 0x1FF60345: 0x00001FF7
- "\x03\x9f\x03\x00\x00\x00\x1f\xf8" + // 0x039F0300: 0x00001FF8
- "\x03\xa9\x03\x00\x00\x00\x1f\xfa" + // 0x03A90300: 0x00001FFA
- "\x03\xa9\x03E\x00\x00\x1f\xfc" + // 0x03A90345: 0x00001FFC
- "!\x90\x038\x00\x00!\x9a" + // 0x21900338: 0x0000219A
- "!\x92\x038\x00\x00!\x9b" + // 0x21920338: 0x0000219B
- "!\x94\x038\x00\x00!\xae" + // 0x21940338: 0x000021AE
- "!\xd0\x038\x00\x00!\xcd" + // 0x21D00338: 0x000021CD
- "!\xd4\x038\x00\x00!\xce" + // 0x21D40338: 0x000021CE
- "!\xd2\x038\x00\x00!\xcf" + // 0x21D20338: 0x000021CF
- "\"\x03\x038\x00\x00\"\x04" + // 0x22030338: 0x00002204
- "\"\b\x038\x00\x00\"\t" + // 0x22080338: 0x00002209
- "\"\v\x038\x00\x00\"\f" + // 0x220B0338: 0x0000220C
- "\"#\x038\x00\x00\"$" + // 0x22230338: 0x00002224
- "\"%\x038\x00\x00\"&" + // 0x22250338: 0x00002226
- "\"<\x038\x00\x00\"A" + // 0x223C0338: 0x00002241
- "\"C\x038\x00\x00\"D" + // 0x22430338: 0x00002244
- "\"E\x038\x00\x00\"G" + // 0x22450338: 0x00002247
- "\"H\x038\x00\x00\"I" + // 0x22480338: 0x00002249
- "\x00=\x038\x00\x00\"`" + // 0x003D0338: 0x00002260
- "\"a\x038\x00\x00\"b" + // 0x22610338: 0x00002262
- "\"M\x038\x00\x00\"m" + // 0x224D0338: 0x0000226D
- "\x00<\x038\x00\x00\"n" + // 0x003C0338: 0x0000226E
- "\x00>\x038\x00\x00\"o" + // 0x003E0338: 0x0000226F
- "\"d\x038\x00\x00\"p" + // 0x22640338: 0x00002270
- "\"e\x038\x00\x00\"q" + // 0x22650338: 0x00002271
- "\"r\x038\x00\x00\"t" + // 0x22720338: 0x00002274
- "\"s\x038\x00\x00\"u" + // 0x22730338: 0x00002275
- "\"v\x038\x00\x00\"x" + // 0x22760338: 0x00002278
- "\"w\x038\x00\x00\"y" + // 0x22770338: 0x00002279
- "\"z\x038\x00\x00\"\x80" + // 0x227A0338: 0x00002280
- "\"{\x038\x00\x00\"\x81" + // 0x227B0338: 0x00002281
- "\"\x82\x038\x00\x00\"\x84" + // 0x22820338: 0x00002284
- "\"\x83\x038\x00\x00\"\x85" + // 0x22830338: 0x00002285
- "\"\x86\x038\x00\x00\"\x88" + // 0x22860338: 0x00002288
- "\"\x87\x038\x00\x00\"\x89" + // 0x22870338: 0x00002289
- "\"\xa2\x038\x00\x00\"\xac" + // 0x22A20338: 0x000022AC
- "\"\xa8\x038\x00\x00\"\xad" + // 0x22A80338: 0x000022AD
- "\"\xa9\x038\x00\x00\"\xae" + // 0x22A90338: 0x000022AE
- "\"\xab\x038\x00\x00\"\xaf" + // 0x22AB0338: 0x000022AF
- "\"|\x038\x00\x00\"\xe0" + // 0x227C0338: 0x000022E0
- "\"}\x038\x00\x00\"\xe1" + // 0x227D0338: 0x000022E1
- "\"\x91\x038\x00\x00\"\xe2" + // 0x22910338: 0x000022E2
- "\"\x92\x038\x00\x00\"\xe3" + // 0x22920338: 0x000022E3
- "\"\xb2\x038\x00\x00\"\xea" + // 0x22B20338: 0x000022EA
- "\"\xb3\x038\x00\x00\"\xeb" + // 0x22B30338: 0x000022EB
- "\"\xb4\x038\x00\x00\"\xec" + // 0x22B40338: 0x000022EC
- "\"\xb5\x038\x00\x00\"\xed" + // 0x22B50338: 0x000022ED
- "0K0\x99\x00\x000L" + // 0x304B3099: 0x0000304C
- "0M0\x99\x00\x000N" + // 0x304D3099: 0x0000304E
- "0O0\x99\x00\x000P" + // 0x304F3099: 0x00003050
- "0Q0\x99\x00\x000R" + // 0x30513099: 0x00003052
- "0S0\x99\x00\x000T" + // 0x30533099: 0x00003054
- "0U0\x99\x00\x000V" + // 0x30553099: 0x00003056
- "0W0\x99\x00\x000X" + // 0x30573099: 0x00003058
- "0Y0\x99\x00\x000Z" + // 0x30593099: 0x0000305A
- "0[0\x99\x00\x000\\" + // 0x305B3099: 0x0000305C
- "0]0\x99\x00\x000^" + // 0x305D3099: 0x0000305E
- "0_0\x99\x00\x000`" + // 0x305F3099: 0x00003060
- "0a0\x99\x00\x000b" + // 0x30613099: 0x00003062
- "0d0\x99\x00\x000e" + // 0x30643099: 0x00003065
- "0f0\x99\x00\x000g" + // 0x30663099: 0x00003067
- "0h0\x99\x00\x000i" + // 0x30683099: 0x00003069
- "0o0\x99\x00\x000p" + // 0x306F3099: 0x00003070
- "0o0\x9a\x00\x000q" + // 0x306F309A: 0x00003071
- "0r0\x99\x00\x000s" + // 0x30723099: 0x00003073
- "0r0\x9a\x00\x000t" + // 0x3072309A: 0x00003074
- "0u0\x99\x00\x000v" + // 0x30753099: 0x00003076
- "0u0\x9a\x00\x000w" + // 0x3075309A: 0x00003077
- "0x0\x99\x00\x000y" + // 0x30783099: 0x00003079
- "0x0\x9a\x00\x000z" + // 0x3078309A: 0x0000307A
- "0{0\x99\x00\x000|" + // 0x307B3099: 0x0000307C
- "0{0\x9a\x00\x000}" + // 0x307B309A: 0x0000307D
- "0F0\x99\x00\x000\x94" + // 0x30463099: 0x00003094
- "0\x9d0\x99\x00\x000\x9e" + // 0x309D3099: 0x0000309E
- "0\xab0\x99\x00\x000\xac" + // 0x30AB3099: 0x000030AC
- "0\xad0\x99\x00\x000\xae" + // 0x30AD3099: 0x000030AE
- "0\xaf0\x99\x00\x000\xb0" + // 0x30AF3099: 0x000030B0
- "0\xb10\x99\x00\x000\xb2" + // 0x30B13099: 0x000030B2
- "0\xb30\x99\x00\x000\xb4" + // 0x30B33099: 0x000030B4
- "0\xb50\x99\x00\x000\xb6" + // 0x30B53099: 0x000030B6
- "0\xb70\x99\x00\x000\xb8" + // 0x30B73099: 0x000030B8
- "0\xb90\x99\x00\x000\xba" + // 0x30B93099: 0x000030BA
- "0\xbb0\x99\x00\x000\xbc" + // 0x30BB3099: 0x000030BC
- "0\xbd0\x99\x00\x000\xbe" + // 0x30BD3099: 0x000030BE
- "0\xbf0\x99\x00\x000\xc0" + // 0x30BF3099: 0x000030C0
- "0\xc10\x99\x00\x000\xc2" + // 0x30C13099: 0x000030C2
- "0\xc40\x99\x00\x000\xc5" + // 0x30C43099: 0x000030C5
- "0\xc60\x99\x00\x000\xc7" + // 0x30C63099: 0x000030C7
- "0\xc80\x99\x00\x000\xc9" + // 0x30C83099: 0x000030C9
- "0\xcf0\x99\x00\x000\xd0" + // 0x30CF3099: 0x000030D0
- "0\xcf0\x9a\x00\x000\xd1" + // 0x30CF309A: 0x000030D1
- "0\xd20\x99\x00\x000\xd3" + // 0x30D23099: 0x000030D3
- "0\xd20\x9a\x00\x000\xd4" + // 0x30D2309A: 0x000030D4
- "0\xd50\x99\x00\x000\xd6" + // 0x30D53099: 0x000030D6
- "0\xd50\x9a\x00\x000\xd7" + // 0x30D5309A: 0x000030D7
- "0\xd80\x99\x00\x000\xd9" + // 0x30D83099: 0x000030D9
- "0\xd80\x9a\x00\x000\xda" + // 0x30D8309A: 0x000030DA
- "0\xdb0\x99\x00\x000\xdc" + // 0x30DB3099: 0x000030DC
- "0\xdb0\x9a\x00\x000\xdd" + // 0x30DB309A: 0x000030DD
- "0\xa60\x99\x00\x000\xf4" + // 0x30A63099: 0x000030F4
- "0\xef0\x99\x00\x000\xf7" + // 0x30EF3099: 0x000030F7
- "0\xf00\x99\x00\x000\xf8" + // 0x30F03099: 0x000030F8
- "0\xf10\x99\x00\x000\xf9" + // 0x30F13099: 0x000030F9
- "0\xf20\x99\x00\x000\xfa" + // 0x30F23099: 0x000030FA
- "0\xfd0\x99\x00\x000\xfe" + // 0x30FD3099: 0x000030FE
- "\x05\xd2\x03\a\x00\x01\x05\xc9" + // 0x05D20307: 0x000105C9
- "\x05\xda\x03\a\x00\x01\x05\xe4" + // 0x05DA0307: 0x000105E4
- "\x10\x99\x10\xba\x00\x01\x10\x9a" + // 0x109910BA: 0x0001109A
- "\x10\x9b\x10\xba\x00\x01\x10\x9c" + // 0x109B10BA: 0x0001109C
- "\x10\xa5\x10\xba\x00\x01\x10\xab" + // 0x10A510BA: 0x000110AB
- "\x111\x11'\x00\x01\x11." + // 0x11311127: 0x0001112E
- "\x112\x11'\x00\x01\x11/" + // 0x11321127: 0x0001112F
- "\x13G\x13>\x00\x01\x13K" + // 0x1347133E: 0x0001134B
- "\x13G\x13W\x00\x01\x13L" + // 0x13471357: 0x0001134C
- "\x13\x82\x13\xc9\x00\x01\x13\x83" + // 0x138213C9: 0x00011383
- "\x13\x84\x13\xbb\x00\x01\x13\x85" + // 0x138413BB: 0x00011385
- "\x13\x8b\x13\xc2\x00\x01\x13\x8e" + // 0x138B13C2: 0x0001138E
- "\x13\x90\x13\xc9\x00\x01\x13\x91" + // 0x139013C9: 0x00011391
- "\x13\xc2\x13\xc2\x00\x01\x13\xc5" + // 0x13C213C2: 0x000113C5
- "\x13\xc2\x13\xb8\x00\x01\x13\xc7" + // 0x13C213B8: 0x000113C7
- "\x13\xc2\x13\xc9\x00\x01\x13\xc8" + // 0x13C213C9: 0x000113C8
- "\x14\xb9\x14\xba\x00\x01\x14\xbb" + // 0x14B914BA: 0x000114BB
- "\x14\xb9\x14\xb0\x00\x01\x14\xbc" + // 0x14B914B0: 0x000114BC
- "\x14\xb9\x14\xbd\x00\x01\x14\xbe" + // 0x14B914BD: 0x000114BE
- "\x15\xb8\x15\xaf\x00\x01\x15\xba" + // 0x15B815AF: 0x000115BA
- "\x15\xb9\x15\xaf\x00\x01\x15\xbb" + // 0x15B915AF: 0x000115BB
- "\x195\x190\x00\x01\x198" + // 0x19351930: 0x00011938
- "a\x1ea\x1e\x00\x01a!" + // 0x611E611E: 0x00016121
- "a\x1ea)\x00\x01a\"" + // 0x611E6129: 0x00016122
- "a\x1ea\x1f\x00\x01a#" + // 0x611E611F: 0x00016123
- "a)a\x1f\x00\x01a$" + // 0x6129611F: 0x00016124
- "a\x1ea \x00\x01a%" + // 0x611E6120: 0x00016125
- "a!a\x1f\x00\x01a&" + // 0x6121611F: 0x00016126
- "a\"a\x1f\x00\x01a'" + // 0x6122611F: 0x00016127
- "a!a \x00\x01a(" + // 0x61216120: 0x00016128
- "mgmg\x00\x01mh" + // 0x6D676D67: 0x00016D68
- "mcmg\x00\x01mi" + // 0x6D636D67: 0x00016D69
- "mimg\x00\x01mj" + // 0x6D696D67: 0x00016D6A
+ "\x00\x01\x04\x00`\x00\x00\xc0" + // 0x00041 0x00300: 0x000C0
+ "\x00\x01\x04\x00` \x00\xc1" + // 0x00041 0x00301: 0x000C1
+ "\x00\x01\x04\x00`@\x00\xc2" + // 0x00041 0x00302: 0x000C2
+ "\x00\x01\x04\x00``\x00\xc3" + // 0x00041 0x00303: 0x000C3
+ "\x00\x01\x04\x00a\x00\x00\xc4" + // 0x00041 0x00308: 0x000C4
+ "\x00\x01\x04\x00a@\x00\xc5" + // 0x00041 0x0030A: 0x000C5
+ "\x00\x01\f\x00d\xe0\x00\xc7" + // 0x00043 0x00327: 0x000C7
+ "\x00\x01\x14\x00`\x00\x00\xc8" + // 0x00045 0x00300: 0x000C8
+ "\x00\x01\x14\x00` \x00\xc9" + // 0x00045 0x00301: 0x000C9
+ "\x00\x01\x14\x00`@\x00\xca" + // 0x00045 0x00302: 0x000CA
+ "\x00\x01\x14\x00a\x00\x00\xcb" + // 0x00045 0x00308: 0x000CB
+ "\x00\x01$\x00`\x00\x00\xcc" + // 0x00049 0x00300: 0x000CC
+ "\x00\x01$\x00` \x00\xcd" + // 0x00049 0x00301: 0x000CD
+ "\x00\x01$\x00`@\x00\xce" + // 0x00049 0x00302: 0x000CE
+ "\x00\x01$\x00a\x00\x00\xcf" + // 0x00049 0x00308: 0x000CF
+ "\x00\x018\x00``\x00\xd1" + // 0x0004E 0x00303: 0x000D1
+ "\x00\x01<\x00`\x00\x00\xd2" + // 0x0004F 0x00300: 0x000D2
+ "\x00\x01<\x00` \x00\xd3" + // 0x0004F 0x00301: 0x000D3
+ "\x00\x01<\x00`@\x00\xd4" + // 0x0004F 0x00302: 0x000D4
+ "\x00\x01<\x00``\x00\xd5" + // 0x0004F 0x00303: 0x000D5
+ "\x00\x01<\x00a\x00\x00\xd6" + // 0x0004F 0x00308: 0x000D6
+ "\x00\x01T\x00`\x00\x00\xd9" + // 0x00055 0x00300: 0x000D9
+ "\x00\x01T\x00` \x00\xda" + // 0x00055 0x00301: 0x000DA
+ "\x00\x01T\x00`@\x00\xdb" + // 0x00055 0x00302: 0x000DB
+ "\x00\x01T\x00a\x00\x00\xdc" + // 0x00055 0x00308: 0x000DC
+ "\x00\x01d\x00` \x00\xdd" + // 0x00059 0x00301: 0x000DD
+ "\x00\x01\x84\x00`\x00\x00\xe0" + // 0x00061 0x00300: 0x000E0
+ "\x00\x01\x84\x00` \x00\xe1" + // 0x00061 0x00301: 0x000E1
+ "\x00\x01\x84\x00`@\x00\xe2" + // 0x00061 0x00302: 0x000E2
+ "\x00\x01\x84\x00``\x00\xe3" + // 0x00061 0x00303: 0x000E3
+ "\x00\x01\x84\x00a\x00\x00\xe4" + // 0x00061 0x00308: 0x000E4
+ "\x00\x01\x84\x00a@\x00\xe5" + // 0x00061 0x0030A: 0x000E5
+ "\x00\x01\x8c\x00d\xe0\x00\xe7" + // 0x00063 0x00327: 0x000E7
+ "\x00\x01\x94\x00`\x00\x00\xe8" + // 0x00065 0x00300: 0x000E8
+ "\x00\x01\x94\x00` \x00\xe9" + // 0x00065 0x00301: 0x000E9
+ "\x00\x01\x94\x00`@\x00\xea" + // 0x00065 0x00302: 0x000EA
+ "\x00\x01\x94\x00a\x00\x00\xeb" + // 0x00065 0x00308: 0x000EB
+ "\x00\x01\xa4\x00`\x00\x00\xec" + // 0x00069 0x00300: 0x000EC
+ "\x00\x01\xa4\x00` \x00\xed" + // 0x00069 0x00301: 0x000ED
+ "\x00\x01\xa4\x00`@\x00\xee" + // 0x00069 0x00302: 0x000EE
+ "\x00\x01\xa4\x00a\x00\x00\xef" + // 0x00069 0x00308: 0x000EF
+ "\x00\x01\xb8\x00``\x00\xf1" + // 0x0006E 0x00303: 0x000F1
+ "\x00\x01\xbc\x00`\x00\x00\xf2" + // 0x0006F 0x00300: 0x000F2
+ "\x00\x01\xbc\x00` \x00\xf3" + // 0x0006F 0x00301: 0x000F3
+ "\x00\x01\xbc\x00`@\x00\xf4" + // 0x0006F 0x00302: 0x000F4
+ "\x00\x01\xbc\x00``\x00\xf5" + // 0x0006F 0x00303: 0x000F5
+ "\x00\x01\xbc\x00a\x00\x00\xf6" + // 0x0006F 0x00308: 0x000F6
+ "\x00\x01\xd4\x00`\x00\x00\xf9" + // 0x00075 0x00300: 0x000F9
+ "\x00\x01\xd4\x00` \x00\xfa" + // 0x00075 0x00301: 0x000FA
+ "\x00\x01\xd4\x00`@\x00\xfb" + // 0x00075 0x00302: 0x000FB
+ "\x00\x01\xd4\x00a\x00\x00\xfc" + // 0x00075 0x00308: 0x000FC
+ "\x00\x01\xe4\x00` \x00\xfd" + // 0x00079 0x00301: 0x000FD
+ "\x00\x01\xe4\x00a\x00\x00\xff" + // 0x00079 0x00308: 0x000FF
+ "\x00\x01\x04\x00`\x80\x01\x00" + // 0x00041 0x00304: 0x00100
+ "\x00\x01\x84\x00`\x80\x01\x01" + // 0x00061 0x00304: 0x00101
+ "\x00\x01\x04\x00`\xc0\x01\x02" + // 0x00041 0x00306: 0x00102
+ "\x00\x01\x84\x00`\xc0\x01\x03" + // 0x00061 0x00306: 0x00103
+ "\x00\x01\x04\x00e\x00\x01\x04" + // 0x00041 0x00328: 0x00104
+ "\x00\x01\x84\x00e\x00\x01\x05" + // 0x00061 0x00328: 0x00105
+ "\x00\x01\f\x00` \x01\x06" + // 0x00043 0x00301: 0x00106
+ "\x00\x01\x8c\x00` \x01\a" + // 0x00063 0x00301: 0x00107
+ "\x00\x01\f\x00`@\x01\b" + // 0x00043 0x00302: 0x00108
+ "\x00\x01\x8c\x00`@\x01\t" + // 0x00063 0x00302: 0x00109
+ "\x00\x01\f\x00`\xe0\x01\n" + // 0x00043 0x00307: 0x0010A
+ "\x00\x01\x8c\x00`\xe0\x01\v" + // 0x00063 0x00307: 0x0010B
+ "\x00\x01\f\x00a\x80\x01\f" + // 0x00043 0x0030C: 0x0010C
+ "\x00\x01\x8c\x00a\x80\x01\r" + // 0x00063 0x0030C: 0x0010D
+ "\x00\x01\x10\x00a\x80\x01\x0e" + // 0x00044 0x0030C: 0x0010E
+ "\x00\x01\x90\x00a\x80\x01\x0f" + // 0x00064 0x0030C: 0x0010F
+ "\x00\x01\x14\x00`\x80\x01\x12" + // 0x00045 0x00304: 0x00112
+ "\x00\x01\x94\x00`\x80\x01\x13" + // 0x00065 0x00304: 0x00113
+ "\x00\x01\x14\x00`\xc0\x01\x14" + // 0x00045 0x00306: 0x00114
+ "\x00\x01\x94\x00`\xc0\x01\x15" + // 0x00065 0x00306: 0x00115
+ "\x00\x01\x14\x00`\xe0\x01\x16" + // 0x00045 0x00307: 0x00116
+ "\x00\x01\x94\x00`\xe0\x01\x17" + // 0x00065 0x00307: 0x00117
+ "\x00\x01\x14\x00e\x00\x01\x18" + // 0x00045 0x00328: 0x00118
+ "\x00\x01\x94\x00e\x00\x01\x19" + // 0x00065 0x00328: 0x00119
+ "\x00\x01\x14\x00a\x80\x01\x1a" + // 0x00045 0x0030C: 0x0011A
+ "\x00\x01\x94\x00a\x80\x01\x1b" + // 0x00065 0x0030C: 0x0011B
+ "\x00\x01\x1c\x00`@\x01\x1c" + // 0x00047 0x00302: 0x0011C
+ "\x00\x01\x9c\x00`@\x01\x1d" + // 0x00067 0x00302: 0x0011D
+ "\x00\x01\x1c\x00`\xc0\x01\x1e" + // 0x00047 0x00306: 0x0011E
+ "\x00\x01\x9c\x00`\xc0\x01\x1f" + // 0x00067 0x00306: 0x0011F
+ "\x00\x01\x1c\x00`\xe0\x01 " + // 0x00047 0x00307: 0x00120
+ "\x00\x01\x9c\x00`\xe0\x01!" + // 0x00067 0x00307: 0x00121
+ "\x00\x01\x1c\x00d\xe0\x01\"" + // 0x00047 0x00327: 0x00122
+ "\x00\x01\x9c\x00d\xe0\x01#" + // 0x00067 0x00327: 0x00123
+ "\x00\x01 \x00`@\x01$" + // 0x00048 0x00302: 0x00124
+ "\x00\x01\xa0\x00`@\x01%" + // 0x00068 0x00302: 0x00125
+ "\x00\x01$\x00``\x01(" + // 0x00049 0x00303: 0x00128
+ "\x00\x01\xa4\x00``\x01)" + // 0x00069 0x00303: 0x00129
+ "\x00\x01$\x00`\x80\x01*" + // 0x00049 0x00304: 0x0012A
+ "\x00\x01\xa4\x00`\x80\x01+" + // 0x00069 0x00304: 0x0012B
+ "\x00\x01$\x00`\xc0\x01," + // 0x00049 0x00306: 0x0012C
+ "\x00\x01\xa4\x00`\xc0\x01-" + // 0x00069 0x00306: 0x0012D
+ "\x00\x01$\x00e\x00\x01." + // 0x00049 0x00328: 0x0012E
+ "\x00\x01\xa4\x00e\x00\x01/" + // 0x00069 0x00328: 0x0012F
+ "\x00\x01$\x00`\xe0\x010" + // 0x00049 0x00307: 0x00130
+ "\x00\x01(\x00`@\x014" + // 0x0004A 0x00302: 0x00134
+ "\x00\x01\xa8\x00`@\x015" + // 0x0006A 0x00302: 0x00135
+ "\x00\x01,\x00d\xe0\x016" + // 0x0004B 0x00327: 0x00136
+ "\x00\x01\xac\x00d\xe0\x017" + // 0x0006B 0x00327: 0x00137
+ "\x00\x010\x00` \x019" + // 0x0004C 0x00301: 0x00139
+ "\x00\x01\xb0\x00` \x01:" + // 0x0006C 0x00301: 0x0013A
+ "\x00\x010\x00d\xe0\x01;" + // 0x0004C 0x00327: 0x0013B
+ "\x00\x01\xb0\x00d\xe0\x01<" + // 0x0006C 0x00327: 0x0013C
+ "\x00\x010\x00a\x80\x01=" + // 0x0004C 0x0030C: 0x0013D
+ "\x00\x01\xb0\x00a\x80\x01>" + // 0x0006C 0x0030C: 0x0013E
+ "\x00\x018\x00` \x01C" + // 0x0004E 0x00301: 0x00143
+ "\x00\x01\xb8\x00` \x01D" + // 0x0006E 0x00301: 0x00144
+ "\x00\x018\x00d\xe0\x01E" + // 0x0004E 0x00327: 0x00145
+ "\x00\x01\xb8\x00d\xe0\x01F" + // 0x0006E 0x00327: 0x00146
+ "\x00\x018\x00a\x80\x01G" + // 0x0004E 0x0030C: 0x00147
+ "\x00\x01\xb8\x00a\x80\x01H" + // 0x0006E 0x0030C: 0x00148
+ "\x00\x01<\x00`\x80\x01L" + // 0x0004F 0x00304: 0x0014C
+ "\x00\x01\xbc\x00`\x80\x01M" + // 0x0006F 0x00304: 0x0014D
+ "\x00\x01<\x00`\xc0\x01N" + // 0x0004F 0x00306: 0x0014E
+ "\x00\x01\xbc\x00`\xc0\x01O" + // 0x0006F 0x00306: 0x0014F
+ "\x00\x01<\x00a`\x01P" + // 0x0004F 0x0030B: 0x00150
+ "\x00\x01\xbc\x00a`\x01Q" + // 0x0006F 0x0030B: 0x00151
+ "\x00\x01H\x00` \x01T" + // 0x00052 0x00301: 0x00154
+ "\x00\x01\xc8\x00` \x01U" + // 0x00072 0x00301: 0x00155
+ "\x00\x01H\x00d\xe0\x01V" + // 0x00052 0x00327: 0x00156
+ "\x00\x01\xc8\x00d\xe0\x01W" + // 0x00072 0x00327: 0x00157
+ "\x00\x01H\x00a\x80\x01X" + // 0x00052 0x0030C: 0x00158
+ "\x00\x01\xc8\x00a\x80\x01Y" + // 0x00072 0x0030C: 0x00159
+ "\x00\x01L\x00` \x01Z" + // 0x00053 0x00301: 0x0015A
+ "\x00\x01\xcc\x00` \x01[" + // 0x00073 0x00301: 0x0015B
+ "\x00\x01L\x00`@\x01\\" + // 0x00053 0x00302: 0x0015C
+ "\x00\x01\xcc\x00`@\x01]" + // 0x00073 0x00302: 0x0015D
+ "\x00\x01L\x00d\xe0\x01^" + // 0x00053 0x00327: 0x0015E
+ "\x00\x01\xcc\x00d\xe0\x01_" + // 0x00073 0x00327: 0x0015F
+ "\x00\x01L\x00a\x80\x01`" + // 0x00053 0x0030C: 0x00160
+ "\x00\x01\xcc\x00a\x80\x01a" + // 0x00073 0x0030C: 0x00161
+ "\x00\x01P\x00d\xe0\x01b" + // 0x00054 0x00327: 0x00162
+ "\x00\x01\xd0\x00d\xe0\x01c" + // 0x00074 0x00327: 0x00163
+ "\x00\x01P\x00a\x80\x01d" + // 0x00054 0x0030C: 0x00164
+ "\x00\x01\xd0\x00a\x80\x01e" + // 0x00074 0x0030C: 0x00165
+ "\x00\x01T\x00``\x01h" + // 0x00055 0x00303: 0x00168
+ "\x00\x01\xd4\x00``\x01i" + // 0x00075 0x00303: 0x00169
+ "\x00\x01T\x00`\x80\x01j" + // 0x00055 0x00304: 0x0016A
+ "\x00\x01\xd4\x00`\x80\x01k" + // 0x00075 0x00304: 0x0016B
+ "\x00\x01T\x00`\xc0\x01l" + // 0x00055 0x00306: 0x0016C
+ "\x00\x01\xd4\x00`\xc0\x01m" + // 0x00075 0x00306: 0x0016D
+ "\x00\x01T\x00a@\x01n" + // 0x00055 0x0030A: 0x0016E
+ "\x00\x01\xd4\x00a@\x01o" + // 0x00075 0x0030A: 0x0016F
+ "\x00\x01T\x00a`\x01p" + // 0x00055 0x0030B: 0x00170
+ "\x00\x01\xd4\x00a`\x01q" + // 0x00075 0x0030B: 0x00171
+ "\x00\x01T\x00e\x00\x01r" + // 0x00055 0x00328: 0x00172
+ "\x00\x01\xd4\x00e\x00\x01s" + // 0x00075 0x00328: 0x00173
+ "\x00\x01\\\x00`@\x01t" + // 0x00057 0x00302: 0x00174
+ "\x00\x01\xdc\x00`@\x01u" + // 0x00077 0x00302: 0x00175
+ "\x00\x01d\x00`@\x01v" + // 0x00059 0x00302: 0x00176
+ "\x00\x01\xe4\x00`@\x01w" + // 0x00079 0x00302: 0x00177
+ "\x00\x01d\x00a\x00\x01x" + // 0x00059 0x00308: 0x00178
+ "\x00\x01h\x00` \x01y" + // 0x0005A 0x00301: 0x00179
+ "\x00\x01\xe8\x00` \x01z" + // 0x0007A 0x00301: 0x0017A
+ "\x00\x01h\x00`\xe0\x01{" + // 0x0005A 0x00307: 0x0017B
+ "\x00\x01\xe8\x00`\xe0\x01|" + // 0x0007A 0x00307: 0x0017C
+ "\x00\x01h\x00a\x80\x01}" + // 0x0005A 0x0030C: 0x0017D
+ "\x00\x01\xe8\x00a\x80\x01~" + // 0x0007A 0x0030C: 0x0017E
+ "\x00\x01<\x00c`\x01\xa0" + // 0x0004F 0x0031B: 0x001A0
+ "\x00\x01\xbc\x00c`\x01\xa1" + // 0x0006F 0x0031B: 0x001A1
+ "\x00\x01T\x00c`\x01\xaf" + // 0x00055 0x0031B: 0x001AF
+ "\x00\x01\xd4\x00c`\x01\xb0" + // 0x00075 0x0031B: 0x001B0
+ "\x00\x01\x04\x00a\x80\x01\xcd" + // 0x00041 0x0030C: 0x001CD
+ "\x00\x01\x84\x00a\x80\x01\xce" + // 0x00061 0x0030C: 0x001CE
+ "\x00\x01$\x00a\x80\x01\xcf" + // 0x00049 0x0030C: 0x001CF
+ "\x00\x01\xa4\x00a\x80\x01\xd0" + // 0x00069 0x0030C: 0x001D0
+ "\x00\x01<\x00a\x80\x01\xd1" + // 0x0004F 0x0030C: 0x001D1
+ "\x00\x01\xbc\x00a\x80\x01\xd2" + // 0x0006F 0x0030C: 0x001D2
+ "\x00\x01T\x00a\x80\x01\xd3" + // 0x00055 0x0030C: 0x001D3
+ "\x00\x01\xd4\x00a\x80\x01\xd4" + // 0x00075 0x0030C: 0x001D4
+ "\x00\x03p\x00`\x80\x01\xd5" + // 0x000DC 0x00304: 0x001D5
+ "\x00\x03\xf0\x00`\x80\x01\xd6" + // 0x000FC 0x00304: 0x001D6
+ "\x00\x03p\x00` \x01\xd7" + // 0x000DC 0x00301: 0x001D7
+ "\x00\x03\xf0\x00` \x01\xd8" + // 0x000FC 0x00301: 0x001D8
+ "\x00\x03p\x00a\x80\x01\xd9" + // 0x000DC 0x0030C: 0x001D9
+ "\x00\x03\xf0\x00a\x80\x01\xda" + // 0x000FC 0x0030C: 0x001DA
+ "\x00\x03p\x00`\x00\x01\xdb" + // 0x000DC 0x00300: 0x001DB
+ "\x00\x03\xf0\x00`\x00\x01\xdc" + // 0x000FC 0x00300: 0x001DC
+ "\x00\x03\x10\x00`\x80\x01\xde" + // 0x000C4 0x00304: 0x001DE
+ "\x00\x03\x90\x00`\x80\x01\xdf" + // 0x000E4 0x00304: 0x001DF
+ "\x00\b\x98\x00`\x80\x01\xe0" + // 0x00226 0x00304: 0x001E0
+ "\x00\b\x9c\x00`\x80\x01\xe1" + // 0x00227 0x00304: 0x001E1
+ "\x00\x03\x18\x00`\x80\x01\xe2" + // 0x000C6 0x00304: 0x001E2
+ "\x00\x03\x98\x00`\x80\x01\xe3" + // 0x000E6 0x00304: 0x001E3
+ "\x00\x01\x1c\x00a\x80\x01\xe6" + // 0x00047 0x0030C: 0x001E6
+ "\x00\x01\x9c\x00a\x80\x01\xe7" + // 0x00067 0x0030C: 0x001E7
+ "\x00\x01,\x00a\x80\x01\xe8" + // 0x0004B 0x0030C: 0x001E8
+ "\x00\x01\xac\x00a\x80\x01\xe9" + // 0x0006B 0x0030C: 0x001E9
+ "\x00\x01<\x00e\x00\x01\xea" + // 0x0004F 0x00328: 0x001EA
+ "\x00\x01\xbc\x00e\x00\x01\xeb" + // 0x0006F 0x00328: 0x001EB
+ "\x00\a\xa8\x00`\x80\x01\xec" + // 0x001EA 0x00304: 0x001EC
+ "\x00\a\xac\x00`\x80\x01\xed" + // 0x001EB 0x00304: 0x001ED
+ "\x00\x06\xdc\x00a\x80\x01\xee" + // 0x001B7 0x0030C: 0x001EE
+ "\x00\nH\x00a\x80\x01\xef" + // 0x00292 0x0030C: 0x001EF
+ "\x00\x01\xa8\x00a\x80\x01\xf0" + // 0x0006A 0x0030C: 0x001F0
+ "\x00\x01\x1c\x00` \x01\xf4" + // 0x00047 0x00301: 0x001F4
+ "\x00\x01\x9c\x00` \x01\xf5" + // 0x00067 0x00301: 0x001F5
+ "\x00\x018\x00`\x00\x01\xf8" + // 0x0004E 0x00300: 0x001F8
+ "\x00\x01\xb8\x00`\x00\x01\xf9" + // 0x0006E 0x00300: 0x001F9
+ "\x00\x03\x14\x00` \x01\xfa" + // 0x000C5 0x00301: 0x001FA
+ "\x00\x03\x94\x00` \x01\xfb" + // 0x000E5 0x00301: 0x001FB
+ "\x00\x03\x18\x00` \x01\xfc" + // 0x000C6 0x00301: 0x001FC
+ "\x00\x03\x98\x00` \x01\xfd" + // 0x000E6 0x00301: 0x001FD
+ "\x00\x03`\x00` \x01\xfe" + // 0x000D8 0x00301: 0x001FE
+ "\x00\x03\xe0\x00` \x01\xff" + // 0x000F8 0x00301: 0x001FF
+ "\x00\x01\x04\x00a\xe0\x02\x00" + // 0x00041 0x0030F: 0x00200
+ "\x00\x01\x84\x00a\xe0\x02\x01" + // 0x00061 0x0030F: 0x00201
+ "\x00\x01\x04\x00b \x02\x02" + // 0x00041 0x00311: 0x00202
+ "\x00\x01\x84\x00b \x02\x03" + // 0x00061 0x00311: 0x00203
+ "\x00\x01\x14\x00a\xe0\x02\x04" + // 0x00045 0x0030F: 0x00204
+ "\x00\x01\x94\x00a\xe0\x02\x05" + // 0x00065 0x0030F: 0x00205
+ "\x00\x01\x14\x00b \x02\x06" + // 0x00045 0x00311: 0x00206
+ "\x00\x01\x94\x00b \x02\a" + // 0x00065 0x00311: 0x00207
+ "\x00\x01$\x00a\xe0\x02\b" + // 0x00049 0x0030F: 0x00208
+ "\x00\x01\xa4\x00a\xe0\x02\t" + // 0x00069 0x0030F: 0x00209
+ "\x00\x01$\x00b \x02\n" + // 0x00049 0x00311: 0x0020A
+ "\x00\x01\xa4\x00b \x02\v" + // 0x00069 0x00311: 0x0020B
+ "\x00\x01<\x00a\xe0\x02\f" + // 0x0004F 0x0030F: 0x0020C
+ "\x00\x01\xbc\x00a\xe0\x02\r" + // 0x0006F 0x0030F: 0x0020D
+ "\x00\x01<\x00b \x02\x0e" + // 0x0004F 0x00311: 0x0020E
+ "\x00\x01\xbc\x00b \x02\x0f" + // 0x0006F 0x00311: 0x0020F
+ "\x00\x01H\x00a\xe0\x02\x10" + // 0x00052 0x0030F: 0x00210
+ "\x00\x01\xc8\x00a\xe0\x02\x11" + // 0x00072 0x0030F: 0x00211
+ "\x00\x01H\x00b \x02\x12" + // 0x00052 0x00311: 0x00212
+ "\x00\x01\xc8\x00b \x02\x13" + // 0x00072 0x00311: 0x00213
+ "\x00\x01T\x00a\xe0\x02\x14" + // 0x00055 0x0030F: 0x00214
+ "\x00\x01\xd4\x00a\xe0\x02\x15" + // 0x00075 0x0030F: 0x00215
+ "\x00\x01T\x00b \x02\x16" + // 0x00055 0x00311: 0x00216
+ "\x00\x01\xd4\x00b \x02\x17" + // 0x00075 0x00311: 0x00217
+ "\x00\x01L\x00d\xc0\x02\x18" + // 0x00053 0x00326: 0x00218
+ "\x00\x01\xcc\x00d\xc0\x02\x19" + // 0x00073 0x00326: 0x00219
+ "\x00\x01P\x00d\xc0\x02\x1a" + // 0x00054 0x00326: 0x0021A
+ "\x00\x01\xd0\x00d\xc0\x02\x1b" + // 0x00074 0x00326: 0x0021B
+ "\x00\x01 \x00a\x80\x02\x1e" + // 0x00048 0x0030C: 0x0021E
+ "\x00\x01\xa0\x00a\x80\x02\x1f" + // 0x00068 0x0030C: 0x0021F
+ "\x00\x01\x04\x00`\xe0\x02&" + // 0x00041 0x00307: 0x00226
+ "\x00\x01\x84\x00`\xe0\x02'" + // 0x00061 0x00307: 0x00227
+ "\x00\x01\x14\x00d\xe0\x02(" + // 0x00045 0x00327: 0x00228
+ "\x00\x01\x94\x00d\xe0\x02)" + // 0x00065 0x00327: 0x00229
+ "\x00\x03X\x00`\x80\x02*" + // 0x000D6 0x00304: 0x0022A
+ "\x00\x03\xd8\x00`\x80\x02+" + // 0x000F6 0x00304: 0x0022B
+ "\x00\x03T\x00`\x80\x02," + // 0x000D5 0x00304: 0x0022C
+ "\x00\x03\xd4\x00`\x80\x02-" + // 0x000F5 0x00304: 0x0022D
+ "\x00\x01<\x00`\xe0\x02." + // 0x0004F 0x00307: 0x0022E
+ "\x00\x01\xbc\x00`\xe0\x02/" + // 0x0006F 0x00307: 0x0022F
+ "\x00\b\xb8\x00`\x80\x020" + // 0x0022E 0x00304: 0x00230
+ "\x00\b\xbc\x00`\x80\x021" + // 0x0022F 0x00304: 0x00231
+ "\x00\x01d\x00`\x80\x022" + // 0x00059 0x00304: 0x00232
+ "\x00\x01\xe4\x00`\x80\x023" + // 0x00079 0x00304: 0x00233
+ "\x00\x02\xa0\x00` \x03\x85" + // 0x000A8 0x00301: 0x00385
+ "\x00\x0eD\x00` \x03\x86" + // 0x00391 0x00301: 0x00386
+ "\x00\x0eT\x00` \x03\x88" + // 0x00395 0x00301: 0x00388
+ "\x00\x0e\\\x00` \x03\x89" + // 0x00397 0x00301: 0x00389
+ "\x00\x0ed\x00` \x03\x8a" + // 0x00399 0x00301: 0x0038A
+ "\x00\x0e|\x00` \x03\x8c" + // 0x0039F 0x00301: 0x0038C
+ "\x00\x0e\x94\x00` \x03\x8e" + // 0x003A5 0x00301: 0x0038E
+ "\x00\x0e\xa4\x00` \x03\x8f" + // 0x003A9 0x00301: 0x0038F
+ "\x00\x0f(\x00` \x03\x90" + // 0x003CA 0x00301: 0x00390
+ "\x00\x0ed\x00a\x00\x03\xaa" + // 0x00399 0x00308: 0x003AA
+ "\x00\x0e\x94\x00a\x00\x03\xab" + // 0x003A5 0x00308: 0x003AB
+ "\x00\x0e\xc4\x00` \x03\xac" + // 0x003B1 0x00301: 0x003AC
+ "\x00\x0e\xd4\x00` \x03\xad" + // 0x003B5 0x00301: 0x003AD
+ "\x00\x0e\xdc\x00` \x03\xae" + // 0x003B7 0x00301: 0x003AE
+ "\x00\x0e\xe4\x00` \x03\xaf" + // 0x003B9 0x00301: 0x003AF
+ "\x00\x0f,\x00` \x03\xb0" + // 0x003CB 0x00301: 0x003B0
+ "\x00\x0e\xe4\x00a\x00\x03\xca" + // 0x003B9 0x00308: 0x003CA
+ "\x00\x0f\x14\x00a\x00\x03\xcb" + // 0x003C5 0x00308: 0x003CB
+ "\x00\x0e\xfc\x00` \x03\xcc" + // 0x003BF 0x00301: 0x003CC
+ "\x00\x0f\x14\x00` \x03\xcd" + // 0x003C5 0x00301: 0x003CD
+ "\x00\x0f$\x00` \x03\xce" + // 0x003C9 0x00301: 0x003CE
+ "\x00\x0fH\x00` \x03\xd3" + // 0x003D2 0x00301: 0x003D3
+ "\x00\x0fH\x00a\x00\x03\xd4" + // 0x003D2 0x00308: 0x003D4
+ "\x00\x10T\x00`\x00\x04\x00" + // 0x00415 0x00300: 0x00400
+ "\x00\x10T\x00a\x00\x04\x01" + // 0x00415 0x00308: 0x00401
+ "\x00\x10L\x00` \x04\x03" + // 0x00413 0x00301: 0x00403
+ "\x00\x10\x18\x00a\x00\x04\a" + // 0x00406 0x00308: 0x00407
+ "\x00\x10h\x00` \x04\f" + // 0x0041A 0x00301: 0x0040C
+ "\x00\x10`\x00`\x00\x04\r" + // 0x00418 0x00300: 0x0040D
+ "\x00\x10\x8c\x00`\xc0\x04\x0e" + // 0x00423 0x00306: 0x0040E
+ "\x00\x10`\x00`\xc0\x04\x19" + // 0x00418 0x00306: 0x00419
+ "\x00\x10\xe0\x00`\xc0\x049" + // 0x00438 0x00306: 0x00439
+ "\x00\x10\xd4\x00`\x00\x04P" + // 0x00435 0x00300: 0x00450
+ "\x00\x10\xd4\x00a\x00\x04Q" + // 0x00435 0x00308: 0x00451
+ "\x00\x10\xcc\x00` \x04S" + // 0x00433 0x00301: 0x00453
+ "\x00\x11X\x00a\x00\x04W" + // 0x00456 0x00308: 0x00457
+ "\x00\x10\xe8\x00` \x04\\" + // 0x0043A 0x00301: 0x0045C
+ "\x00\x10\xe0\x00`\x00\x04]" + // 0x00438 0x00300: 0x0045D
+ "\x00\x11\f\x00`\xc0\x04^" + // 0x00443 0x00306: 0x0045E
+ "\x00\x11\xd0\x00a\xe0\x04v" + // 0x00474 0x0030F: 0x00476
+ "\x00\x11\xd4\x00a\xe0\x04w" + // 0x00475 0x0030F: 0x00477
+ "\x00\x10X\x00`\xc0\x04\xc1" + // 0x00416 0x00306: 0x004C1
+ "\x00\x10\xd8\x00`\xc0\x04\xc2" + // 0x00436 0x00306: 0x004C2
+ "\x00\x10@\x00`\xc0\x04\xd0" + // 0x00410 0x00306: 0x004D0
+ "\x00\x10\xc0\x00`\xc0\x04\xd1" + // 0x00430 0x00306: 0x004D1
+ "\x00\x10@\x00a\x00\x04\xd2" + // 0x00410 0x00308: 0x004D2
+ "\x00\x10\xc0\x00a\x00\x04\xd3" + // 0x00430 0x00308: 0x004D3
+ "\x00\x10T\x00`\xc0\x04\xd6" + // 0x00415 0x00306: 0x004D6
+ "\x00\x10\xd4\x00`\xc0\x04\xd7" + // 0x00435 0x00306: 0x004D7
+ "\x00\x13`\x00a\x00\x04\xda" + // 0x004D8 0x00308: 0x004DA
+ "\x00\x13d\x00a\x00\x04\xdb" + // 0x004D9 0x00308: 0x004DB
+ "\x00\x10X\x00a\x00\x04\xdc" + // 0x00416 0x00308: 0x004DC
+ "\x00\x10\xd8\x00a\x00\x04\xdd" + // 0x00436 0x00308: 0x004DD
+ "\x00\x10\\\x00a\x00\x04\xde" + // 0x00417 0x00308: 0x004DE
+ "\x00\x10\xdc\x00a\x00\x04\xdf" + // 0x00437 0x00308: 0x004DF
+ "\x00\x10`\x00`\x80\x04\xe2" + // 0x00418 0x00304: 0x004E2
+ "\x00\x10\xe0\x00`\x80\x04\xe3" + // 0x00438 0x00304: 0x004E3
+ "\x00\x10`\x00a\x00\x04\xe4" + // 0x00418 0x00308: 0x004E4
+ "\x00\x10\xe0\x00a\x00\x04\xe5" + // 0x00438 0x00308: 0x004E5
+ "\x00\x10x\x00a\x00\x04\xe6" + // 0x0041E 0x00308: 0x004E6
+ "\x00\x10\xf8\x00a\x00\x04\xe7" + // 0x0043E 0x00308: 0x004E7
+ "\x00\x13\xa0\x00a\x00\x04\xea" + // 0x004E8 0x00308: 0x004EA
+ "\x00\x13\xa4\x00a\x00\x04\xeb" + // 0x004E9 0x00308: 0x004EB
+ "\x00\x10\xb4\x00a\x00\x04\xec" + // 0x0042D 0x00308: 0x004EC
+ "\x00\x114\x00a\x00\x04\xed" + // 0x0044D 0x00308: 0x004ED
+ "\x00\x10\x8c\x00`\x80\x04\xee" + // 0x00423 0x00304: 0x004EE
+ "\x00\x11\f\x00`\x80\x04\xef" + // 0x00443 0x00304: 0x004EF
+ "\x00\x10\x8c\x00a\x00\x04\xf0" + // 0x00423 0x00308: 0x004F0
+ "\x00\x11\f\x00a\x00\x04\xf1" + // 0x00443 0x00308: 0x004F1
+ "\x00\x10\x8c\x00a`\x04\xf2" + // 0x00423 0x0030B: 0x004F2
+ "\x00\x11\f\x00a`\x04\xf3" + // 0x00443 0x0030B: 0x004F3
+ "\x00\x10\x9c\x00a\x00\x04\xf4" + // 0x00427 0x00308: 0x004F4
+ "\x00\x11\x1c\x00a\x00\x04\xf5" + // 0x00447 0x00308: 0x004F5
+ "\x00\x10\xac\x00a\x00\x04\xf8" + // 0x0042B 0x00308: 0x004F8
+ "\x00\x11,\x00a\x00\x04\xf9" + // 0x0044B 0x00308: 0x004F9
+ "\x00\x18\x9c\x00\xca`\x06\"" + // 0x00627 0x00653: 0x00622
+ "\x00\x18\x9c\x00ʀ\x06#" + // 0x00627 0x00654: 0x00623
+ "\x00\x19 \x00ʀ\x06$" + // 0x00648 0x00654: 0x00624
+ "\x00\x18\x9c\x00ʠ\x06%" + // 0x00627 0x00655: 0x00625
+ "\x00\x19(\x00ʀ\x06&" + // 0x0064A 0x00654: 0x00626
+ "\x00\x1bT\x00ʀ\x06\xc0" + // 0x006D5 0x00654: 0x006C0
+ "\x00\x1b\x04\x00ʀ\x06\xc2" + // 0x006C1 0x00654: 0x006C2
+ "\x00\x1bH\x00ʀ\x06\xd3" + // 0x006D2 0x00654: 0x006D3
+ "\x00$\xa0\x01'\x80\t)" + // 0x00928 0x0093C: 0x00929
+ "\x00$\xc0\x01'\x80\t1" + // 0x00930 0x0093C: 0x00931
+ "\x00$\xcc\x01'\x80\t4" + // 0x00933 0x0093C: 0x00934
+ "\x00'\x1c\x017\xc0\t\xcb" + // 0x009C7 0x009BE: 0x009CB
+ "\x00'\x1c\x01:\xe0\t\xcc" + // 0x009C7 0x009D7: 0x009CC
+ "\x00-\x1c\x01j\xc0\vH" + // 0x00B47 0x00B56: 0x00B48
+ "\x00-\x1c\x01g\xc0\vK" + // 0x00B47 0x00B3E: 0x00B4B
+ "\x00-\x1c\x01j\xe0\vL" + // 0x00B47 0x00B57: 0x00B4C
+ "\x00.H\x01z\xe0\v\x94" + // 0x00B92 0x00BD7: 0x00B94
+ "\x00/\x18\x01w\xc0\v\xca" + // 0x00BC6 0x00BBE: 0x00BCA
+ "\x00/\x1c\x01w\xc0\v\xcb" + // 0x00BC7 0x00BBE: 0x00BCB
+ "\x00/\x18\x01z\xe0\v\xcc" + // 0x00BC6 0x00BD7: 0x00BCC
+ "\x001\x18\x01\x8a\xc0\fH" + // 0x00C46 0x00C56: 0x00C48
+ "\x002\xfc\x01\x9a\xa0\f\xc0" + // 0x00CBF 0x00CD5: 0x00CC0
+ "\x003\x18\x01\x9a\xa0\f\xc7" + // 0x00CC6 0x00CD5: 0x00CC7
+ "\x003\x18\x01\x9a\xc0\f\xc8" + // 0x00CC6 0x00CD6: 0x00CC8
+ "\x003\x18\x01\x98@\f\xca" + // 0x00CC6 0x00CC2: 0x00CCA
+ "\x003(\x01\x9a\xa0\f\xcb" + // 0x00CCA 0x00CD5: 0x00CCB
+ "\x005\x18\x01\xa7\xc0\rJ" + // 0x00D46 0x00D3E: 0x00D4A
+ "\x005\x1c\x01\xa7\xc0\rK" + // 0x00D47 0x00D3E: 0x00D4B
+ "\x005\x18\x01\xaa\xe0\rL" + // 0x00D46 0x00D57: 0x00D4C
+ "\x007d\x01\xb9@\r\xda" + // 0x00DD9 0x00DCA: 0x00DDA
+ "\x007d\x01\xb9\xe0\r\xdc" + // 0x00DD9 0x00DCF: 0x00DDC
+ "\x007p\x01\xb9@\r\xdd" + // 0x00DDC 0x00DCA: 0x00DDD
+ "\x007d\x01\xbb\xe0\r\xde" + // 0x00DD9 0x00DDF: 0x00DDE
+ "\x00@\x94\x02\x05\xc0\x10&" + // 0x01025 0x0102E: 0x01026
+ "\x00l\x14\x03f\xa0\x1b\x06" + // 0x01B05 0x01B35: 0x01B06
+ "\x00l\x1c\x03f\xa0\x1b\b" + // 0x01B07 0x01B35: 0x01B08
+ "\x00l$\x03f\xa0\x1b\n" + // 0x01B09 0x01B35: 0x01B0A
+ "\x00l,\x03f\xa0\x1b\f" + // 0x01B0B 0x01B35: 0x01B0C
+ "\x00l4\x03f\xa0\x1b\x0e" + // 0x01B0D 0x01B35: 0x01B0E
+ "\x00lD\x03f\xa0\x1b\x12" + // 0x01B11 0x01B35: 0x01B12
+ "\x00l\xe8\x03f\xa0\x1b;" + // 0x01B3A 0x01B35: 0x01B3B
+ "\x00l\xf0\x03f\xa0\x1b=" + // 0x01B3C 0x01B35: 0x01B3D
+ "\x00l\xf8\x03f\xa0\x1b@" + // 0x01B3E 0x01B35: 0x01B40
+ "\x00l\xfc\x03f\xa0\x1bA" + // 0x01B3F 0x01B35: 0x01B41
+ "\x00m\b\x03f\xa0\x1bC" + // 0x01B42 0x01B35: 0x01B43
+ "\x00\x01\x04\x00d\xa0\x1e\x00" + // 0x00041 0x00325: 0x01E00
+ "\x00\x01\x84\x00d\xa0\x1e\x01" + // 0x00061 0x00325: 0x01E01
+ "\x00\x01\b\x00`\xe0\x1e\x02" + // 0x00042 0x00307: 0x01E02
+ "\x00\x01\x88\x00`\xe0\x1e\x03" + // 0x00062 0x00307: 0x01E03
+ "\x00\x01\b\x00d`\x1e\x04" + // 0x00042 0x00323: 0x01E04
+ "\x00\x01\x88\x00d`\x1e\x05" + // 0x00062 0x00323: 0x01E05
+ "\x00\x01\b\x00f \x1e\x06" + // 0x00042 0x00331: 0x01E06
+ "\x00\x01\x88\x00f \x1e\a" + // 0x00062 0x00331: 0x01E07
+ "\x00\x03\x1c\x00` \x1e\b" + // 0x000C7 0x00301: 0x01E08
+ "\x00\x03\x9c\x00` \x1e\t" + // 0x000E7 0x00301: 0x01E09
+ "\x00\x01\x10\x00`\xe0\x1e\n" + // 0x00044 0x00307: 0x01E0A
+ "\x00\x01\x90\x00`\xe0\x1e\v" + // 0x00064 0x00307: 0x01E0B
+ "\x00\x01\x10\x00d`\x1e\f" + // 0x00044 0x00323: 0x01E0C
+ "\x00\x01\x90\x00d`\x1e\r" + // 0x00064 0x00323: 0x01E0D
+ "\x00\x01\x10\x00f \x1e\x0e" + // 0x00044 0x00331: 0x01E0E
+ "\x00\x01\x90\x00f \x1e\x0f" + // 0x00064 0x00331: 0x01E0F
+ "\x00\x01\x10\x00d\xe0\x1e\x10" + // 0x00044 0x00327: 0x01E10
+ "\x00\x01\x90\x00d\xe0\x1e\x11" + // 0x00064 0x00327: 0x01E11
+ "\x00\x01\x10\x00e\xa0\x1e\x12" + // 0x00044 0x0032D: 0x01E12
+ "\x00\x01\x90\x00e\xa0\x1e\x13" + // 0x00064 0x0032D: 0x01E13
+ "\x00\x04H\x00`\x00\x1e\x14" + // 0x00112 0x00300: 0x01E14
+ "\x00\x04L\x00`\x00\x1e\x15" + // 0x00113 0x00300: 0x01E15
+ "\x00\x04H\x00` \x1e\x16" + // 0x00112 0x00301: 0x01E16
+ "\x00\x04L\x00` \x1e\x17" + // 0x00113 0x00301: 0x01E17
+ "\x00\x01\x14\x00e\xa0\x1e\x18" + // 0x00045 0x0032D: 0x01E18
+ "\x00\x01\x94\x00e\xa0\x1e\x19" + // 0x00065 0x0032D: 0x01E19
+ "\x00\x01\x14\x00f\x00\x1e\x1a" + // 0x00045 0x00330: 0x01E1A
+ "\x00\x01\x94\x00f\x00\x1e\x1b" + // 0x00065 0x00330: 0x01E1B
+ "\x00\b\xa0\x00`\xc0\x1e\x1c" + // 0x00228 0x00306: 0x01E1C
+ "\x00\b\xa4\x00`\xc0\x1e\x1d" + // 0x00229 0x00306: 0x01E1D
+ "\x00\x01\x18\x00`\xe0\x1e\x1e" + // 0x00046 0x00307: 0x01E1E
+ "\x00\x01\x98\x00`\xe0\x1e\x1f" + // 0x00066 0x00307: 0x01E1F
+ "\x00\x01\x1c\x00`\x80\x1e " + // 0x00047 0x00304: 0x01E20
+ "\x00\x01\x9c\x00`\x80\x1e!" + // 0x00067 0x00304: 0x01E21
+ "\x00\x01 \x00`\xe0\x1e\"" + // 0x00048 0x00307: 0x01E22
+ "\x00\x01\xa0\x00`\xe0\x1e#" + // 0x00068 0x00307: 0x01E23
+ "\x00\x01 \x00d`\x1e$" + // 0x00048 0x00323: 0x01E24
+ "\x00\x01\xa0\x00d`\x1e%" + // 0x00068 0x00323: 0x01E25
+ "\x00\x01 \x00a\x00\x1e&" + // 0x00048 0x00308: 0x01E26
+ "\x00\x01\xa0\x00a\x00\x1e'" + // 0x00068 0x00308: 0x01E27
+ "\x00\x01 \x00d\xe0\x1e(" + // 0x00048 0x00327: 0x01E28
+ "\x00\x01\xa0\x00d\xe0\x1e)" + // 0x00068 0x00327: 0x01E29
+ "\x00\x01 \x00e\xc0\x1e*" + // 0x00048 0x0032E: 0x01E2A
+ "\x00\x01\xa0\x00e\xc0\x1e+" + // 0x00068 0x0032E: 0x01E2B
+ "\x00\x01$\x00f\x00\x1e," + // 0x00049 0x00330: 0x01E2C
+ "\x00\x01\xa4\x00f\x00\x1e-" + // 0x00069 0x00330: 0x01E2D
+ "\x00\x03<\x00` \x1e." + // 0x000CF 0x00301: 0x01E2E
+ "\x00\x03\xbc\x00` \x1e/" + // 0x000EF 0x00301: 0x01E2F
+ "\x00\x01,\x00` \x1e0" + // 0x0004B 0x00301: 0x01E30
+ "\x00\x01\xac\x00` \x1e1" + // 0x0006B 0x00301: 0x01E31
+ "\x00\x01,\x00d`\x1e2" + // 0x0004B 0x00323: 0x01E32
+ "\x00\x01\xac\x00d`\x1e3" + // 0x0006B 0x00323: 0x01E33
+ "\x00\x01,\x00f \x1e4" + // 0x0004B 0x00331: 0x01E34
+ "\x00\x01\xac\x00f \x1e5" + // 0x0006B 0x00331: 0x01E35
+ "\x00\x010\x00d`\x1e6" + // 0x0004C 0x00323: 0x01E36
+ "\x00\x01\xb0\x00d`\x1e7" + // 0x0006C 0x00323: 0x01E37
+ "\x00x\xd8\x00`\x80\x1e8" + // 0x01E36 0x00304: 0x01E38
+ "\x00x\xdc\x00`\x80\x1e9" + // 0x01E37 0x00304: 0x01E39
+ "\x00\x010\x00f \x1e:" + // 0x0004C 0x00331: 0x01E3A
+ "\x00\x01\xb0\x00f \x1e;" + // 0x0006C 0x00331: 0x01E3B
+ "\x00\x010\x00e\xa0\x1e<" + // 0x0004C 0x0032D: 0x01E3C
+ "\x00\x01\xb0\x00e\xa0\x1e=" + // 0x0006C 0x0032D: 0x01E3D
+ "\x00\x014\x00` \x1e>" + // 0x0004D 0x00301: 0x01E3E
+ "\x00\x01\xb4\x00` \x1e?" + // 0x0006D 0x00301: 0x01E3F
+ "\x00\x014\x00`\xe0\x1e@" + // 0x0004D 0x00307: 0x01E40
+ "\x00\x01\xb4\x00`\xe0\x1eA" + // 0x0006D 0x00307: 0x01E41
+ "\x00\x014\x00d`\x1eB" + // 0x0004D 0x00323: 0x01E42
+ "\x00\x01\xb4\x00d`\x1eC" + // 0x0006D 0x00323: 0x01E43
+ "\x00\x018\x00`\xe0\x1eD" + // 0x0004E 0x00307: 0x01E44
+ "\x00\x01\xb8\x00`\xe0\x1eE" + // 0x0006E 0x00307: 0x01E45
+ "\x00\x018\x00d`\x1eF" + // 0x0004E 0x00323: 0x01E46
+ "\x00\x01\xb8\x00d`\x1eG" + // 0x0006E 0x00323: 0x01E47
+ "\x00\x018\x00f \x1eH" + // 0x0004E 0x00331: 0x01E48
+ "\x00\x01\xb8\x00f \x1eI" + // 0x0006E 0x00331: 0x01E49
+ "\x00\x018\x00e\xa0\x1eJ" + // 0x0004E 0x0032D: 0x01E4A
+ "\x00\x01\xb8\x00e\xa0\x1eK" + // 0x0006E 0x0032D: 0x01E4B
+ "\x00\x03T\x00` \x1eL" + // 0x000D5 0x00301: 0x01E4C
+ "\x00\x03\xd4\x00` \x1eM" + // 0x000F5 0x00301: 0x01E4D
+ "\x00\x03T\x00a\x00\x1eN" + // 0x000D5 0x00308: 0x01E4E
+ "\x00\x03\xd4\x00a\x00\x1eO" + // 0x000F5 0x00308: 0x01E4F
+ "\x00\x050\x00`\x00\x1eP" + // 0x0014C 0x00300: 0x01E50
+ "\x00\x054\x00`\x00\x1eQ" + // 0x0014D 0x00300: 0x01E51
+ "\x00\x050\x00` \x1eR" + // 0x0014C 0x00301: 0x01E52
+ "\x00\x054\x00` \x1eS" + // 0x0014D 0x00301: 0x01E53
+ "\x00\x01@\x00` \x1eT" + // 0x00050 0x00301: 0x01E54
+ "\x00\x01\xc0\x00` \x1eU" + // 0x00070 0x00301: 0x01E55
+ "\x00\x01@\x00`\xe0\x1eV" + // 0x00050 0x00307: 0x01E56
+ "\x00\x01\xc0\x00`\xe0\x1eW" + // 0x00070 0x00307: 0x01E57
+ "\x00\x01H\x00`\xe0\x1eX" + // 0x00052 0x00307: 0x01E58
+ "\x00\x01\xc8\x00`\xe0\x1eY" + // 0x00072 0x00307: 0x01E59
+ "\x00\x01H\x00d`\x1eZ" + // 0x00052 0x00323: 0x01E5A
+ "\x00\x01\xc8\x00d`\x1e[" + // 0x00072 0x00323: 0x01E5B
+ "\x00yh\x00`\x80\x1e\\" + // 0x01E5A 0x00304: 0x01E5C
+ "\x00yl\x00`\x80\x1e]" + // 0x01E5B 0x00304: 0x01E5D
+ "\x00\x01H\x00f \x1e^" + // 0x00052 0x00331: 0x01E5E
+ "\x00\x01\xc8\x00f \x1e_" + // 0x00072 0x00331: 0x01E5F
+ "\x00\x01L\x00`\xe0\x1e`" + // 0x00053 0x00307: 0x01E60
+ "\x00\x01\xcc\x00`\xe0\x1ea" + // 0x00073 0x00307: 0x01E61
+ "\x00\x01L\x00d`\x1eb" + // 0x00053 0x00323: 0x01E62
+ "\x00\x01\xcc\x00d`\x1ec" + // 0x00073 0x00323: 0x01E63
+ "\x00\x05h\x00`\xe0\x1ed" + // 0x0015A 0x00307: 0x01E64
+ "\x00\x05l\x00`\xe0\x1ee" + // 0x0015B 0x00307: 0x01E65
+ "\x00\x05\x80\x00`\xe0\x1ef" + // 0x00160 0x00307: 0x01E66
+ "\x00\x05\x84\x00`\xe0\x1eg" + // 0x00161 0x00307: 0x01E67
+ "\x00y\x88\x00`\xe0\x1eh" + // 0x01E62 0x00307: 0x01E68
+ "\x00y\x8c\x00`\xe0\x1ei" + // 0x01E63 0x00307: 0x01E69
+ "\x00\x01P\x00`\xe0\x1ej" + // 0x00054 0x00307: 0x01E6A
+ "\x00\x01\xd0\x00`\xe0\x1ek" + // 0x00074 0x00307: 0x01E6B
+ "\x00\x01P\x00d`\x1el" + // 0x00054 0x00323: 0x01E6C
+ "\x00\x01\xd0\x00d`\x1em" + // 0x00074 0x00323: 0x01E6D
+ "\x00\x01P\x00f \x1en" + // 0x00054 0x00331: 0x01E6E
+ "\x00\x01\xd0\x00f \x1eo" + // 0x00074 0x00331: 0x01E6F
+ "\x00\x01P\x00e\xa0\x1ep" + // 0x00054 0x0032D: 0x01E70
+ "\x00\x01\xd0\x00e\xa0\x1eq" + // 0x00074 0x0032D: 0x01E71
+ "\x00\x01T\x00d\x80\x1er" + // 0x00055 0x00324: 0x01E72
+ "\x00\x01\xd4\x00d\x80\x1es" + // 0x00075 0x00324: 0x01E73
+ "\x00\x01T\x00f\x00\x1et" + // 0x00055 0x00330: 0x01E74
+ "\x00\x01\xd4\x00f\x00\x1eu" + // 0x00075 0x00330: 0x01E75
+ "\x00\x01T\x00e\xa0\x1ev" + // 0x00055 0x0032D: 0x01E76
+ "\x00\x01\xd4\x00e\xa0\x1ew" + // 0x00075 0x0032D: 0x01E77
+ "\x00\x05\xa0\x00` \x1ex" + // 0x00168 0x00301: 0x01E78
+ "\x00\x05\xa4\x00` \x1ey" + // 0x00169 0x00301: 0x01E79
+ "\x00\x05\xa8\x00a\x00\x1ez" + // 0x0016A 0x00308: 0x01E7A
+ "\x00\x05\xac\x00a\x00\x1e{" + // 0x0016B 0x00308: 0x01E7B
+ "\x00\x01X\x00``\x1e|" + // 0x00056 0x00303: 0x01E7C
+ "\x00\x01\xd8\x00``\x1e}" + // 0x00076 0x00303: 0x01E7D
+ "\x00\x01X\x00d`\x1e~" + // 0x00056 0x00323: 0x01E7E
+ "\x00\x01\xd8\x00d`\x1e\x7f" + // 0x00076 0x00323: 0x01E7F
+ "\x00\x01\\\x00`\x00\x1e\x80" + // 0x00057 0x00300: 0x01E80
+ "\x00\x01\xdc\x00`\x00\x1e\x81" + // 0x00077 0x00300: 0x01E81
+ "\x00\x01\\\x00` \x1e\x82" + // 0x00057 0x00301: 0x01E82
+ "\x00\x01\xdc\x00` \x1e\x83" + // 0x00077 0x00301: 0x01E83
+ "\x00\x01\\\x00a\x00\x1e\x84" + // 0x00057 0x00308: 0x01E84
+ "\x00\x01\xdc\x00a\x00\x1e\x85" + // 0x00077 0x00308: 0x01E85
+ "\x00\x01\\\x00`\xe0\x1e\x86" + // 0x00057 0x00307: 0x01E86
+ "\x00\x01\xdc\x00`\xe0\x1e\x87" + // 0x00077 0x00307: 0x01E87
+ "\x00\x01\\\x00d`\x1e\x88" + // 0x00057 0x00323: 0x01E88
+ "\x00\x01\xdc\x00d`\x1e\x89" + // 0x00077 0x00323: 0x01E89
+ "\x00\x01`\x00`\xe0\x1e\x8a" + // 0x00058 0x00307: 0x01E8A
+ "\x00\x01\xe0\x00`\xe0\x1e\x8b" + // 0x00078 0x00307: 0x01E8B
+ "\x00\x01`\x00a\x00\x1e\x8c" + // 0x00058 0x00308: 0x01E8C
+ "\x00\x01\xe0\x00a\x00\x1e\x8d" + // 0x00078 0x00308: 0x01E8D
+ "\x00\x01d\x00`\xe0\x1e\x8e" + // 0x00059 0x00307: 0x01E8E
+ "\x00\x01\xe4\x00`\xe0\x1e\x8f" + // 0x00079 0x00307: 0x01E8F
+ "\x00\x01h\x00`@\x1e\x90" + // 0x0005A 0x00302: 0x01E90
+ "\x00\x01\xe8\x00`@\x1e\x91" + // 0x0007A 0x00302: 0x01E91
+ "\x00\x01h\x00d`\x1e\x92" + // 0x0005A 0x00323: 0x01E92
+ "\x00\x01\xe8\x00d`\x1e\x93" + // 0x0007A 0x00323: 0x01E93
+ "\x00\x01h\x00f \x1e\x94" + // 0x0005A 0x00331: 0x01E94
+ "\x00\x01\xe8\x00f \x1e\x95" + // 0x0007A 0x00331: 0x01E95
+ "\x00\x01\xa0\x00f \x1e\x96" + // 0x00068 0x00331: 0x01E96
+ "\x00\x01\xd0\x00a\x00\x1e\x97" + // 0x00074 0x00308: 0x01E97
+ "\x00\x01\xdc\x00a@\x1e\x98" + // 0x00077 0x0030A: 0x01E98
+ "\x00\x01\xe4\x00a@\x1e\x99" + // 0x00079 0x0030A: 0x01E99
+ "\x00\x05\xfc\x00`\xe0\x1e\x9b" + // 0x0017F 0x00307: 0x01E9B
+ "\x00\x01\x04\x00d`\x1e\xa0" + // 0x00041 0x00323: 0x01EA0
+ "\x00\x01\x84\x00d`\x1e\xa1" + // 0x00061 0x00323: 0x01EA1
+ "\x00\x01\x04\x00a \x1e\xa2" + // 0x00041 0x00309: 0x01EA2
+ "\x00\x01\x84\x00a \x1e\xa3" + // 0x00061 0x00309: 0x01EA3
+ "\x00\x03\b\x00` \x1e\xa4" + // 0x000C2 0x00301: 0x01EA4
+ "\x00\x03\x88\x00` \x1e\xa5" + // 0x000E2 0x00301: 0x01EA5
+ "\x00\x03\b\x00`\x00\x1e\xa6" + // 0x000C2 0x00300: 0x01EA6
+ "\x00\x03\x88\x00`\x00\x1e\xa7" + // 0x000E2 0x00300: 0x01EA7
+ "\x00\x03\b\x00a \x1e\xa8" + // 0x000C2 0x00309: 0x01EA8
+ "\x00\x03\x88\x00a \x1e\xa9" + // 0x000E2 0x00309: 0x01EA9
+ "\x00\x03\b\x00``\x1e\xaa" + // 0x000C2 0x00303: 0x01EAA
+ "\x00\x03\x88\x00``\x1e\xab" + // 0x000E2 0x00303: 0x01EAB
+ "\x00z\x80\x00`@\x1e\xac" + // 0x01EA0 0x00302: 0x01EAC
+ "\x00z\x84\x00`@\x1e\xad" + // 0x01EA1 0x00302: 0x01EAD
+ "\x00\x04\b\x00` \x1e\xae" + // 0x00102 0x00301: 0x01EAE
+ "\x00\x04\f\x00` \x1e\xaf" + // 0x00103 0x00301: 0x01EAF
+ "\x00\x04\b\x00`\x00\x1e\xb0" + // 0x00102 0x00300: 0x01EB0
+ "\x00\x04\f\x00`\x00\x1e\xb1" + // 0x00103 0x00300: 0x01EB1
+ "\x00\x04\b\x00a \x1e\xb2" + // 0x00102 0x00309: 0x01EB2
+ "\x00\x04\f\x00a \x1e\xb3" + // 0x00103 0x00309: 0x01EB3
+ "\x00\x04\b\x00``\x1e\xb4" + // 0x00102 0x00303: 0x01EB4
+ "\x00\x04\f\x00``\x1e\xb5" + // 0x00103 0x00303: 0x01EB5
+ "\x00z\x80\x00`\xc0\x1e\xb6" + // 0x01EA0 0x00306: 0x01EB6
+ "\x00z\x84\x00`\xc0\x1e\xb7" + // 0x01EA1 0x00306: 0x01EB7
+ "\x00\x01\x14\x00d`\x1e\xb8" + // 0x00045 0x00323: 0x01EB8
+ "\x00\x01\x94\x00d`\x1e\xb9" + // 0x00065 0x00323: 0x01EB9
+ "\x00\x01\x14\x00a \x1e\xba" + // 0x00045 0x00309: 0x01EBA
+ "\x00\x01\x94\x00a \x1e\xbb" + // 0x00065 0x00309: 0x01EBB
+ "\x00\x01\x14\x00``\x1e\xbc" + // 0x00045 0x00303: 0x01EBC
+ "\x00\x01\x94\x00``\x1e\xbd" + // 0x00065 0x00303: 0x01EBD
+ "\x00\x03(\x00` \x1e\xbe" + // 0x000CA 0x00301: 0x01EBE
+ "\x00\x03\xa8\x00` \x1e\xbf" + // 0x000EA 0x00301: 0x01EBF
+ "\x00\x03(\x00`\x00\x1e\xc0" + // 0x000CA 0x00300: 0x01EC0
+ "\x00\x03\xa8\x00`\x00\x1e\xc1" + // 0x000EA 0x00300: 0x01EC1
+ "\x00\x03(\x00a \x1e\xc2" + // 0x000CA 0x00309: 0x01EC2
+ "\x00\x03\xa8\x00a \x1e\xc3" + // 0x000EA 0x00309: 0x01EC3
+ "\x00\x03(\x00``\x1e\xc4" + // 0x000CA 0x00303: 0x01EC4
+ "\x00\x03\xa8\x00``\x1e\xc5" + // 0x000EA 0x00303: 0x01EC5
+ "\x00z\xe0\x00`@\x1e\xc6" + // 0x01EB8 0x00302: 0x01EC6
+ "\x00z\xe4\x00`@\x1e\xc7" + // 0x01EB9 0x00302: 0x01EC7
+ "\x00\x01$\x00a \x1e\xc8" + // 0x00049 0x00309: 0x01EC8
+ "\x00\x01\xa4\x00a \x1e\xc9" + // 0x00069 0x00309: 0x01EC9
+ "\x00\x01$\x00d`\x1e\xca" + // 0x00049 0x00323: 0x01ECA
+ "\x00\x01\xa4\x00d`\x1e\xcb" + // 0x00069 0x00323: 0x01ECB
+ "\x00\x01<\x00d`\x1e\xcc" + // 0x0004F 0x00323: 0x01ECC
+ "\x00\x01\xbc\x00d`\x1e\xcd" + // 0x0006F 0x00323: 0x01ECD
+ "\x00\x01<\x00a \x1e\xce" + // 0x0004F 0x00309: 0x01ECE
+ "\x00\x01\xbc\x00a \x1e\xcf" + // 0x0006F 0x00309: 0x01ECF
+ "\x00\x03P\x00` \x1e\xd0" + // 0x000D4 0x00301: 0x01ED0
+ "\x00\x03\xd0\x00` \x1e\xd1" + // 0x000F4 0x00301: 0x01ED1
+ "\x00\x03P\x00`\x00\x1e\xd2" + // 0x000D4 0x00300: 0x01ED2
+ "\x00\x03\xd0\x00`\x00\x1e\xd3" + // 0x000F4 0x00300: 0x01ED3
+ "\x00\x03P\x00a \x1e\xd4" + // 0x000D4 0x00309: 0x01ED4
+ "\x00\x03\xd0\x00a \x1e\xd5" + // 0x000F4 0x00309: 0x01ED5
+ "\x00\x03P\x00``\x1e\xd6" + // 0x000D4 0x00303: 0x01ED6
+ "\x00\x03\xd0\x00``\x1e\xd7" + // 0x000F4 0x00303: 0x01ED7
+ "\x00{0\x00`@\x1e\xd8" + // 0x01ECC 0x00302: 0x01ED8
+ "\x00{4\x00`@\x1e\xd9" + // 0x01ECD 0x00302: 0x01ED9
+ "\x00\x06\x80\x00` \x1e\xda" + // 0x001A0 0x00301: 0x01EDA
+ "\x00\x06\x84\x00` \x1e\xdb" + // 0x001A1 0x00301: 0x01EDB
+ "\x00\x06\x80\x00`\x00\x1e\xdc" + // 0x001A0 0x00300: 0x01EDC
+ "\x00\x06\x84\x00`\x00\x1e\xdd" + // 0x001A1 0x00300: 0x01EDD
+ "\x00\x06\x80\x00a \x1e\xde" + // 0x001A0 0x00309: 0x01EDE
+ "\x00\x06\x84\x00a \x1e\xdf" + // 0x001A1 0x00309: 0x01EDF
+ "\x00\x06\x80\x00``\x1e\xe0" + // 0x001A0 0x00303: 0x01EE0
+ "\x00\x06\x84\x00``\x1e\xe1" + // 0x001A1 0x00303: 0x01EE1
+ "\x00\x06\x80\x00d`\x1e\xe2" + // 0x001A0 0x00323: 0x01EE2
+ "\x00\x06\x84\x00d`\x1e\xe3" + // 0x001A1 0x00323: 0x01EE3
+ "\x00\x01T\x00d`\x1e\xe4" + // 0x00055 0x00323: 0x01EE4
+ "\x00\x01\xd4\x00d`\x1e\xe5" + // 0x00075 0x00323: 0x01EE5
+ "\x00\x01T\x00a \x1e\xe6" + // 0x00055 0x00309: 0x01EE6
+ "\x00\x01\xd4\x00a \x1e\xe7" + // 0x00075 0x00309: 0x01EE7
+ "\x00\x06\xbc\x00` \x1e\xe8" + // 0x001AF 0x00301: 0x01EE8
+ "\x00\x06\xc0\x00` \x1e\xe9" + // 0x001B0 0x00301: 0x01EE9
+ "\x00\x06\xbc\x00`\x00\x1e\xea" + // 0x001AF 0x00300: 0x01EEA
+ "\x00\x06\xc0\x00`\x00\x1e\xeb" + // 0x001B0 0x00300: 0x01EEB
+ "\x00\x06\xbc\x00a \x1e\xec" + // 0x001AF 0x00309: 0x01EEC
+ "\x00\x06\xc0\x00a \x1e\xed" + // 0x001B0 0x00309: 0x01EED
+ "\x00\x06\xbc\x00``\x1e\xee" + // 0x001AF 0x00303: 0x01EEE
+ "\x00\x06\xc0\x00``\x1e\xef" + // 0x001B0 0x00303: 0x01EEF
+ "\x00\x06\xbc\x00d`\x1e\xf0" + // 0x001AF 0x00323: 0x01EF0
+ "\x00\x06\xc0\x00d`\x1e\xf1" + // 0x001B0 0x00323: 0x01EF1
+ "\x00\x01d\x00`\x00\x1e\xf2" + // 0x00059 0x00300: 0x01EF2
+ "\x00\x01\xe4\x00`\x00\x1e\xf3" + // 0x00079 0x00300: 0x01EF3
+ "\x00\x01d\x00d`\x1e\xf4" + // 0x00059 0x00323: 0x01EF4
+ "\x00\x01\xe4\x00d`\x1e\xf5" + // 0x00079 0x00323: 0x01EF5
+ "\x00\x01d\x00a \x1e\xf6" + // 0x00059 0x00309: 0x01EF6
+ "\x00\x01\xe4\x00a \x1e\xf7" + // 0x00079 0x00309: 0x01EF7
+ "\x00\x01d\x00``\x1e\xf8" + // 0x00059 0x00303: 0x01EF8
+ "\x00\x01\xe4\x00``\x1e\xf9" + // 0x00079 0x00303: 0x01EF9
+ "\x00\x0e\xc4\x00b`\x1f\x00" + // 0x003B1 0x00313: 0x01F00
+ "\x00\x0e\xc4\x00b\x80\x1f\x01" + // 0x003B1 0x00314: 0x01F01
+ "\x00|\x00\x00`\x00\x1f\x02" + // 0x01F00 0x00300: 0x01F02
+ "\x00|\x04\x00`\x00\x1f\x03" + // 0x01F01 0x00300: 0x01F03
+ "\x00|\x00\x00` \x1f\x04" + // 0x01F00 0x00301: 0x01F04
+ "\x00|\x04\x00` \x1f\x05" + // 0x01F01 0x00301: 0x01F05
+ "\x00|\x00\x00h@\x1f\x06" + // 0x01F00 0x00342: 0x01F06
+ "\x00|\x04\x00h@\x1f\a" + // 0x01F01 0x00342: 0x01F07
+ "\x00\x0eD\x00b`\x1f\b" + // 0x00391 0x00313: 0x01F08
+ "\x00\x0eD\x00b\x80\x1f\t" + // 0x00391 0x00314: 0x01F09
+ "\x00| \x00`\x00\x1f\n" + // 0x01F08 0x00300: 0x01F0A
+ "\x00|$\x00`\x00\x1f\v" + // 0x01F09 0x00300: 0x01F0B
+ "\x00| \x00` \x1f\f" + // 0x01F08 0x00301: 0x01F0C
+ "\x00|$\x00` \x1f\r" + // 0x01F09 0x00301: 0x01F0D
+ "\x00| \x00h@\x1f\x0e" + // 0x01F08 0x00342: 0x01F0E
+ "\x00|$\x00h@\x1f\x0f" + // 0x01F09 0x00342: 0x01F0F
+ "\x00\x0e\xd4\x00b`\x1f\x10" + // 0x003B5 0x00313: 0x01F10
+ "\x00\x0e\xd4\x00b\x80\x1f\x11" + // 0x003B5 0x00314: 0x01F11
+ "\x00|@\x00`\x00\x1f\x12" + // 0x01F10 0x00300: 0x01F12
+ "\x00|D\x00`\x00\x1f\x13" + // 0x01F11 0x00300: 0x01F13
+ "\x00|@\x00` \x1f\x14" + // 0x01F10 0x00301: 0x01F14
+ "\x00|D\x00` \x1f\x15" + // 0x01F11 0x00301: 0x01F15
+ "\x00\x0eT\x00b`\x1f\x18" + // 0x00395 0x00313: 0x01F18
+ "\x00\x0eT\x00b\x80\x1f\x19" + // 0x00395 0x00314: 0x01F19
+ "\x00|`\x00`\x00\x1f\x1a" + // 0x01F18 0x00300: 0x01F1A
+ "\x00|d\x00`\x00\x1f\x1b" + // 0x01F19 0x00300: 0x01F1B
+ "\x00|`\x00` \x1f\x1c" + // 0x01F18 0x00301: 0x01F1C
+ "\x00|d\x00` \x1f\x1d" + // 0x01F19 0x00301: 0x01F1D
+ "\x00\x0e\xdc\x00b`\x1f " + // 0x003B7 0x00313: 0x01F20
+ "\x00\x0e\xdc\x00b\x80\x1f!" + // 0x003B7 0x00314: 0x01F21
+ "\x00|\x80\x00`\x00\x1f\"" + // 0x01F20 0x00300: 0x01F22
+ "\x00|\x84\x00`\x00\x1f#" + // 0x01F21 0x00300: 0x01F23
+ "\x00|\x80\x00` \x1f$" + // 0x01F20 0x00301: 0x01F24
+ "\x00|\x84\x00` \x1f%" + // 0x01F21 0x00301: 0x01F25
+ "\x00|\x80\x00h@\x1f&" + // 0x01F20 0x00342: 0x01F26
+ "\x00|\x84\x00h@\x1f'" + // 0x01F21 0x00342: 0x01F27
+ "\x00\x0e\\\x00b`\x1f(" + // 0x00397 0x00313: 0x01F28
+ "\x00\x0e\\\x00b\x80\x1f)" + // 0x00397 0x00314: 0x01F29
+ "\x00|\xa0\x00`\x00\x1f*" + // 0x01F28 0x00300: 0x01F2A
+ "\x00|\xa4\x00`\x00\x1f+" + // 0x01F29 0x00300: 0x01F2B
+ "\x00|\xa0\x00` \x1f," + // 0x01F28 0x00301: 0x01F2C
+ "\x00|\xa4\x00` \x1f-" + // 0x01F29 0x00301: 0x01F2D
+ "\x00|\xa0\x00h@\x1f." + // 0x01F28 0x00342: 0x01F2E
+ "\x00|\xa4\x00h@\x1f/" + // 0x01F29 0x00342: 0x01F2F
+ "\x00\x0e\xe4\x00b`\x1f0" + // 0x003B9 0x00313: 0x01F30
+ "\x00\x0e\xe4\x00b\x80\x1f1" + // 0x003B9 0x00314: 0x01F31
+ "\x00|\xc0\x00`\x00\x1f2" + // 0x01F30 0x00300: 0x01F32
+ "\x00|\xc4\x00`\x00\x1f3" + // 0x01F31 0x00300: 0x01F33
+ "\x00|\xc0\x00` \x1f4" + // 0x01F30 0x00301: 0x01F34
+ "\x00|\xc4\x00` \x1f5" + // 0x01F31 0x00301: 0x01F35
+ "\x00|\xc0\x00h@\x1f6" + // 0x01F30 0x00342: 0x01F36
+ "\x00|\xc4\x00h@\x1f7" + // 0x01F31 0x00342: 0x01F37
+ "\x00\x0ed\x00b`\x1f8" + // 0x00399 0x00313: 0x01F38
+ "\x00\x0ed\x00b\x80\x1f9" + // 0x00399 0x00314: 0x01F39
+ "\x00|\xe0\x00`\x00\x1f:" + // 0x01F38 0x00300: 0x01F3A
+ "\x00|\xe4\x00`\x00\x1f;" + // 0x01F39 0x00300: 0x01F3B
+ "\x00|\xe0\x00` \x1f<" + // 0x01F38 0x00301: 0x01F3C
+ "\x00|\xe4\x00` \x1f=" + // 0x01F39 0x00301: 0x01F3D
+ "\x00|\xe0\x00h@\x1f>" + // 0x01F38 0x00342: 0x01F3E
+ "\x00|\xe4\x00h@\x1f?" + // 0x01F39 0x00342: 0x01F3F
+ "\x00\x0e\xfc\x00b`\x1f@" + // 0x003BF 0x00313: 0x01F40
+ "\x00\x0e\xfc\x00b\x80\x1fA" + // 0x003BF 0x00314: 0x01F41
+ "\x00}\x00\x00`\x00\x1fB" + // 0x01F40 0x00300: 0x01F42
+ "\x00}\x04\x00`\x00\x1fC" + // 0x01F41 0x00300: 0x01F43
+ "\x00}\x00\x00` \x1fD" + // 0x01F40 0x00301: 0x01F44
+ "\x00}\x04\x00` \x1fE" + // 0x01F41 0x00301: 0x01F45
+ "\x00\x0e|\x00b`\x1fH" + // 0x0039F 0x00313: 0x01F48
+ "\x00\x0e|\x00b\x80\x1fI" + // 0x0039F 0x00314: 0x01F49
+ "\x00} \x00`\x00\x1fJ" + // 0x01F48 0x00300: 0x01F4A
+ "\x00}$\x00`\x00\x1fK" + // 0x01F49 0x00300: 0x01F4B
+ "\x00} \x00` \x1fL" + // 0x01F48 0x00301: 0x01F4C
+ "\x00}$\x00` \x1fM" + // 0x01F49 0x00301: 0x01F4D
+ "\x00\x0f\x14\x00b`\x1fP" + // 0x003C5 0x00313: 0x01F50
+ "\x00\x0f\x14\x00b\x80\x1fQ" + // 0x003C5 0x00314: 0x01F51
+ "\x00}@\x00`\x00\x1fR" + // 0x01F50 0x00300: 0x01F52
+ "\x00}D\x00`\x00\x1fS" + // 0x01F51 0x00300: 0x01F53
+ "\x00}@\x00` \x1fT" + // 0x01F50 0x00301: 0x01F54
+ "\x00}D\x00` \x1fU" + // 0x01F51 0x00301: 0x01F55
+ "\x00}@\x00h@\x1fV" + // 0x01F50 0x00342: 0x01F56
+ "\x00}D\x00h@\x1fW" + // 0x01F51 0x00342: 0x01F57
+ "\x00\x0e\x94\x00b\x80\x1fY" + // 0x003A5 0x00314: 0x01F59
+ "\x00}d\x00`\x00\x1f[" + // 0x01F59 0x00300: 0x01F5B
+ "\x00}d\x00` \x1f]" + // 0x01F59 0x00301: 0x01F5D
+ "\x00}d\x00h@\x1f_" + // 0x01F59 0x00342: 0x01F5F
+ "\x00\x0f$\x00b`\x1f`" + // 0x003C9 0x00313: 0x01F60
+ "\x00\x0f$\x00b\x80\x1fa" + // 0x003C9 0x00314: 0x01F61
+ "\x00}\x80\x00`\x00\x1fb" + // 0x01F60 0x00300: 0x01F62
+ "\x00}\x84\x00`\x00\x1fc" + // 0x01F61 0x00300: 0x01F63
+ "\x00}\x80\x00` \x1fd" + // 0x01F60 0x00301: 0x01F64
+ "\x00}\x84\x00` \x1fe" + // 0x01F61 0x00301: 0x01F65
+ "\x00}\x80\x00h@\x1ff" + // 0x01F60 0x00342: 0x01F66
+ "\x00}\x84\x00h@\x1fg" + // 0x01F61 0x00342: 0x01F67
+ "\x00\x0e\xa4\x00b`\x1fh" + // 0x003A9 0x00313: 0x01F68
+ "\x00\x0e\xa4\x00b\x80\x1fi" + // 0x003A9 0x00314: 0x01F69
+ "\x00}\xa0\x00`\x00\x1fj" + // 0x01F68 0x00300: 0x01F6A
+ "\x00}\xa4\x00`\x00\x1fk" + // 0x01F69 0x00300: 0x01F6B
+ "\x00}\xa0\x00` \x1fl" + // 0x01F68 0x00301: 0x01F6C
+ "\x00}\xa4\x00` \x1fm" + // 0x01F69 0x00301: 0x01F6D
+ "\x00}\xa0\x00h@\x1fn" + // 0x01F68 0x00342: 0x01F6E
+ "\x00}\xa4\x00h@\x1fo" + // 0x01F69 0x00342: 0x01F6F
+ "\x00\x0e\xc4\x00`\x00\x1fp" + // 0x003B1 0x00300: 0x01F70
+ "\x00\x0e\xd4\x00`\x00\x1fr" + // 0x003B5 0x00300: 0x01F72
+ "\x00\x0e\xdc\x00`\x00\x1ft" + // 0x003B7 0x00300: 0x01F74
+ "\x00\x0e\xe4\x00`\x00\x1fv" + // 0x003B9 0x00300: 0x01F76
+ "\x00\x0e\xfc\x00`\x00\x1fx" + // 0x003BF 0x00300: 0x01F78
+ "\x00\x0f\x14\x00`\x00\x1fz" + // 0x003C5 0x00300: 0x01F7A
+ "\x00\x0f$\x00`\x00\x1f|" + // 0x003C9 0x00300: 0x01F7C
+ "\x00|\x00\x00h\xa0\x1f\x80" + // 0x01F00 0x00345: 0x01F80
+ "\x00|\x04\x00h\xa0\x1f\x81" + // 0x01F01 0x00345: 0x01F81
+ "\x00|\b\x00h\xa0\x1f\x82" + // 0x01F02 0x00345: 0x01F82
+ "\x00|\f\x00h\xa0\x1f\x83" + // 0x01F03 0x00345: 0x01F83
+ "\x00|\x10\x00h\xa0\x1f\x84" + // 0x01F04 0x00345: 0x01F84
+ "\x00|\x14\x00h\xa0\x1f\x85" + // 0x01F05 0x00345: 0x01F85
+ "\x00|\x18\x00h\xa0\x1f\x86" + // 0x01F06 0x00345: 0x01F86
+ "\x00|\x1c\x00h\xa0\x1f\x87" + // 0x01F07 0x00345: 0x01F87
+ "\x00| \x00h\xa0\x1f\x88" + // 0x01F08 0x00345: 0x01F88
+ "\x00|$\x00h\xa0\x1f\x89" + // 0x01F09 0x00345: 0x01F89
+ "\x00|(\x00h\xa0\x1f\x8a" + // 0x01F0A 0x00345: 0x01F8A
+ "\x00|,\x00h\xa0\x1f\x8b" + // 0x01F0B 0x00345: 0x01F8B
+ "\x00|0\x00h\xa0\x1f\x8c" + // 0x01F0C 0x00345: 0x01F8C
+ "\x00|4\x00h\xa0\x1f\x8d" + // 0x01F0D 0x00345: 0x01F8D
+ "\x00|8\x00h\xa0\x1f\x8e" + // 0x01F0E 0x00345: 0x01F8E
+ "\x00|<\x00h\xa0\x1f\x8f" + // 0x01F0F 0x00345: 0x01F8F
+ "\x00|\x80\x00h\xa0\x1f\x90" + // 0x01F20 0x00345: 0x01F90
+ "\x00|\x84\x00h\xa0\x1f\x91" + // 0x01F21 0x00345: 0x01F91
+ "\x00|\x88\x00h\xa0\x1f\x92" + // 0x01F22 0x00345: 0x01F92
+ "\x00|\x8c\x00h\xa0\x1f\x93" + // 0x01F23 0x00345: 0x01F93
+ "\x00|\x90\x00h\xa0\x1f\x94" + // 0x01F24 0x00345: 0x01F94
+ "\x00|\x94\x00h\xa0\x1f\x95" + // 0x01F25 0x00345: 0x01F95
+ "\x00|\x98\x00h\xa0\x1f\x96" + // 0x01F26 0x00345: 0x01F96
+ "\x00|\x9c\x00h\xa0\x1f\x97" + // 0x01F27 0x00345: 0x01F97
+ "\x00|\xa0\x00h\xa0\x1f\x98" + // 0x01F28 0x00345: 0x01F98
+ "\x00|\xa4\x00h\xa0\x1f\x99" + // 0x01F29 0x00345: 0x01F99
+ "\x00|\xa8\x00h\xa0\x1f\x9a" + // 0x01F2A 0x00345: 0x01F9A
+ "\x00|\xac\x00h\xa0\x1f\x9b" + // 0x01F2B 0x00345: 0x01F9B
+ "\x00|\xb0\x00h\xa0\x1f\x9c" + // 0x01F2C 0x00345: 0x01F9C
+ "\x00|\xb4\x00h\xa0\x1f\x9d" + // 0x01F2D 0x00345: 0x01F9D
+ "\x00|\xb8\x00h\xa0\x1f\x9e" + // 0x01F2E 0x00345: 0x01F9E
+ "\x00|\xbc\x00h\xa0\x1f\x9f" + // 0x01F2F 0x00345: 0x01F9F
+ "\x00}\x80\x00h\xa0\x1f\xa0" + // 0x01F60 0x00345: 0x01FA0
+ "\x00}\x84\x00h\xa0\x1f\xa1" + // 0x01F61 0x00345: 0x01FA1
+ "\x00}\x88\x00h\xa0\x1f\xa2" + // 0x01F62 0x00345: 0x01FA2
+ "\x00}\x8c\x00h\xa0\x1f\xa3" + // 0x01F63 0x00345: 0x01FA3
+ "\x00}\x90\x00h\xa0\x1f\xa4" + // 0x01F64 0x00345: 0x01FA4
+ "\x00}\x94\x00h\xa0\x1f\xa5" + // 0x01F65 0x00345: 0x01FA5
+ "\x00}\x98\x00h\xa0\x1f\xa6" + // 0x01F66 0x00345: 0x01FA6
+ "\x00}\x9c\x00h\xa0\x1f\xa7" + // 0x01F67 0x00345: 0x01FA7
+ "\x00}\xa0\x00h\xa0\x1f\xa8" + // 0x01F68 0x00345: 0x01FA8
+ "\x00}\xa4\x00h\xa0\x1f\xa9" + // 0x01F69 0x00345: 0x01FA9
+ "\x00}\xa8\x00h\xa0\x1f\xaa" + // 0x01F6A 0x00345: 0x01FAA
+ "\x00}\xac\x00h\xa0\x1f\xab" + // 0x01F6B 0x00345: 0x01FAB
+ "\x00}\xb0\x00h\xa0\x1f\xac" + // 0x01F6C 0x00345: 0x01FAC
+ "\x00}\xb4\x00h\xa0\x1f\xad" + // 0x01F6D 0x00345: 0x01FAD
+ "\x00}\xb8\x00h\xa0\x1f\xae" + // 0x01F6E 0x00345: 0x01FAE
+ "\x00}\xbc\x00h\xa0\x1f\xaf" + // 0x01F6F 0x00345: 0x01FAF
+ "\x00\x0e\xc4\x00`\xc0\x1f\xb0" + // 0x003B1 0x00306: 0x01FB0
+ "\x00\x0e\xc4\x00`\x80\x1f\xb1" + // 0x003B1 0x00304: 0x01FB1
+ "\x00}\xc0\x00h\xa0\x1f\xb2" + // 0x01F70 0x00345: 0x01FB2
+ "\x00\x0e\xc4\x00h\xa0\x1f\xb3" + // 0x003B1 0x00345: 0x01FB3
+ "\x00\x0e\xb0\x00h\xa0\x1f\xb4" + // 0x003AC 0x00345: 0x01FB4
+ "\x00\x0e\xc4\x00h@\x1f\xb6" + // 0x003B1 0x00342: 0x01FB6
+ "\x00~\xd8\x00h\xa0\x1f\xb7" + // 0x01FB6 0x00345: 0x01FB7
+ "\x00\x0eD\x00`\xc0\x1f\xb8" + // 0x00391 0x00306: 0x01FB8
+ "\x00\x0eD\x00`\x80\x1f\xb9" + // 0x00391 0x00304: 0x01FB9
+ "\x00\x0eD\x00`\x00\x1f\xba" + // 0x00391 0x00300: 0x01FBA
+ "\x00\x0eD\x00h\xa0\x1f\xbc" + // 0x00391 0x00345: 0x01FBC
+ "\x00\x02\xa0\x00h@\x1f\xc1" + // 0x000A8 0x00342: 0x01FC1
+ "\x00}\xd0\x00h\xa0\x1f\xc2" + // 0x01F74 0x00345: 0x01FC2
+ "\x00\x0e\xdc\x00h\xa0\x1f\xc3" + // 0x003B7 0x00345: 0x01FC3
+ "\x00\x0e\xb8\x00h\xa0\x1f\xc4" + // 0x003AE 0x00345: 0x01FC4
+ "\x00\x0e\xdc\x00h@\x1f\xc6" + // 0x003B7 0x00342: 0x01FC6
+ "\x00\x7f\x18\x00h\xa0\x1f\xc7" + // 0x01FC6 0x00345: 0x01FC7
+ "\x00\x0eT\x00`\x00\x1f\xc8" + // 0x00395 0x00300: 0x01FC8
+ "\x00\x0e\\\x00`\x00\x1f\xca" + // 0x00397 0x00300: 0x01FCA
+ "\x00\x0e\\\x00h\xa0\x1f\xcc" + // 0x00397 0x00345: 0x01FCC
+ "\x00~\xfc\x00`\x00\x1f\xcd" + // 0x01FBF 0x00300: 0x01FCD
+ "\x00~\xfc\x00` \x1f\xce" + // 0x01FBF 0x00301: 0x01FCE
+ "\x00~\xfc\x00h@\x1f\xcf" + // 0x01FBF 0x00342: 0x01FCF
+ "\x00\x0e\xe4\x00`\xc0\x1f\xd0" + // 0x003B9 0x00306: 0x01FD0
+ "\x00\x0e\xe4\x00`\x80\x1f\xd1" + // 0x003B9 0x00304: 0x01FD1
+ "\x00\x0f(\x00`\x00\x1f\xd2" + // 0x003CA 0x00300: 0x01FD2
+ "\x00\x0e\xe4\x00h@\x1f\xd6" + // 0x003B9 0x00342: 0x01FD6
+ "\x00\x0f(\x00h@\x1f\xd7" + // 0x003CA 0x00342: 0x01FD7
+ "\x00\x0ed\x00`\xc0\x1f\xd8" + // 0x00399 0x00306: 0x01FD8
+ "\x00\x0ed\x00`\x80\x1f\xd9" + // 0x00399 0x00304: 0x01FD9
+ "\x00\x0ed\x00`\x00\x1f\xda" + // 0x00399 0x00300: 0x01FDA
+ "\x00\x7f\xf8\x00`\x00\x1f\xdd" + // 0x01FFE 0x00300: 0x01FDD
+ "\x00\x7f\xf8\x00` \x1f\xde" + // 0x01FFE 0x00301: 0x01FDE
+ "\x00\x7f\xf8\x00h@\x1f\xdf" + // 0x01FFE 0x00342: 0x01FDF
+ "\x00\x0f\x14\x00`\xc0\x1f\xe0" + // 0x003C5 0x00306: 0x01FE0
+ "\x00\x0f\x14\x00`\x80\x1f\xe1" + // 0x003C5 0x00304: 0x01FE1
+ "\x00\x0f,\x00`\x00\x1f\xe2" + // 0x003CB 0x00300: 0x01FE2
+ "\x00\x0f\x04\x00b`\x1f\xe4" + // 0x003C1 0x00313: 0x01FE4
+ "\x00\x0f\x04\x00b\x80\x1f\xe5" + // 0x003C1 0x00314: 0x01FE5
+ "\x00\x0f\x14\x00h@\x1f\xe6" + // 0x003C5 0x00342: 0x01FE6
+ "\x00\x0f,\x00h@\x1f\xe7" + // 0x003CB 0x00342: 0x01FE7
+ "\x00\x0e\x94\x00`\xc0\x1f\xe8" + // 0x003A5 0x00306: 0x01FE8
+ "\x00\x0e\x94\x00`\x80\x1f\xe9" + // 0x003A5 0x00304: 0x01FE9
+ "\x00\x0e\x94\x00`\x00\x1f\xea" + // 0x003A5 0x00300: 0x01FEA
+ "\x00\x0e\x84\x00b\x80\x1f\xec" + // 0x003A1 0x00314: 0x01FEC
+ "\x00\x02\xa0\x00`\x00\x1f\xed" + // 0x000A8 0x00300: 0x01FED
+ "\x00}\xf0\x00h\xa0\x1f\xf2" + // 0x01F7C 0x00345: 0x01FF2
+ "\x00\x0f$\x00h\xa0\x1f\xf3" + // 0x003C9 0x00345: 0x01FF3
+ "\x00\x0f8\x00h\xa0\x1f\xf4" + // 0x003CE 0x00345: 0x01FF4
+ "\x00\x0f$\x00h@\x1f\xf6" + // 0x003C9 0x00342: 0x01FF6
+ "\x00\x7f\xd8\x00h\xa0\x1f\xf7" + // 0x01FF6 0x00345: 0x01FF7
+ "\x00\x0e|\x00`\x00\x1f\xf8" + // 0x0039F 0x00300: 0x01FF8
+ "\x00\x0e\xa4\x00`\x00\x1f\xfa" + // 0x003A9 0x00300: 0x01FFA
+ "\x00\x0e\xa4\x00h\xa0\x1f\xfc" + // 0x003A9 0x00345: 0x01FFC
+ "\x00\x86@\x00g\x00!\x9a" + // 0x02190 0x00338: 0x0219A
+ "\x00\x86H\x00g\x00!\x9b" + // 0x02192 0x00338: 0x0219B
+ "\x00\x86P\x00g\x00!\xae" + // 0x02194 0x00338: 0x021AE
+ "\x00\x87@\x00g\x00!\xcd" + // 0x021D0 0x00338: 0x021CD
+ "\x00\x87P\x00g\x00!\xce" + // 0x021D4 0x00338: 0x021CE
+ "\x00\x87H\x00g\x00!\xcf" + // 0x021D2 0x00338: 0x021CF
+ "\x00\x88\f\x00g\x00\"\x04" + // 0x02203 0x00338: 0x02204
+ "\x00\x88 \x00g\x00\"\t" + // 0x02208 0x00338: 0x02209
+ "\x00\x88,\x00g\x00\"\f" + // 0x0220B 0x00338: 0x0220C
+ "\x00\x88\x8c\x00g\x00\"$" + // 0x02223 0x00338: 0x02224
+ "\x00\x88\x94\x00g\x00\"&" + // 0x02225 0x00338: 0x02226
+ "\x00\x88\xf0\x00g\x00\"A" + // 0x0223C 0x00338: 0x02241
+ "\x00\x89\f\x00g\x00\"D" + // 0x02243 0x00338: 0x02244
+ "\x00\x89\x14\x00g\x00\"G" + // 0x02245 0x00338: 0x02247
+ "\x00\x89 \x00g\x00\"I" + // 0x02248 0x00338: 0x02249
+ "\x00\x00\xf4\x00g\x00\"`" + // 0x0003D 0x00338: 0x02260
+ "\x00\x89\x84\x00g\x00\"b" + // 0x02261 0x00338: 0x02262
+ "\x00\x894\x00g\x00\"m" + // 0x0224D 0x00338: 0x0226D
+ "\x00\x00\xf0\x00g\x00\"n" + // 0x0003C 0x00338: 0x0226E
+ "\x00\x00\xf8\x00g\x00\"o" + // 0x0003E 0x00338: 0x0226F
+ "\x00\x89\x90\x00g\x00\"p" + // 0x02264 0x00338: 0x02270
+ "\x00\x89\x94\x00g\x00\"q" + // 0x02265 0x00338: 0x02271
+ "\x00\x89\xc8\x00g\x00\"t" + // 0x02272 0x00338: 0x02274
+ "\x00\x89\xcc\x00g\x00\"u" + // 0x02273 0x00338: 0x02275
+ "\x00\x89\xd8\x00g\x00\"x" + // 0x02276 0x00338: 0x02278
+ "\x00\x89\xdc\x00g\x00\"y" + // 0x02277 0x00338: 0x02279
+ "\x00\x89\xe8\x00g\x00\"\x80" + // 0x0227A 0x00338: 0x02280
+ "\x00\x89\xec\x00g\x00\"\x81" + // 0x0227B 0x00338: 0x02281
+ "\x00\x8a\b\x00g\x00\"\x84" + // 0x02282 0x00338: 0x02284
+ "\x00\x8a\f\x00g\x00\"\x85" + // 0x02283 0x00338: 0x02285
+ "\x00\x8a\x18\x00g\x00\"\x88" + // 0x02286 0x00338: 0x02288
+ "\x00\x8a\x1c\x00g\x00\"\x89" + // 0x02287 0x00338: 0x02289
+ "\x00\x8a\x88\x00g\x00\"\xac" + // 0x022A2 0x00338: 0x022AC
+ "\x00\x8a\xa0\x00g\x00\"\xad" + // 0x022A8 0x00338: 0x022AD
+ "\x00\x8a\xa4\x00g\x00\"\xae" + // 0x022A9 0x00338: 0x022AE
+ "\x00\x8a\xac\x00g\x00\"\xaf" + // 0x022AB 0x00338: 0x022AF
+ "\x00\x89\xf0\x00g\x00\"\xe0" + // 0x0227C 0x00338: 0x022E0
+ "\x00\x89\xf4\x00g\x00\"\xe1" + // 0x0227D 0x00338: 0x022E1
+ "\x00\x8aD\x00g\x00\"\xe2" + // 0x02291 0x00338: 0x022E2
+ "\x00\x8aH\x00g\x00\"\xe3" + // 0x02292 0x00338: 0x022E3
+ "\x00\x8a\xc8\x00g\x00\"\xea" + // 0x022B2 0x00338: 0x022EA
+ "\x00\x8a\xcc\x00g\x00\"\xeb" + // 0x022B3 0x00338: 0x022EB
+ "\x00\x8a\xd0\x00g\x00\"\xec" + // 0x022B4 0x00338: 0x022EC
+ "\x00\x8a\xd4\x00g\x00\"\xed" + // 0x022B5 0x00338: 0x022ED
+ "\x00\xc1,\x06\x13 0L" + // 0x0304B 0x03099: 0x0304C
+ "\x00\xc14\x06\x13 0N" + // 0x0304D 0x03099: 0x0304E
+ "\x00\xc1<\x06\x13 0P" + // 0x0304F 0x03099: 0x03050
+ "\x00\xc1D\x06\x13 0R" + // 0x03051 0x03099: 0x03052
+ "\x00\xc1L\x06\x13 0T" + // 0x03053 0x03099: 0x03054
+ "\x00\xc1T\x06\x13 0V" + // 0x03055 0x03099: 0x03056
+ "\x00\xc1\\\x06\x13 0X" + // 0x03057 0x03099: 0x03058
+ "\x00\xc1d\x06\x13 0Z" + // 0x03059 0x03099: 0x0305A
+ "\x00\xc1l\x06\x13 0\\" + // 0x0305B 0x03099: 0x0305C
+ "\x00\xc1t\x06\x13 0^" + // 0x0305D 0x03099: 0x0305E
+ "\x00\xc1|\x06\x13 0`" + // 0x0305F 0x03099: 0x03060
+ "\x00\xc1\x84\x06\x13 0b" + // 0x03061 0x03099: 0x03062
+ "\x00\xc1\x90\x06\x13 0e" + // 0x03064 0x03099: 0x03065
+ "\x00\xc1\x98\x06\x13 0g" + // 0x03066 0x03099: 0x03067
+ "\x00\xc1\xa0\x06\x13 0i" + // 0x03068 0x03099: 0x03069
+ "\x00\xc1\xbc\x06\x13 0p" + // 0x0306F 0x03099: 0x03070
+ "\x00\xc1\xbc\x06\x13@0q" + // 0x0306F 0x0309A: 0x03071
+ "\x00\xc1\xc8\x06\x13 0s" + // 0x03072 0x03099: 0x03073
+ "\x00\xc1\xc8\x06\x13@0t" + // 0x03072 0x0309A: 0x03074
+ "\x00\xc1\xd4\x06\x13 0v" + // 0x03075 0x03099: 0x03076
+ "\x00\xc1\xd4\x06\x13@0w" + // 0x03075 0x0309A: 0x03077
+ "\x00\xc1\xe0\x06\x13 0y" + // 0x03078 0x03099: 0x03079
+ "\x00\xc1\xe0\x06\x13@0z" + // 0x03078 0x0309A: 0x0307A
+ "\x00\xc1\xec\x06\x13 0|" + // 0x0307B 0x03099: 0x0307C
+ "\x00\xc1\xec\x06\x13@0}" + // 0x0307B 0x0309A: 0x0307D
+ "\x00\xc1\x18\x06\x13 0\x94" + // 0x03046 0x03099: 0x03094
+ "\x00\xc2t\x06\x13 0\x9e" + // 0x0309D 0x03099: 0x0309E
+ "\x00¬\x06\x13 0\xac" + // 0x030AB 0x03099: 0x030AC
+ "\x00´\x06\x13 0\xae" + // 0x030AD 0x03099: 0x030AE
+ "\x00¼\x06\x13 0\xb0" + // 0x030AF 0x03099: 0x030B0
+ "\x00\xc2\xc4\x06\x13 0\xb2" + // 0x030B1 0x03099: 0x030B2
+ "\x00\xc2\xcc\x06\x13 0\xb4" + // 0x030B3 0x03099: 0x030B4
+ "\x00\xc2\xd4\x06\x13 0\xb6" + // 0x030B5 0x03099: 0x030B6
+ "\x00\xc2\xdc\x06\x13 0\xb8" + // 0x030B7 0x03099: 0x030B8
+ "\x00\xc2\xe4\x06\x13 0\xba" + // 0x030B9 0x03099: 0x030BA
+ "\x00\xc2\xec\x06\x13 0\xbc" + // 0x030BB 0x03099: 0x030BC
+ "\x00\xc2\xf4\x06\x13 0\xbe" + // 0x030BD 0x03099: 0x030BE
+ "\x00\xc2\xfc\x06\x13 0\xc0" + // 0x030BF 0x03099: 0x030C0
+ "\x00\xc3\x04\x06\x13 0\xc2" + // 0x030C1 0x03099: 0x030C2
+ "\x00\xc3\x10\x06\x13 0\xc5" + // 0x030C4 0x03099: 0x030C5
+ "\x00\xc3\x18\x06\x13 0\xc7" + // 0x030C6 0x03099: 0x030C7
+ "\x00\xc3 \x06\x13 0\xc9" + // 0x030C8 0x03099: 0x030C9
+ "\x00\xc3<\x06\x13 0\xd0" + // 0x030CF 0x03099: 0x030D0
+ "\x00\xc3<\x06\x13@0\xd1" + // 0x030CF 0x0309A: 0x030D1
+ "\x00\xc3H\x06\x13 0\xd3" + // 0x030D2 0x03099: 0x030D3
+ "\x00\xc3H\x06\x13@0\xd4" + // 0x030D2 0x0309A: 0x030D4
+ "\x00\xc3T\x06\x13 0\xd6" + // 0x030D5 0x03099: 0x030D6
+ "\x00\xc3T\x06\x13@0\xd7" + // 0x030D5 0x0309A: 0x030D7
+ "\x00\xc3`\x06\x13 0\xd9" + // 0x030D8 0x03099: 0x030D9
+ "\x00\xc3`\x06\x13@0\xda" + // 0x030D8 0x0309A: 0x030DA
+ "\x00\xc3l\x06\x13 0\xdc" + // 0x030DB 0x03099: 0x030DC
+ "\x00\xc3l\x06\x13@0\xdd" + // 0x030DB 0x0309A: 0x030DD
+ "\x00\u0098\x06\x13 0\xf4" + // 0x030A6 0x03099: 0x030F4
+ "\x00ü\x06\x13 0\xf7" + // 0x030EF 0x03099: 0x030F7
+ "\x00\xc3\xc0\x06\x13 0\xf8" + // 0x030F0 0x03099: 0x030F8
+ "\x00\xc3\xc4\x06\x13 0\xf9" + // 0x030F1 0x03099: 0x030F9
+ "\x00\xc3\xc8\x06\x13 0\xfa" + // 0x030F2 0x03099: 0x030FA
+ "\x00\xc3\xf4\x06\x13 0\xfe" + // 0x030FD 0x03099: 0x030FE
+ "\x04\x17H\x00`\xe1\x05\xc9" + // 0x105D2 0x00307: 0x105C9
+ "\x04\x17h\x00`\xe1\x05\xe4" + // 0x105DA 0x00307: 0x105E4
+ "\x04Bd\"\x17A\x10\x9a" + // 0x11099 0x110BA: 0x1109A
+ "\x04Bl\"\x17A\x10\x9c" + // 0x1109B 0x110BA: 0x1109C
+ "\x04B\x94\"\x17A\x10\xab" + // 0x110A5 0x110BA: 0x110AB
+ "\x04D\xc4\"$\xe1\x11." + // 0x11131 0x11127: 0x1112E
+ "\x04D\xc8\"$\xe1\x11/" + // 0x11132 0x11127: 0x1112F
+ "\x04M\x1c\"g\xc1\x13K" + // 0x11347 0x1133E: 0x1134B
+ "\x04M\x1c\"j\xe1\x13L" + // 0x11347 0x11357: 0x1134C
+ "\x04N\b\"y!\x13\x83" + // 0x11382 0x113C9: 0x11383
+ "\x04N\x10\"wa\x13\x85" + // 0x11384 0x113BB: 0x11385
+ "\x04N,\"xA\x13\x8e" + // 0x1138B 0x113C2: 0x1138E
+ "\x04N@\"y!\x13\x91" + // 0x11390 0x113C9: 0x11391
+ "\x04O\b\"xA\x13\xc5" + // 0x113C2 0x113C2: 0x113C5
+ "\x04O\b\"w\x01\x13\xc7" + // 0x113C2 0x113B8: 0x113C7
+ "\x04O\b\"y!\x13\xc8" + // 0x113C2 0x113C9: 0x113C8
+ "\x04R\xe4\"\x97A\x14\xbb" + // 0x114B9 0x114BA: 0x114BB
+ "\x04R\xe4\"\x96\x01\x14\xbc" + // 0x114B9 0x114B0: 0x114BC
+ "\x04R\xe4\"\x97\xa1\x14\xbe" + // 0x114B9 0x114BD: 0x114BE
+ "\x04V\xe0\"\xb5\xe1\x15\xba" + // 0x115B8 0x115AF: 0x115BA
+ "\x04V\xe4\"\xb5\xe1\x15\xbb" + // 0x115B9 0x115AF: 0x115BB
+ "\x04d\xd4#&\x01\x198" + // 0x11935 0x11930: 0x11938
+ "\x05\x84x,#\xc1a!" + // 0x1611E 0x1611E: 0x16121
+ "\x05\x84x,%!a\"" + // 0x1611E 0x16129: 0x16122
+ "\x05\x84x,#\xe1a#" + // 0x1611E 0x1611F: 0x16123
+ "\x05\x84\xa4,#\xe1a$" + // 0x16129 0x1611F: 0x16124
+ "\x05\x84x,$\x01a%" + // 0x1611E 0x16120: 0x16125
+ "\x05\x84\x84,#\xe1a&" + // 0x16121 0x1611F: 0x16126
+ "\x05\x84\x88,#\xe1a'" + // 0x16122 0x1611F: 0x16127
+ "\x05\x84\x84,$\x01a(" + // 0x16121 0x16120: 0x16128
+ "\x05\xb5\x9c-\xac\xe1mh" + // 0x16D67 0x16D67: 0x16D68
+ "\x05\xb5\x8c-\xac\xe1mi" + // 0x16D63 0x16D67: 0x16D69
+ "\x05\xb5\xa4-\xac\xe1mj" + // 0x16D69 0x16D67: 0x16D6A
""
// Total size of tables: 57KB (58086 bytes)
diff --git a/vendor/golang.org/x/text/unicode/norm/transform.go b/vendor/golang.org/x/text/unicode/norm/transform.go
index a1d366a..583230d 100644
--- a/vendor/golang.org/x/text/unicode/norm/transform.go
+++ b/vendor/golang.org/x/text/unicode/norm/transform.go
@@ -33,7 +33,7 @@ func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
return nDst + n, nSrc + n, err
}
- if err == nil && n < len(src) && !atEOF {
+ if err == nil && n < len(src) {
err = transform.ErrShortSrc
}
return n, n, err
@@ -67,6 +67,7 @@ func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
nSrc = end
// Next quickSpan.
+ var err error
end = rb.nsrc
eof := atEOF
if n := nSrc + len(dst) - nDst; n < end {
@@ -79,7 +80,7 @@ func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
nSrc += n
nDst += n
if ok {
- if err == nil && n < rb.nsrc && !atEOF {
+ if err == nil && nSrc < rb.nsrc {
err = transform.ErrShortSrc
}
return nDst, nSrc, err
diff --git a/vendor/golang.org/x/time/LICENSE b/vendor/golang.org/x/time/LICENSE
new file mode 100644
index 0000000..2a7cf70
--- /dev/null
+++ b/vendor/golang.org/x/time/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/time/PATENTS b/vendor/golang.org/x/time/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/vendor/golang.org/x/time/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/time/rate/rate.go b/vendor/golang.org/x/time/rate/rate.go
new file mode 100644
index 0000000..563270c
--- /dev/null
+++ b/vendor/golang.org/x/time/rate/rate.go
@@ -0,0 +1,427 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rate provides a rate limiter.
+package rate
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "sync"
+ "time"
+)
+
+// Limit defines the maximum frequency of some events.
+// Limit is represented as number of events per second.
+// A zero Limit allows no events.
+type Limit float64
+
+// Inf is the infinite rate limit; it allows all events (even if burst is zero).
+const Inf = Limit(math.MaxFloat64)
+
+// Every converts a minimum time interval between events to a Limit.
+func Every(interval time.Duration) Limit {
+ if interval <= 0 {
+ return Inf
+ }
+ return 1 / Limit(interval.Seconds())
+}
+
+// A Limiter controls how frequently events are allowed to happen.
+// It implements a "token bucket" of size b, initially full and refilled
+// at rate r tokens per second.
+// Informally, in any large enough time interval, the Limiter limits the
+// rate to r tokens per second, with a maximum burst size of b events.
+// As a special case, if r == Inf (the infinite rate), b is ignored.
+// See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.
+//
+// The zero value is a valid Limiter, but it will reject all events.
+// Use NewLimiter to create non-zero Limiters.
+//
+// Limiter has three main methods, Allow, Reserve, and Wait.
+// Most callers should use Wait.
+//
+// Each of the three methods consumes a single token.
+// They differ in their behavior when no token is available.
+// If no token is available, Allow returns false.
+// If no token is available, Reserve returns a reservation for a future token
+// and the amount of time the caller must wait before using it.
+// If no token is available, Wait blocks until one can be obtained
+// or its associated context.Context is canceled.
+//
+// The methods AllowN, ReserveN, and WaitN consume n tokens.
+//
+// Limiter is safe for simultaneous use by multiple goroutines.
+type Limiter struct {
+ mu sync.Mutex
+ limit Limit
+ burst int
+ tokens float64
+ // last is the last time the limiter's tokens field was updated
+ last time.Time
+ // lastEvent is the latest time of a rate-limited event (past or future)
+ lastEvent time.Time
+}
+
+// Limit returns the maximum overall event rate.
+func (lim *Limiter) Limit() Limit {
+ lim.mu.Lock()
+ defer lim.mu.Unlock()
+ return lim.limit
+}
+
+// Burst returns the maximum burst size. Burst is the maximum number of tokens
+// that can be consumed in a single call to Allow, Reserve, or Wait, so higher
+// Burst values allow more events to happen at once.
+// A zero Burst allows no events, unless limit == Inf.
+func (lim *Limiter) Burst() int {
+ lim.mu.Lock()
+ defer lim.mu.Unlock()
+ return lim.burst
+}
+
+// TokensAt returns the number of tokens available at time t.
+func (lim *Limiter) TokensAt(t time.Time) float64 {
+ lim.mu.Lock()
+ tokens := lim.advance(t) // does not mutate lim
+ lim.mu.Unlock()
+ return tokens
+}
+
+// Tokens returns the number of tokens available now.
+func (lim *Limiter) Tokens() float64 {
+ return lim.TokensAt(time.Now())
+}
+
+// NewLimiter returns a new Limiter that allows events up to rate r and permits
+// bursts of at most b tokens.
+func NewLimiter(r Limit, b int) *Limiter {
+ return &Limiter{
+ limit: r,
+ burst: b,
+ tokens: float64(b),
+ }
+}
+
+// Allow reports whether an event may happen now.
+func (lim *Limiter) Allow() bool {
+ return lim.AllowN(time.Now(), 1)
+}
+
+// AllowN reports whether n events may happen at time t.
+// Use this method if you intend to drop / skip events that exceed the rate limit.
+// Otherwise use Reserve or Wait.
+func (lim *Limiter) AllowN(t time.Time, n int) bool {
+ return lim.reserveN(t, n, 0).ok
+}
+
+// A Reservation holds information about events that are permitted by a Limiter to happen after a delay.
+// A Reservation may be canceled, which may enable the Limiter to permit additional events.
+type Reservation struct {
+ ok bool
+ lim *Limiter
+ tokens int
+ timeToAct time.Time
+ // This is the Limit at reservation time, it can change later.
+ limit Limit
+}
+
+// OK returns whether the limiter can provide the requested number of tokens
+// within the maximum wait time. If OK is false, Delay returns InfDuration, and
+// Cancel does nothing.
+func (r *Reservation) OK() bool {
+ return r.ok
+}
+
+// Delay is shorthand for DelayFrom(time.Now()).
+func (r *Reservation) Delay() time.Duration {
+ return r.DelayFrom(time.Now())
+}
+
+// InfDuration is the duration returned by Delay when a Reservation is not OK.
+const InfDuration = time.Duration(math.MaxInt64)
+
+// DelayFrom returns the duration for which the reservation holder must wait
+// before taking the reserved action. Zero duration means act immediately.
+// InfDuration means the limiter cannot grant the tokens requested in this
+// Reservation within the maximum wait time.
+func (r *Reservation) DelayFrom(t time.Time) time.Duration {
+ if !r.ok {
+ return InfDuration
+ }
+ delay := r.timeToAct.Sub(t)
+ if delay < 0 {
+ return 0
+ }
+ return delay
+}
+
+// Cancel is shorthand for CancelAt(time.Now()).
+func (r *Reservation) Cancel() {
+ r.CancelAt(time.Now())
+}
+
+// CancelAt indicates that the reservation holder will not perform the reserved action
+// and reverses the effects of this Reservation on the rate limit as much as possible,
+// considering that other reservations may have already been made.
+func (r *Reservation) CancelAt(t time.Time) {
+ if !r.ok {
+ return
+ }
+
+ r.lim.mu.Lock()
+ defer r.lim.mu.Unlock()
+
+ if r.lim.limit == Inf || r.tokens == 0 || r.timeToAct.Before(t) {
+ return
+ }
+
+ // calculate tokens to restore
+ // The duration between lim.lastEvent and r.timeToAct tells us how many tokens were reserved
+ // after r was obtained. These tokens should not be restored.
+ restoreTokens := float64(r.tokens) - r.limit.tokensFromDuration(r.lim.lastEvent.Sub(r.timeToAct))
+ if restoreTokens <= 0 {
+ return
+ }
+ // advance time to now
+ tokens := r.lim.advance(t)
+ // calculate new number of tokens
+ tokens += restoreTokens
+ if burst := float64(r.lim.burst); tokens > burst {
+ tokens = burst
+ }
+ // update state
+ r.lim.last = t
+ r.lim.tokens = tokens
+ if r.timeToAct.Equal(r.lim.lastEvent) {
+ prevEvent := r.timeToAct.Add(r.limit.durationFromTokens(float64(-r.tokens)))
+ if !prevEvent.Before(t) {
+ r.lim.lastEvent = prevEvent
+ }
+ }
+}
+
+// Reserve is shorthand for ReserveN(time.Now(), 1).
+func (lim *Limiter) Reserve() *Reservation {
+ return lim.ReserveN(time.Now(), 1)
+}
+
+// ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.
+// The Limiter takes this Reservation into account when allowing future events.
+// The returned Reservation’s OK() method returns false if n exceeds the Limiter's burst size.
+// Usage example:
+//
+// r := lim.ReserveN(time.Now(), 1)
+// if !r.OK() {
+// // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
+// return
+// }
+// time.Sleep(r.Delay())
+// Act()
+//
+// Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.
+// If you need to respect a deadline or cancel the delay, use Wait instead.
+// To drop or skip events exceeding rate limit, use Allow instead.
+func (lim *Limiter) ReserveN(t time.Time, n int) *Reservation {
+ r := lim.reserveN(t, n, InfDuration)
+ return &r
+}
+
+// Wait is shorthand for WaitN(ctx, 1).
+func (lim *Limiter) Wait(ctx context.Context) (err error) {
+ return lim.WaitN(ctx, 1)
+}
+
+// WaitN blocks until lim permits n events to happen.
+// It returns an error if n exceeds the Limiter's burst size, the Context is
+// canceled, or the expected wait time exceeds the Context's Deadline.
+// The burst limit is ignored if the rate limit is Inf.
+func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
+ // The test code calls lim.wait with a fake timer generator.
+ // This is the real timer generator.
+ newTimer := func(d time.Duration) (<-chan time.Time, func() bool, func()) {
+ timer := time.NewTimer(d)
+ return timer.C, timer.Stop, func() {}
+ }
+
+ return lim.wait(ctx, n, time.Now(), newTimer)
+}
+
+// wait is the internal implementation of WaitN.
+func (lim *Limiter) wait(ctx context.Context, n int, t time.Time, newTimer func(d time.Duration) (<-chan time.Time, func() bool, func())) error {
+ lim.mu.Lock()
+ burst := lim.burst
+ limit := lim.limit
+ lim.mu.Unlock()
+
+ if n > burst && limit != Inf {
+ return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, burst)
+ }
+ // Check if ctx is already cancelled
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ }
+ // Determine wait limit
+ waitLimit := InfDuration
+ if deadline, ok := ctx.Deadline(); ok {
+ waitLimit = deadline.Sub(t)
+ }
+ // Reserve
+ r := lim.reserveN(t, n, waitLimit)
+ if !r.ok {
+ return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
+ }
+ // Wait if necessary
+ delay := r.DelayFrom(t)
+ if delay == 0 {
+ return nil
+ }
+ ch, stop, advance := newTimer(delay)
+ defer stop()
+ advance() // only has an effect when testing
+ select {
+ case <-ch:
+ // We can proceed.
+ return nil
+ case <-ctx.Done():
+ // Context was canceled before we could proceed. Cancel the
+ // reservation, which may permit other events to proceed sooner.
+ r.Cancel()
+ return ctx.Err()
+ }
+}
+
+// SetLimit is shorthand for SetLimitAt(time.Now(), newLimit).
+func (lim *Limiter) SetLimit(newLimit Limit) {
+ lim.SetLimitAt(time.Now(), newLimit)
+}
+
+// SetLimitAt sets a new Limit for the limiter. The new Limit, and Burst, may be violated
+// or underutilized by those which reserved (using Reserve or Wait) but did not yet act
+// before SetLimitAt was called.
+func (lim *Limiter) SetLimitAt(t time.Time, newLimit Limit) {
+ lim.mu.Lock()
+ defer lim.mu.Unlock()
+
+ tokens := lim.advance(t)
+
+ lim.last = t
+ lim.tokens = tokens
+ lim.limit = newLimit
+}
+
+// SetBurst is shorthand for SetBurstAt(time.Now(), newBurst).
+func (lim *Limiter) SetBurst(newBurst int) {
+ lim.SetBurstAt(time.Now(), newBurst)
+}
+
+// SetBurstAt sets a new burst size for the limiter.
+func (lim *Limiter) SetBurstAt(t time.Time, newBurst int) {
+ lim.mu.Lock()
+ defer lim.mu.Unlock()
+
+ tokens := lim.advance(t)
+
+ lim.last = t
+ lim.tokens = tokens
+ lim.burst = newBurst
+}
+
+// reserveN is a helper method for AllowN, ReserveN, and WaitN.
+// maxFutureReserve specifies the maximum reservation wait duration allowed.
+// reserveN returns Reservation, not *Reservation, to avoid allocation in AllowN and WaitN.
+func (lim *Limiter) reserveN(t time.Time, n int, maxFutureReserve time.Duration) Reservation {
+ lim.mu.Lock()
+ defer lim.mu.Unlock()
+
+ if lim.limit == Inf {
+ return Reservation{
+ ok: true,
+ lim: lim,
+ tokens: n,
+ timeToAct: t,
+ }
+ }
+
+ tokens := lim.advance(t)
+
+ // Calculate the remaining number of tokens resulting from the request.
+ tokens -= float64(n)
+
+ // Calculate the wait duration
+ var waitDuration time.Duration
+ if tokens < 0 {
+ waitDuration = lim.limit.durationFromTokens(-tokens)
+ }
+
+ // Decide result
+ ok := n <= lim.burst && waitDuration <= maxFutureReserve
+
+ // Prepare reservation
+ r := Reservation{
+ ok: ok,
+ lim: lim,
+ limit: lim.limit,
+ }
+ if ok {
+ r.tokens = n
+ r.timeToAct = t.Add(waitDuration)
+
+ // Update state
+ lim.last = t
+ lim.tokens = tokens
+ lim.lastEvent = r.timeToAct
+ }
+
+ return r
+}
+
+// advance calculates and returns an updated number of tokens for lim
+// resulting from the passage of time.
+// lim is not changed.
+// advance requires that lim.mu is held.
+func (lim *Limiter) advance(t time.Time) (newTokens float64) {
+ last := lim.last
+ if t.Before(last) {
+ last = t
+ }
+
+ // Calculate the new number of tokens, due to time that passed.
+ elapsed := t.Sub(last)
+ delta := lim.limit.tokensFromDuration(elapsed)
+ tokens := lim.tokens + delta
+ if burst := float64(lim.burst); tokens > burst {
+ tokens = burst
+ }
+ return tokens
+}
+
+// durationFromTokens is a unit conversion function from the number of tokens to the duration
+// of time it takes to accumulate them at a rate of limit tokens per second.
+func (limit Limit) durationFromTokens(tokens float64) time.Duration {
+ if limit <= 0 {
+ return InfDuration
+ }
+
+ duration := (tokens / float64(limit)) * float64(time.Second)
+
+ // Cap the duration to the maximum representable int64 value, to avoid overflow.
+ if duration > float64(math.MaxInt64) {
+ return InfDuration
+ }
+
+ return time.Duration(duration)
+}
+
+// tokensFromDuration is a unit conversion function from a time duration to the number of tokens
+// which could be accumulated during that duration at a rate of limit tokens per second.
+func (limit Limit) tokensFromDuration(d time.Duration) float64 {
+ if limit <= 0 {
+ return 0
+ }
+ return d.Seconds() * float64(limit)
+}
diff --git a/vendor/golang.org/x/time/rate/sometimes.go b/vendor/golang.org/x/time/rate/sometimes.go
new file mode 100644
index 0000000..9b83932
--- /dev/null
+++ b/vendor/golang.org/x/time/rate/sometimes.go
@@ -0,0 +1,69 @@
+// 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 rate
+
+import (
+ "sync"
+ "time"
+)
+
+// Sometimes will perform an action occasionally. The First, Every, and
+// Interval fields govern the behavior of Do, which performs the action.
+// A zero Sometimes value will perform an action exactly once.
+//
+// # Example: logging with rate limiting
+//
+// var sometimes = rate.Sometimes{First: 3, Interval: 10*time.Second}
+// func Spammy() {
+// sometimes.Do(func() { log.Info("here I am!") })
+// }
+type Sometimes struct {
+ First int // if non-zero, the first N calls to Do will run f.
+ Every int // if non-zero, every Nth call to Do will run f.
+ Interval time.Duration // if non-zero and Interval has elapsed since f's last run, Do will run f.
+
+ mu sync.Mutex
+ count int // number of Do calls
+ last time.Time // last time f was run
+}
+
+// Do runs the function f as allowed by First, Every, and Interval.
+//
+// The model is a union (not intersection) of filters. The first call to Do
+// always runs f. Subsequent calls to Do run f if allowed by First or Every or
+// Interval.
+//
+// A non-zero First:N causes the first N Do(f) calls to run f.
+//
+// A non-zero Every:M causes every Mth Do(f) call, starting with the first, to
+// run f.
+//
+// A non-zero Interval causes Do(f) to run f if Interval has elapsed since
+// Do last ran f.
+//
+// Specifying multiple filters produces the union of these execution streams.
+// For example, specifying both First:N and Every:M causes the first N Do(f)
+// calls and every Mth Do(f) call, starting with the first, to run f. See
+// Examples for more.
+//
+// If Do is called multiple times simultaneously, the calls will block and run
+// serially. Therefore, Do is intended for lightweight operations.
+//
+// Because a call to Do may block until f returns, if f causes Do to be called,
+// it will deadlock.
+func (s *Sometimes) Do(f func()) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.count == 0 ||
+ (s.First > 0 && s.count < s.First) ||
+ (s.Every > 0 && s.count%s.Every == 0) ||
+ (s.Interval > 0 && time.Since(s.last) >= s.Interval) {
+ f()
+ if s.Interval > 0 {
+ s.last = time.Now()
+ }
+ }
+ s.count++
+}
diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go
index 326888a..7e3dbaa 100644
--- a/vendor/google.golang.org/grpc/balancer/balancer.go
+++ b/vendor/google.golang.org/grpc/balancer/balancer.go
@@ -60,7 +60,7 @@ func Register(b Builder) {
if !envconfig.CaseSensitiveBalancerRegistries {
name = strings.ToLower(name)
if name != b.Name() {
- logger.Warningf("Balancer registered with name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", b.Name())
+ logger.Warningf("Balancer registered with name %q. grpc-go has switched to case sensitive balancer registries. GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES env variable will be removed in release v1.82.0", b.Name())
}
}
m[name] = b
@@ -85,7 +85,7 @@ func Get(name string) Builder {
if !envconfig.CaseSensitiveBalancerRegistries {
lowerName := strings.ToLower(name)
if lowerName != name {
- logger.Warningf("Balancer retrieved for name %q. grpc-go will be switching to case sensitive balancer registries soon. After 2 releases, we will enable the env var by default.", name)
+ logger.Warningf("Balancer retrieved for name %q. grpc-go has switched to case sensitive balancer registries. GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES env variable will be removed in release v1.82.0", name)
}
name = lowerName
}
diff --git a/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go b/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go
index 12479f6..22dbc52 100644
--- a/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go
+++ b/vendor/google.golang.org/grpc/balancer/endpointsharding/endpointsharding.go
@@ -39,27 +39,14 @@ import (
var randIntN = rand.IntN
-// ChildState is the balancer state of a child along with the endpoint which
-// identifies the child balancer.
+// ChildState is the state of a child balancer.
type ChildState struct {
- Endpoint resolver.Endpoint
- State balancer.State
-
- // Balancer exposes only the ExitIdler interface of the child LB policy.
- // Other methods of the child policy are called only by endpointsharding.
- Balancer ExitIdler
-}
-
-// ExitIdler provides access to only the ExitIdle method of the child balancer.
-type ExitIdler interface {
- // ExitIdle instructs the LB policy to reconnect to backends / exit the
- // IDLE state, if appropriate and possible. Note that SubConns that enter
- // the IDLE state will not reconnect until SubConn.Connect is called.
- ExitIdle()
+ Endpoint resolver.Endpoint // Endpoint of the child balancer.
+ State balancer.State // State of the child balancer.
+ ExitIdle func() // Function to exit the child balancer from IDLE state.
}
-// Options are the options to configure the behaviour of the
-// endpointsharding balancer.
+// Options configure the behaviour of the endpointsharding balancer.
type Options struct {
// DisableAutoReconnect allows the balancer to keep child balancer in the
// IDLE state until they are explicitly triggered to exit using the
@@ -77,14 +64,13 @@ type ChildBuilderFunc func(cc balancer.ClientConn, opts balancer.BuildOptions) b
// policies each owning a single endpoint. The endpointsharding balancer
// forwards the LoadBalancingConfig in ClientConn state updates to its children.
func NewBalancer(cc balancer.ClientConn, opts balancer.BuildOptions, childBuilder ChildBuilderFunc, esOpts Options) balancer.Balancer {
- es := &endpointSharding{
+ return &endpointSharding{
cc: cc,
bOpts: opts,
esOpts: esOpts,
childBuilder: childBuilder,
+ endpoints: resolver.NewEndpointMap[*endpointState](),
}
- es.children.Store(resolver.NewEndpointMap[*balancerWrapper]())
- return es
}
// endpointSharding is a balancer that wraps child balancers. It creates a child
@@ -96,124 +82,129 @@ type endpointSharding struct {
esOpts Options
childBuilder ChildBuilderFunc
- // childMu synchronizes calls to any single child. It must be held for all
- // calls into a child. To avoid deadlocks, do not acquire childMu while
- // holding mu.
- childMu sync.Mutex
- children atomic.Pointer[resolver.EndpointMap[*balancerWrapper]]
-
- // inhibitChildUpdates is set during UpdateClientConnState/ResolverError
- // calls (calls to children will each produce an update, only want one
- // update).
- inhibitChildUpdates atomic.Bool
-
- // mu synchronizes access to the state stored in balancerWrappers in the
- // children field. mu must not be held during calls into a child since
- // synchronous calls back from the child may require taking mu, causing a
- // deadlock. To avoid deadlocks, do not acquire childMu while holding mu.
- mu sync.Mutex
+ // mu guards access to the below fields and guarantees mutual exclusion
+ // between top-down methods (like UpdateClientConnState, ResolverError etc,
+ // which are already serialized) and bottom-up methods (like UpdateState)
+ // that can be called concurrently.
+ //
+ // Lock ordering & deadlock prevention:
+ // Child callbacks (like UpdateState) acquire this mutex to push state updates
+ // to the parent. This establishes a strict lock ordering:
+ // [endpointState.childMu] -> [endpointSharding.mu]
+ //
+ // To prevent deadlocks, we must never invert this order. Therefore, we must
+ // never call any methods on a child balancer while holding this mutex. If we
+ // did, and that child balancer invoked UpdateState synchronously, it would
+ // attempt to re-acquire this mutex, causing a deadlock.
+ //
+ // Concurrency:
+ // Top-down operations need to iterate over all children. To ensure a
+ // single, clean aggregated update at the end of such operations, we inhibit
+ // intermediate updates from children. We grab this mutex briefly to set
+ // `inhibitChildUpdates = true` and immediately release it. This allows us
+ // to perform the potentially slow, top-down child updates without holding
+ // any parent locks. Once finished, we grab the mutex again to unset the
+ // flag and push the final aggregated state. An update from a child during
+ // this time will *only* update the child state, and will not access the
+ // endpoints map or push an aggregated state to the parent.
+ mu sync.Mutex
+ endpoints *resolver.EndpointMap[*endpointState]
+ inhibitChildUpdates bool
}
// rotateEndpoints returns a slice of all the input endpoints rotated a random
// amount.
func rotateEndpoints(es []resolver.Endpoint) []resolver.Endpoint {
- les := len(es)
- if les == 0 {
+ n := len(es)
+ if n == 0 {
return es
}
- r := randIntN(les)
+ r := randIntN(n)
+
// Make a copy to avoid mutating data beyond the end of es.
- ret := make([]resolver.Endpoint, les)
+ ret := make([]resolver.Endpoint, n)
copy(ret, es[r:])
- copy(ret[les-r:], es[:r])
+ copy(ret[n-r:], es[:r])
return ret
}
// UpdateClientConnState creates a child for new endpoints and deletes children
// for endpoints that are no longer present. It also updates all the children,
// and sends a single synchronous update of the childrens' aggregated state at
-// the end of the UpdateClientConnState operation. If any endpoint has no
-// addresses it will ignore that endpoint. Otherwise, returns first error found
-// from a child, but fully processes the new update.
+// the end of the UpdateClientConnState operation.
+//
+// Returns the first error found from a child, but fully processes the update.
func (es *endpointSharding) UpdateClientConnState(state balancer.ClientConnState) error {
- es.childMu.Lock()
- defer es.childMu.Unlock()
-
- es.inhibitChildUpdates.Store(true)
- defer func() {
- es.inhibitChildUpdates.Store(false)
- es.updateState()
- }()
- var ret error
-
- children := es.children.Load()
- newChildren := resolver.NewEndpointMap[*balancerWrapper]()
+ es.inhibitUpdatesFromChildren()
- // Update/Create new children.
+ // Update/create child balancers for each endpoint in the update. Note that we
+ // don't hold the mutex here, but this is fine because inhibitChildUpdates is
+ // true, and therefore UpdateState will not access es.endpoints.
+ var retErr error
+ newEndpoints := resolver.NewEndpointMap[*endpointState]()
for _, endpoint := range rotateEndpoints(state.ResolverState.Endpoints) {
- if _, ok := newChildren.Get(endpoint); ok {
- // Endpoint child was already created, continue to avoid duplicate
- // update.
+ if _, ok := newEndpoints.Get(endpoint); ok {
+ // Skip duplicate endpoints.
continue
}
- childBalancer, ok := children.Get(endpoint)
+ epState, ok := es.endpoints.Get(endpoint)
if ok {
- // Endpoint attributes may have changed, update the stored endpoint.
- es.mu.Lock()
- childBalancer.childState.Endpoint = endpoint
- es.mu.Unlock()
+ // Endpoint child already exists, update the stored endpoint.
+ epState.endpoint = endpoint
} else {
- childBalancer = &balancerWrapper{
- childState: ChildState{Endpoint: endpoint},
- ClientConn: es.cc,
- es: es,
+ // Endpoint child does not exist, create a new one.
+ epState = &endpointState{
+ ClientConn: es.cc,
+ parent: es,
+ endpoint: endpoint,
+ disableAutoReconnect: es.esOpts.DisableAutoReconnect,
}
- childBalancer.childState.Balancer = childBalancer
- childBalancer.child = es.childBuilder(childBalancer, es.bOpts)
+ epState.childLB = es.childBuilder(epState, es.bOpts)
}
- newChildren.Set(endpoint, childBalancer)
- if err := childBalancer.updateClientConnStateLocked(balancer.ClientConnState{
+ // Update the endpoint state for the endpoint.
+ newEndpoints.Set(endpoint, epState)
+
+ if err := epState.updateClientConnState(balancer.ClientConnState{
BalancerConfig: state.BalancerConfig,
ResolverState: resolver.State{
Endpoints: []resolver.Endpoint{endpoint},
Attributes: state.ResolverState.Attributes,
},
- }); err != nil && ret == nil {
- // Return first error found, and always commit full processing of
- // updating children. If desired to process more specific errors
- // across all endpoints, caller should make these specific
- // validations, this is a current limitation for simplicity sake.
- ret = err
+ }); err != nil && retErr == nil {
+ // Keep the first error found from any child.
+ retErr = err
}
}
+
// Delete old children that are no longer present.
- for e, child := range children.All() {
- if _, ok := newChildren.Get(e); !ok {
- child.closeLocked()
+ for e, child := range es.endpoints.All() {
+ if _, ok := newEndpoints.Get(e); !ok {
+ child.close()
}
}
- es.children.Store(newChildren)
- if newChildren.Len() == 0 {
- return balancer.ErrBadResolverState
+
+ if newEndpoints.Len() == 0 {
+ retErr = balancer.ErrBadResolverState
}
- return ret
+
+ es.mu.Lock()
+ es.endpoints = newEndpoints
+ es.inhibitChildUpdates = false
+ es.updateStateLocked()
+ es.mu.Unlock()
+
+ return retErr
}
// ResolverError forwards the resolver error to all of the endpointSharding's
// children and sends a single synchronous update of the childStates at the end
// of the ResolverError operation.
func (es *endpointSharding) ResolverError(err error) {
- es.childMu.Lock()
- defer es.childMu.Unlock()
- es.inhibitChildUpdates.Store(true)
- defer func() {
- es.inhibitChildUpdates.Store(false)
- es.updateState()
- }()
- children := es.children.Load()
- for _, child := range children.All() {
- child.resolverErrorLocked(err)
+ es.inhibitUpdatesFromChildren()
+ for _, child := range es.endpoints.All() {
+ child.resolverError(err)
}
+ es.allowUpdatesFromChildren()
}
func (es *endpointSharding) UpdateSubConnState(balancer.SubConn, balancer.SubConnState) {
@@ -221,41 +212,49 @@ func (es *endpointSharding) UpdateSubConnState(balancer.SubConn, balancer.SubCon
}
func (es *endpointSharding) Close() {
- es.childMu.Lock()
- defer es.childMu.Unlock()
- children := es.children.Load()
- for _, child := range children.All() {
- child.closeLocked()
+ es.inhibitUpdatesFromChildren()
+ for _, child := range es.endpoints.All() {
+ child.close()
}
}
func (es *endpointSharding) ExitIdle() {
- es.childMu.Lock()
- defer es.childMu.Unlock()
- for _, bw := range es.children.Load().All() {
- if !bw.isClosed {
- bw.child.ExitIdle()
- }
+ es.inhibitUpdatesFromChildren()
+ for _, child := range es.endpoints.All() {
+ child.exitIdle()
}
+ es.allowUpdatesFromChildren()
}
-// updateState updates this component's state. It sends the aggregated state,
-// and a picker with round robin behavior with all the child states present if
-// needed.
-func (es *endpointSharding) updateState() {
- if es.inhibitChildUpdates.Load() {
- return
- }
- var readyPickers, connectingPickers, idlePickers, transientFailurePickers []balancer.Picker
+func (es *endpointSharding) inhibitUpdatesFromChildren() {
+ es.mu.Lock()
+ es.inhibitChildUpdates = true
+ es.mu.Unlock()
+}
+func (es *endpointSharding) allowUpdatesFromChildren() {
es.mu.Lock()
- defer es.mu.Unlock()
+ es.inhibitChildUpdates = false
+ es.updateStateLocked()
+ es.mu.Unlock()
+}
- children := es.children.Load()
- childStates := make([]ChildState, 0, children.Len())
+// updateStateLocked updates this component's state. It sends the aggregated
+// state, and a picker with round robin behavior with all the child states
+// present if needed. This method must only be called when inhibitChildUpdates
+// is false.
+//
+// Caller must hold es.mu.
+func (es *endpointSharding) updateStateLocked() {
+ var readyPickers, connectingPickers, idlePickers, transientFailurePickers []balancer.Picker
- for _, child := range children.All() {
- childState := child.childState
+ childStates := make([]ChildState, 0, es.endpoints.Len())
+ for _, epState := range es.endpoints.All() {
+ childState := ChildState{
+ Endpoint: epState.endpoint,
+ State: epState.state,
+ ExitIdle: func() { go epState.exitIdle() },
+ }
childStates = append(childStates, childState)
childPicker := childState.State.Picker
switch childState.State.ConnectivityState {
@@ -292,14 +291,14 @@ func (es *endpointSharding) updateState() {
aggState = connectivity.TransientFailure
pickers = []balancer.Picker{base.NewErrPicker(errors.New("no children to pick from"))}
} // No children (resolver error before valid update).
- p := &pickerWithChildStates{
- pickers: pickers,
- childStates: childStates,
- next: uint32(randIntN(len(pickers))),
- }
+
es.cc.UpdateState(balancer.State{
ConnectivityState: aggState,
- Picker: p,
+ Picker: &pickerWithChildStates{
+ pickers: pickers,
+ childStates: childStates,
+ next: uint32(randIntN(len(pickers))),
+ },
})
}
@@ -328,61 +327,59 @@ func ChildStatesFromPicker(picker balancer.Picker) []ChildState {
return p.childStates
}
-// balancerWrapper is a wrapper of a balancer. It ID's a child balancer by
-// endpoint, and persists recent child balancer state.
-type balancerWrapper struct {
- // The following fields are initialized at build time and read-only after
- // that and therefore do not need to be guarded by a mutex.
-
- // child contains the wrapped balancer. Access its methods only through
- // methods on balancerWrapper to ensure proper synchronization
- child balancer.Balancer
- balancer.ClientConn // embed to intercept UpdateState, doesn't deal with SubConns
+// endpointState is the internal state maintained for each endpoint.
+type endpointState struct {
+ balancer.ClientConn // Embedded to intercept UpdateState
- es *endpointSharding
+ parent *endpointSharding // Parent endpointsharding balancer.
+ endpoint resolver.Endpoint // Endpoint of the child balancer.
+ state balancer.State // State of the child balancer.
+ disableAutoReconnect bool // Whether to disable auto reconnect for this child.
- // Access to the following fields is guarded by es.mu.
-
- childState ChildState
- isClosed bool
+ childMu sync.Mutex // Guarantees mutual exclusion for Balancer API calls to the child balancer.
+ childLB balancer.Balancer // Child balancer.
+ closed bool // Tracks closure of the child balancer to ensure ExitIdle is not called after Close().
}
-func (bw *balancerWrapper) UpdateState(state balancer.State) {
- bw.es.mu.Lock()
- bw.childState.State = state
- bw.es.mu.Unlock()
- if state.ConnectivityState == connectivity.Idle && !bw.es.esOpts.DisableAutoReconnect {
- bw.ExitIdle()
+func (es *endpointState) UpdateState(state balancer.State) {
+ es.parent.mu.Lock()
+ es.state = state
+ if !es.parent.inhibitChildUpdates {
+ es.parent.updateStateLocked()
+ }
+ es.parent.mu.Unlock()
+
+ if state.ConnectivityState == connectivity.Idle && !es.disableAutoReconnect {
+ go es.exitIdle()
}
- bw.es.updateState()
}
-// ExitIdle pings an IDLE child balancer to exit idle in a new goroutine to
-// avoid deadlocks due to synchronous balancer state updates.
-func (bw *balancerWrapper) ExitIdle() {
- go func() {
- bw.es.childMu.Lock()
- if !bw.isClosed {
- bw.child.ExitIdle()
- }
- bw.es.childMu.Unlock()
- }()
+func (es *endpointState) updateClientConnState(state balancer.ClientConnState) error {
+ es.childMu.Lock()
+ err := es.childLB.UpdateClientConnState(state)
+ es.childMu.Unlock()
+ return err
}
-// updateClientConnStateLocked delivers the ClientConnState to the child
-// balancer. Callers must hold the child mutex of the parent endpointsharding
-// balancer.
-func (bw *balancerWrapper) updateClientConnStateLocked(ccs balancer.ClientConnState) error {
- return bw.child.UpdateClientConnState(ccs)
+func (es *endpointState) resolverError(err error) {
+ es.childMu.Lock()
+ es.childLB.ResolverError(err)
+ es.childMu.Unlock()
}
-// closeLocked closes the child balancer. Callers must hold the child mutext of
-// the parent endpointsharding balancer.
-func (bw *balancerWrapper) closeLocked() {
- bw.child.Close()
- bw.isClosed = true
+func (es *endpointState) close() {
+ es.childMu.Lock()
+ if !es.closed {
+ es.closed = true
+ es.childLB.Close()
+ }
+ es.childMu.Unlock()
}
-func (bw *balancerWrapper) resolverErrorLocked(err error) {
- bw.child.ResolverError(err)
+func (es *endpointState) exitIdle() {
+ es.childMu.Lock()
+ if !es.closed {
+ es.childLB.ExitIdle()
+ }
+ es.childMu.Unlock()
}
diff --git a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go
index 518a69d..ddd08f5 100644
--- a/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go
+++ b/vendor/google.golang.org/grpc/balancer/pickfirst/pickfirst.go
@@ -35,9 +35,8 @@ import (
"google.golang.org/grpc/balancer"
"google.golang.org/grpc/balancer/pickfirst/internal"
"google.golang.org/grpc/connectivity"
- expstats "google.golang.org/grpc/experimental/stats"
+ "google.golang.org/grpc/experimental/balancer/weight"
"google.golang.org/grpc/grpclog"
- "google.golang.org/grpc/internal/balancer/weight"
"google.golang.org/grpc/internal/envconfig"
internalgrpclog "google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/pretty"
@@ -56,30 +55,7 @@ const Name = "pick_first"
// attributes to indicate whether the health listener usage is enabled.
type enableHealthListenerKeyType struct{}
-var (
- logger = grpclog.Component("pick-first-leaf-lb")
- disconnectionsMetric = expstats.RegisterInt64Count(expstats.MetricDescriptor{
- Name: "grpc.lb.pick_first.disconnections",
- Description: "EXPERIMENTAL. Number of times the selected subchannel becomes disconnected.",
- Unit: "{disconnection}",
- Labels: []string{"grpc.target"},
- Default: false,
- })
- connectionAttemptsSucceededMetric = expstats.RegisterInt64Count(expstats.MetricDescriptor{
- Name: "grpc.lb.pick_first.connection_attempts_succeeded",
- Description: "EXPERIMENTAL. Number of successful connection attempts.",
- Unit: "{attempt}",
- Labels: []string{"grpc.target"},
- Default: false,
- })
- connectionAttemptsFailedMetric = expstats.RegisterInt64Count(expstats.MetricDescriptor{
- Name: "grpc.lb.pick_first.connection_attempts_failed",
- Description: "EXPERIMENTAL. Number of failed connection attempts.",
- Unit: "{attempt}",
- Labels: []string{"grpc.target"},
- Default: false,
- })
-)
+var logger = grpclog.Component("pick-first-leaf-lb")
const (
// TODO: change to pick-first when this becomes the default pick_first policy.
@@ -101,11 +77,9 @@ const (
type pickfirstBuilder struct{}
-func (pickfirstBuilder) Build(cc balancer.ClientConn, bo balancer.BuildOptions) balancer.Balancer {
+func (pickfirstBuilder) Build(cc balancer.ClientConn, _ balancer.BuildOptions) balancer.Balancer {
b := &pickfirstBalancer{
- cc: cc,
- target: bo.Target.String(),
- metricsRecorder: cc.MetricsRecorder(),
+ cc: cc,
subConns: resolver.NewAddressMapV2[*scData](),
state: connectivity.Connecting,
@@ -185,10 +159,8 @@ func (b *pickfirstBalancer) newSCData(addr resolver.Address) (*scData, error) {
type pickfirstBalancer struct {
// The following fields are initialized at build time and read-only after
// that and therefore do not need to be guarded by a mutex.
- logger *internalgrpclog.PrefixLogger
- cc balancer.ClientConn
- target string
- metricsRecorder expstats.MetricsRecorder // guaranteed to be non nil
+ logger *internalgrpclog.PrefixLogger
+ cc balancer.ClientConn
// The mutex is used to ensure synchronization of updates triggered
// from the idle picker and the already serialized resolver,
@@ -633,14 +605,11 @@ func (b *pickfirstBalancer) updateSubConnState(sd *scData, newState balancer.Sub
return
}
- // Record a connection attempt when exiting CONNECTING.
if newState.ConnectivityState == connectivity.TransientFailure {
sd.connectionFailedInFirstPass = true
- connectionAttemptsFailedMetric.Record(b.metricsRecorder, 1, b.target)
}
if newState.ConnectivityState == connectivity.Ready {
- connectionAttemptsSucceededMetric.Record(b.metricsRecorder, 1, b.target)
b.shutdownRemainingLocked(sd)
if !b.addressList.seekTo(sd.addr) {
// This should not fail as we should have only one SubConn after
@@ -689,15 +658,6 @@ func (b *pickfirstBalancer) updateSubConnState(sd *scData, newState balancer.Sub
// the first address when the picker is used.
b.shutdownRemainingLocked(sd)
sd.effectiveState = newState.ConnectivityState
- // READY SubConn interspliced in between CONNECTING and IDLE, need to
- // account for that.
- if oldState == connectivity.Connecting {
- // A known issue (https://github.com/grpc/grpc-go/issues/7862)
- // causes a race that prevents the READY state change notification.
- // This works around it.
- connectionAttemptsSucceededMetric.Record(b.metricsRecorder, 1, b.target)
- }
- disconnectionsMetric.Record(b.metricsRecorder, 1, b.target)
b.addressList.reset()
b.updateBalancerState(balancer.State{
ConnectivityState: connectivity.Idle,
diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go
index 296123e..6c249fd 100644
--- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go
+++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go
@@ -679,7 +679,7 @@ func (x *Message) GetData() []byte {
// A list of metadata pairs, used in the payload of client header,
// server header, and server trailer.
// Implementations may omit some entries to honor the header limits
-// of GRPC_BINARY_LOG_CONFIG.
+// of GRPC_BINARY_LOG_FILTER.
//
// Header keys added by gRPC are omitted. To be more specific,
// implementations will not log the following entries, and this is
@@ -689,7 +689,9 @@ func (x *Message) GetData() []byte {
// or keys like 'lb-token'
// - transport specific entries, including but not limited to:
// ':path', ':authority', 'content-encoding', 'user-agent', 'te', etc
-// - entries added for call credentials
+// - entries added for call credentials (on client side, excludes all
+// such headers; on server side, excludes only the "authorization"
+// header)
//
// Implementations must always log grpc-trace-bin if it is present.
// Practically speaking it will only be visible on server side because
diff --git a/vendor/google.golang.org/grpc/call.go b/vendor/google.golang.org/grpc/call.go
index 788c89c..2079bf4 100644
--- a/vendor/google.golang.org/grpc/call.go
+++ b/vendor/google.golang.org/grpc/call.go
@@ -20,6 +20,10 @@ package grpc
import (
"context"
+ "io"
+
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
)
// Invoke sends the RPC request on the wire and returns after response is
@@ -67,8 +71,27 @@ func invoke(ctx context.Context, method string, req, reply any, cc *ClientConn,
if err != nil {
return err
}
- if err := cs.SendMsg(req); err != nil {
+ // In case of nil or io.EOF error, call RecvMsg.
+ if err := cs.SendMsg(req); err != nil && err != io.EOF {
+ return err
+ }
+ // CloseSend is needed because in some scenarios (e.g., xDS), the same
+ // interceptors are used to process both unary and streaming RPCs. Calling
+ // CloseSend signals to those interceptors that no more messages are on the
+ // way.
+ if err := cs.CloseSend(); err != nil && err != io.EOF {
return err
}
- return cs.RecvMsg(reply)
+ if err := cs.RecvMsg(reply); err != nil {
+ return err
+ }
+ // Call RecvMsg again to get the trailers.
+ err = cs.RecvMsg(reply)
+ if err == io.EOF {
+ return nil
+ }
+ if err == nil {
+ return status.Error(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message")
+ }
+ return err
}
diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go
index c4bca52..f5ce071 100644
--- a/vendor/google.golang.org/grpc/clientconn.go
+++ b/vendor/google.golang.org/grpc/clientconn.go
@@ -24,12 +24,10 @@ import (
"fmt"
"math"
"net/url"
- "os"
"slices"
"strings"
"sync"
"sync/atomic"
- "syscall"
"time"
"google.golang.org/grpc/balancer"
@@ -555,6 +553,7 @@ func chainStreamClientInterceptors(cc *ClientConn) {
if cc.dopts.streamInt != nil {
interceptors = append([]StreamClientInterceptor{cc.dopts.streamInt}, interceptors...)
}
+ interceptors = append(interceptors, defaultStreamInterceptor)
var chainedInt StreamClientInterceptor
if len(interceptors) == 0 {
chainedInt = nil
@@ -1573,26 +1572,13 @@ func (ac *addrConn) createTransport(ctx context.Context, addr resolver.Address,
// to the provided transport.GoAwayInfo, as specified by gRFC A94:
// https://github.com/grpc/proposal/blob/master/A94-grpc-subchannel-disconnections-metrics.md
func disconnectErrorString(info transport.GoAwayInfo) string {
- err := info.Err
- var sysErr syscall.Errno
- switch {
- case info.Reason != transport.GoAwayInvalid:
+ if info.Reason != transport.GoAwayInvalid {
return fmt.Sprintf("GOAWAY %s", info.GoAwayCode.String())
- case err == nil:
- return "unknown"
- case errors.Is(err, context.Canceled):
- return "subchannel shutdown"
- case errors.Is(err, syscall.ECONNRESET):
- return "connection reset"
- case errors.Is(err, syscall.ETIMEDOUT), errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded):
- return "connection timed out"
- case errors.Is(err, syscall.ECONNABORTED):
- return "connection aborted"
- case errors.As(err, &sysErr):
- return "socket error"
- default:
+ }
+ if info.Err == nil {
return "unknown"
}
+ return disconnectErrorLabel(info.Err)
}
// startHealthCheck starts the health checking stream (RPC) to watch the health
diff --git a/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go
new file mode 100644
index 0000000..f0fcd88
--- /dev/null
+++ b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_noplan9.go
@@ -0,0 +1,48 @@
+//go:build !plan9
+
+/*
+ *
+ * Copyright 2026 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package grpc
+
+import (
+ "context"
+ "errors"
+ "os"
+ "syscall"
+)
+
+// disconnectErrorLabel returns the grpc.disconnect_error metric label for a
+// transport error, as specified by gRFC A94.
+func disconnectErrorLabel(err error) string {
+ var sysErr syscall.Errno
+ switch {
+ case errors.Is(err, context.Canceled):
+ return "subchannel shutdown"
+ case errors.Is(err, syscall.ECONNRESET):
+ return "connection reset"
+ case errors.Is(err, syscall.ETIMEDOUT), errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded):
+ return "connection timed out"
+ case errors.Is(err, syscall.ECONNABORTED):
+ return "connection aborted"
+ case errors.As(err, &sysErr):
+ return "socket error"
+ default:
+ return "unknown"
+ }
+}
diff --git a/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go
new file mode 100644
index 0000000..930b126
--- /dev/null
+++ b/vendor/google.golang.org/grpc/clientconn_disconnect_reason_plan9.go
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2026 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package grpc
+
+import (
+ "context"
+ "errors"
+ "os"
+)
+
+// disconnectErrorLabel returns the grpc.disconnect_error metric label for a
+// transport error, as specified by gRFC A94. syscall.Errno does not exist on
+// plan9, so only the portable classifications are available.
+func disconnectErrorLabel(err error) string {
+ switch {
+ case errors.Is(err, context.Canceled):
+ return "subchannel shutdown"
+ case errors.Is(err, context.DeadlineExceeded), errors.Is(err, os.ErrDeadlineExceeded):
+ return "connection timed out"
+ default:
+ return "unknown"
+ }
+}
diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go
index 4ec5f9c..3af08e1 100644
--- a/vendor/google.golang.org/grpc/dialoptions.go
+++ b/vendor/google.golang.org/grpc/dialoptions.go
@@ -173,10 +173,8 @@ func newJoinDialOption(opts ...DialOption) DialOption {
// If this option is set to true every connection will release the buffer after
// flushing the data on the wire.
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a
-// later release.
+// Deprecated: shared write buffer is enabled by default. WithSharedWriteBuffer
+// will be removed in a future release.
func WithSharedWriteBuffer(val bool) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.SharedWriteBuffer = val
@@ -229,6 +227,14 @@ func WithInitialConnWindowSize(s int32) DialOption {
// WithStaticStreamWindowSize returns a DialOption which sets the initial
// stream window size to the value provided and disables dynamic flow control.
+//
+// Note that this also disables dynamic flow control for the connection,
+// falling back to a default static connection-level window of 64KB. To
+// use a larger connection-level window, you must also use the
+// [WithStaticConnWindowSize] DialOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func WithStaticStreamWindowSize(s int32) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.InitialWindowSize = s
@@ -239,6 +245,14 @@ func WithStaticStreamWindowSize(s int32) DialOption {
// WithStaticConnWindowSize returns a DialOption which sets the initial
// connection window size to the value provided and disables dynamic flow
// control.
+//
+// Note that this also disables dynamic flow control for individual streams,
+// falling back to a default static connection-level window of 64KB. To
+// explicitly configure the stream-level window size, you must also use the
+// [WithStaticStreamWindowSize] DialOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func WithStaticConnWindowSize(s int32) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.InitialConnWindowSize = s
diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go
index 296f38c..bfa8b26 100644
--- a/vendor/google.golang.org/grpc/encoding/encoding.go
+++ b/vendor/google.golang.org/grpc/encoding/encoding.go
@@ -66,6 +66,9 @@ type Compressor interface {
// Decompress reads data from r, decompresses it, and provides the
// uncompressed data via the returned io.Reader. If an error occurs while
// initializing the decompressor, that error is returned instead.
+ //
+ // The returned io.Reader may optionally implement io.ReadCloser, and if it
+ // does, gRPC will call Close() exactly once.
Decompress(r io.Reader) (io.Reader, error)
// Name is the name of the compression codec and is used to set the content
// coding header. The result must be static; the result cannot change
diff --git a/vendor/google.golang.org/grpc/internal/balancer/weight/weight.go b/vendor/google.golang.org/grpc/experimental/balancer/weight/weight.go
similarity index 71%
rename from vendor/google.golang.org/grpc/internal/balancer/weight/weight.go
rename to vendor/google.golang.org/grpc/experimental/balancer/weight/weight.go
index 11beb07..beab9e0 100644
--- a/vendor/google.golang.org/grpc/internal/balancer/weight/weight.go
+++ b/vendor/google.golang.org/grpc/experimental/balancer/weight/weight.go
@@ -16,23 +16,23 @@
*
*/
-// Package weight contains utilities to manage endpoint weights. Weights are
-// used by LB policies such as ringhash to distribute load across multiple
-// endpoints.
+// Package weight contains utilities to manage endpoint weights.
+// Weights may be used by LB policies to distribute load across
+// multiple endpoints.
+//
+// # Experimental
+//
+// Notice: All APIs in this package are EXPERIMENTAL and may be changed
+// or removed in a later release.
package weight
-import (
- "fmt"
-
- "google.golang.org/grpc/resolver"
-)
+import "google.golang.org/grpc/resolver"
// attributeKey is the type used as the key to store EndpointInfo in the
// Attributes field of resolver.Endpoint.
type attributeKey struct{}
-// EndpointInfo will be stored in the Attributes field of Endpoints in order to
-// use the ringhash balancer.
+// EndpointInfo will be stored in the Attributes field of Endpoints.
type EndpointInfo struct {
Weight uint32
}
@@ -43,22 +43,16 @@ func (a EndpointInfo) Equal(o any) bool {
return ok && oa.Weight == a.Weight
}
-// Set returns a copy of endpoint in which the Attributes field is updated with
-// EndpointInfo.
+// Set returns a copy of endpoint in which the Attributes field is
+// updated with EndpointInfo.
func Set(endpoint resolver.Endpoint, epInfo EndpointInfo) resolver.Endpoint {
endpoint.Attributes = endpoint.Attributes.WithValue(attributeKey{}, epInfo)
return endpoint
}
-// String returns a human-readable representation of EndpointInfo.
-// This method is intended for logging, testing, and debugging purposes only.
-// Do not rely on the output format, as it is not guaranteed to remain stable.
-func (a EndpointInfo) String() string {
- return fmt.Sprintf("Weight: %d", a.Weight)
-}
-
-// FromEndpoint returns the EndpointInfo stored in the Attributes field of an
-// endpoint. It returns an empty EndpointInfo if attribute is not found.
+// FromEndpoint returns the EndpointInfo stored in the Attributes
+// field of an endpoint. It returns an empty EndpointInfo if attribute
+// is not found.
func FromEndpoint(endpoint resolver.Endpoint) EndpointInfo {
v := endpoint.Attributes.Value(attributeKey{})
ei, _ := v.(EndpointInfo)
diff --git a/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go b/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go
index 9e10fdd..537ba05 100644
--- a/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go
+++ b/vendor/google.golang.org/grpc/health/grpc_health_v1/health_grpc.pb.go
@@ -17,7 +17,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
-// - protoc-gen-go-grpc v1.6.1
+// - protoc-gen-go-grpc v1.6.2
// - protoc v5.27.1
// source: grpc/health/v1/health.proto
diff --git a/vendor/google.golang.org/grpc/internal/buffer/unbounded.go b/vendor/google.golang.org/grpc/internal/buffer/unbounded.go
index 467392b..d1f4b63 100644
--- a/vendor/google.golang.org/grpc/internal/buffer/unbounded.go
+++ b/vendor/google.golang.org/grpc/internal/buffer/unbounded.go
@@ -27,32 +27,29 @@ import (
// extra goroutines. This is typically used for passing updates from one entity
// to another within gRPC.
//
+// To avoid extra memory allocations and type assertions, using any on
+// performance-critical code paths is discouraged. Use concrete types wherever
+// possible when instantiating Unbounded.
+//
// All methods on this type are thread-safe and don't block on anything except
// the underlying mutex used for synchronization.
-//
-// Unbounded supports values of any type to be stored in it by using a channel
-// of `any`. This means that a call to Put() incurs an extra memory allocation,
-// and also that users need a type assertion while reading. For performance
-// critical code paths, using Unbounded is strongly discouraged and defining a
-// new type specific implementation of this buffer is preferred. See
-// internal/transport/transport.go for an example of this.
-type Unbounded struct {
- c chan any
+type Unbounded[T any] struct {
+ c chan T
closed bool
closing bool
mu sync.Mutex
- backlog []any
+ backlog []T
}
// NewUnbounded returns a new instance of Unbounded.
-func NewUnbounded() *Unbounded {
- return &Unbounded{c: make(chan any, 1)}
+func NewUnbounded[T any]() *Unbounded[T] {
+ return &Unbounded[T]{c: make(chan T, 1)}
}
var errBufferClosed = errors.New("Put called on closed buffer.Unbounded")
// Put adds t to the unbounded buffer.
-func (b *Unbounded) Put(t any) error {
+func (b *Unbounded[T]) Put(t T) error {
b.mu.Lock()
defer b.mu.Unlock()
if b.closing {
@@ -72,13 +69,14 @@ func (b *Unbounded) Put(t any) error {
// Load sends the earliest buffered data, if any, onto the read channel returned
// by Get(). Users are expected to call this every time they successfully read a
// value from the read channel.
-func (b *Unbounded) Load() {
+func (b *Unbounded[T]) Load() {
b.mu.Lock()
defer b.mu.Unlock()
if len(b.backlog) > 0 {
select {
case b.c <- b.backlog[0]:
- b.backlog[0] = nil
+ var zero T
+ b.backlog[0] = zero
b.backlog = b.backlog[1:]
default:
}
@@ -96,14 +94,14 @@ func (b *Unbounded) Load() {
//
// If the unbounded buffer is closed, the read channel returned by this method
// is closed after all data is drained.
-func (b *Unbounded) Get() <-chan any {
+func (b *Unbounded[T]) Get() <-chan T {
return b.c
}
// Close closes the unbounded buffer. No subsequent data may be Put(), and the
// channel returned from Get() will be closed after all the data is read and
// Load() is called for the final time.
-func (b *Unbounded) Close() {
+func (b *Unbounded[T]) Close() {
b.mu.Lock()
defer b.mu.Unlock()
if b.closing {
diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
index 8ca87a5..dc6fc0c 100644
--- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
+++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go
@@ -59,6 +59,15 @@ var (
// unconditionally.
XDSEndpointHashKeyBackwardCompat = boolFromEnv("GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT", false)
+ // LabelServerGoroutines controls setting [runtime/pprof.Labels] on the
+ // goroutines spawned by [grpc.Server] type.
+ // For now, this is limited to the goroutines spawned to handle incoming
+ // requests on the server.
+ // Set "GRPC_GO_SERVER_GOROUTINE_LABELS" to "grpc.method=true" to
+ // enable this grpc.method label, or "all" to enable all valid labels.
+ // This variable is a bit-field.
+ LabelServerGoroutines = goroutineLabelsFromEnv("GRPC_GO_SERVER_GOROUTINE_LABELS", 0)
+
// RingHashSetRequestHashKey is set if the ring hash balancer can get the
// request hash header by setting the "requestHashHeader" field, according
// to gRFC A76. It can be disabled by setting the environment variable
@@ -78,12 +87,12 @@ var (
EnableDefaultPortForProxyTarget = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_DEFAULT_PORT_FOR_PROXY_TARGET", true)
// CaseSensitiveBalancerRegistries is set if the balancer registry should be
- // case-sensitive. This is disabled by default, but can be enabled by setting
+ // case-sensitive. This is enabled by default, but can be disabled by setting
// the env variable "GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES"
- // to "true".
+ // to "false".
//
- // TODO: After 2 releases, we will enable the env var by default.
- CaseSensitiveBalancerRegistries = boolFromEnv("GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES", false)
+ // This env varible will be removed in release v1.82.0.
+ CaseSensitiveBalancerRegistries = boolFromEnv("GRPC_GO_EXPERIMENTAL_CASE_SENSITIVE_BALANCER_REGISTRIES", true)
// XDSAuthorityRewrite indicates whether xDS authority rewriting is enabled.
// This feature is defined in gRFC A81 and is enabled by setting the
@@ -104,22 +113,6 @@ var (
// to "false".
XDSRecoverPanicInResourceParsing = boolFromEnv("GRPC_GO_EXPERIMENTAL_XDS_RESOURCE_PANIC_RECOVERY", true)
- // DisableStrictPathChecking indicates whether strict path checking is
- // disabled. This feature can be disabled by setting the environment
- // variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to "true".
- //
- // When strict path checking is enabled, gRPC will reject requests with
- // paths that do not conform to the gRPC over HTTP/2 specification found at
- // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md.
- //
- // When disabled, gRPC will allow paths that do not contain a leading slash.
- // Enabling strict path checking is recommended for security reasons, as it
- // prevents potential path traversal vulnerabilities.
- //
- // A future release will remove this environment variable, enabling strict
- // path checking behavior unconditionally.
- DisableStrictPathChecking = boolFromEnv("GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING", false)
-
// EnablePriorityLBChildPolicyCache controls whether the priority balancer
// should cache child balancers that are removed from the LB policy config,
// for a period of 15 minutes. This is disabled by default, but can be
@@ -127,6 +120,18 @@ var (
// GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE to true.
EnablePriorityLBChildPolicyCache = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_PRIORITY_LB_CHILD_POLICY_CACHE", false)
+ // Enable8KBDefaultHeaderListSize indicates that default maximum header list
+ // size is restricted to 8KB. This is disabled by default, but can be enabled
+ // by setting the environment variable
+ // "GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE" to "true".
+ // When disabled, the default maximum header list size of 16MB is used.
+ //
+ // When enabled, RPCs with a total size of headers exceeding 8KB will fail
+ // unless explicitly configured otherwise by the user.
+ //
+ // TODO: In release v1.82.0, env var will be enabled by default.
+ Enable8KBDefaultHeaderListSize = boolFromEnv("GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE", false)
+
// EnableHTTPFramerReadBufferPooling enables the use of the
// readyreader.Reader interface to perform non-memory-pinning reads,
// provided the underlying net.Conn supports it. This reduces memory usage
@@ -136,6 +141,34 @@ var (
// feature if unforeseen issues arise, and it will be removed in a future
// release.
EnableHTTPFramerReadBufferPooling = boolFromEnv("GRPC_GO_EXPERIMENTAL_HTTP_FRAMER_READ_BUFFER_POOLING", true)
+
+ // ControlBufferThrottleLimit is the maximum number of control frames that can
+ // be queued in the control buffer before throttling is applied. The value
+ // must be between 1 and 10,000, and is set to 100 by default.
+ //
+ // This environment variable serves as an escape hatch to increase the
+ // throttling limit if unforeseen issues arise, and it will be removed in a
+ // future release.
+ //
+ // TODO: Remove this env var once v1.83.0 is released.
+ ControlBufferThrottleLimit = uint64FromEnv("GRPC_GO_EXPERIMENTAL_CONTROL_BUFFER_THROTTLE_LIMIT", 100, 1, 10000)
+
+ // ALTSMaxFrameSize is the maximum frame size for ALTS in bytes.
+ // This can be overridden by setting the environment variable
+ // "GRPC_GO_EXPERIMENTAL_ALTS_MAX_FRAME_SIZE" (min: 4096, max: 512*1024, capped at
+ // 512KiB to match altsWriteBufferMaxSize in
+ // credentials/alts/internal/conn/record.go).
+ ALTSMaxFrameSize = uint64FromEnv("GRPC_GO_EXPERIMENTAL_ALTS_MAX_FRAME_SIZE", 4096, 4096, 512*1024)
+
+ // EnableReceiveBufferCompaction enables the compaction of data buffers
+ // to reduce the number of buffers in the receive buffer.
+ //
+ // This environment variable serves as an escape hatch to disable the
+ // feature if unforeseen issues arise, and it will be removed in a future
+ // release.
+ //
+ // TODO: Remove this env var once v1.85.0 is released.
+ EnableReceiveBufferCompaction = boolFromEnv("GRPC_GO_EXPERIMENTAL_ENABLE_RECEIVE_BUFFER_COMPACTION", true)
)
func boolFromEnv(envVar string, def bool) bool {
@@ -160,3 +193,52 @@ func uint64FromEnv(envVar string, def, min, max uint64) uint64 {
}
return v
}
+
+// GoroutineLabels is a bitfield indicating which goroutine labels are enabled.
+type GoroutineLabels uint16
+
+func goroutineLabelsFromEnv(envVar string, def GoroutineLabels) GoroutineLabels {
+ val := def
+ v := os.Getenv(envVar)
+ if strings.EqualFold(v, "all") {
+ return AllGoroutineLabels
+ } else if strings.EqualFold(v, "none") {
+ return 0
+ }
+ for s := range strings.SplitSeq(v, ",") {
+ s = strings.TrimSpace(s)
+ if len(s) == 0 {
+ continue
+ }
+ pre, post, ok := strings.Cut(s, "=")
+ if !ok {
+ // no equals sign
+ continue
+ }
+ post = strings.TrimSpace(post)
+ pre = strings.TrimSpace(pre)
+ bitDesignator := GoroutineLabels(0)
+ switch {
+ case strings.EqualFold(pre, "grpc.method"):
+ bitDesignator = GoroutineLabelServerMethod
+ default:
+ continue
+ }
+ if strings.EqualFold(post, "true") {
+ val |= bitDesignator
+ } else if strings.EqualFold(post, "false") {
+ val &^= bitDesignator
+ }
+ }
+ return val
+}
+
+const (
+ // GoroutineLabelServerMethod sets the grpc.method label on new
+ // server-side gRPC streams.
+ GoroutineLabelServerMethod GoroutineLabels = 1 << iota
+)
+
+// AllGoroutineLabels is an or'd together bitfield of all valid GoroutineLabels
+// constant values (above).
+const AllGoroutineLabels = GoroutineLabelServerMethod
diff --git a/vendor/google.golang.org/grpc/internal/envconfig/xds.go b/vendor/google.golang.org/grpc/internal/envconfig/xds.go
index 333d8a0..5ec39bd 100644
--- a/vendor/google.golang.org/grpc/internal/envconfig/xds.go
+++ b/vendor/google.golang.org/grpc/internal/envconfig/xds.go
@@ -69,9 +69,8 @@ var (
// https://github.com/grpc/proposal/blob/master/A87-mtls-spiffe-support.md
XDSSPIFFEEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_MTLS_SPIFFE", false)
- // XDSHTTPConnectEnabled is true if gRPC should parse custom Metadata
- // configuring use of an HTTP CONNECT proxy via xDS from cluster resources.
- // For more details, see:
+ // XDSHTTPConnectEnabled controls support for dynamic HTTP CONNECT proxying
+ // configured via the xDS control plane. For more details, see:
// https://github.com/grpc/proposal/blob/master/A86-xds-http-connect.md
XDSHTTPConnectEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT", false)
@@ -88,5 +87,20 @@ var (
// XDSORCAToLRSPropEnabled controls whether ORCA metrics are explicitly
// filtered and prefix-propagated to the LRS server. For more details, see:
// https://github.com/grpc/proposal/blob/master/A85-lrs-custom-metrics-changes.md
- XDSORCAToLRSPropEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION", false)
+ XDSORCAToLRSPropEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_ORCA_LRS_PROPAGATION", true)
+
+ // XDSClientExtProcEnabled indicates whether ExtProc filter is enabled on
+ // the client side. For more details, see:
+ // https://github.com/grpc/proposal/blob/master/A93-xds-ext-proc.md
+ XDSClientExtProcEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_EXT_PROC_ON_CLIENT", false)
+
+ // GCPAuthenticationFilterEnabled enables the xDS GCP Authentication
+ // filter. For more details, see:
+ // https://github.com/grpc/proposal/blob/master/A83-xds-gcp-authn-filter.md
+ GCPAuthenticationFilterEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_GCP_AUTHENTICATION_FILTER", false)
+
+ // XDSClientExtAuthzEnabled indicates whether the external authorization
+ // filter is enabled on the client side. For more details, see:
+ // https://github.com/grpc/proposal/blob/master/A92-xds-ext-authz.md
+ XDSClientExtAuthzEnabled = boolFromEnv("GRPC_EXPERIMENTAL_XDS_EXT_AUTHZ_ON_CLIENT", false)
)
diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go
index 9b6d8a1..caa9dd6 100644
--- a/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go
+++ b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go
@@ -20,10 +20,15 @@ package grpcsync
import (
"context"
+ "errors"
"google.golang.org/grpc/internal/buffer"
)
+// ErrSerializerClosed is returned by ScheduleAndWait if the CallbackSerializer
+// was closed before the callback could be scheduled.
+var ErrSerializerClosed = errors.New("callback serializer is closed")
+
// CallbackSerializer provides a mechanism to schedule callbacks in a
// synchronized manner. It provides a FIFO guarantee on the order of execution
// of scheduled callbacks. New callbacks can be scheduled by invoking the
@@ -36,7 +41,7 @@ type CallbackSerializer struct {
// its resources.
done chan struct{}
- callbacks *buffer.Unbounded
+ callbacks *buffer.Unbounded[func(context.Context)]
}
// NewCallbackSerializer returns a new CallbackSerializer instance. The provided
@@ -47,7 +52,7 @@ type CallbackSerializer struct {
func NewCallbackSerializer(ctx context.Context) *CallbackSerializer {
cs := &CallbackSerializer{
done: make(chan struct{}),
- callbacks: buffer.NewUnbounded(),
+ callbacks: buffer.NewUnbounded[func(context.Context)](),
}
go cs.run(ctx)
return cs
@@ -77,6 +82,27 @@ func (cs *CallbackSerializer) ScheduleOr(f func(ctx context.Context), onFailure
}
}
+// ScheduleAndWait schedules the provided callback function f to be executed in
+// the order it was added and blocks until f has run. If the context passed to
+// NewCallbackSerializer was canceled before this method is called, f is not run
+// and ScheduleAndWait returns ErrSerializerClosed.
+//
+// Callbacks are expected to honor the context when performing any blocking
+// operations, and should return early when the context is canceled.
+func (cs *CallbackSerializer) ScheduleAndWait(f func(ctx context.Context)) error {
+ done := make(chan struct{})
+ var err error
+ cs.ScheduleOr(func(ctx context.Context) {
+ f(ctx)
+ close(done)
+ }, func() {
+ err = ErrSerializerClosed
+ close(done)
+ })
+ <-done
+ return err
+}
+
func (cs *CallbackSerializer) run(ctx context.Context) {
defer close(cs.done)
@@ -87,7 +113,7 @@ func (cs *CallbackSerializer) run(ctx context.Context) {
// Run all callbacks.
for cb := range cs.callbacks.Get() {
cs.callbacks.Load()
- cb.(func(context.Context))(ctx)
+ cb(ctx)
}
}
diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/refcounted.go b/vendor/google.golang.org/grpc/internal/grpcsync/refcounted.go
new file mode 100644
index 0000000..bca9b83
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/grpcsync/refcounted.go
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2026 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package grpcsync
+
+import (
+ "sync/atomic"
+
+ "google.golang.org/grpc/grpclog"
+)
+
+var logger = grpclog.Component("grpcsync")
+
+// RefCounted is a reference counted wrapper of type T. It tracks the number of
+// active references and runs a cleanup when the last reference is released.
+type RefCounted[T any] struct {
+ val T
+ refCount atomic.Int32
+ onZero func()
+}
+
+// NewRefCounted creates a new RefCounted instance wrapping the given value with
+// initial refcount of one.
+//
+// The value should typically be a pointer, interface, or handle rather than a
+// plain value type (such as a struct or primitive value).
+//
+// The provided onZero callback must not be nil, and is executed exactly once
+// when the reference count drops to zero. Panics if onZero is nil.
+//
+// WARNING: onZero runs synchronously inside Decrement; it must not acquire
+// locks held by Decrement callers.
+func NewRefCounted[T any](val T, onZero func()) *RefCounted[T] {
+ if onZero == nil {
+ panic("grpcsync: onZero callback cannot be nil")
+ }
+ rc := &RefCounted[T]{
+ val: val,
+ onZero: onZero,
+ }
+ rc.refCount.Store(1)
+ return rc
+}
+
+// Value returns the encapsulated resource.
+func (rc *RefCounted[T]) Value() T {
+ return rc.val
+}
+
+// TryIncrement attempts to increment the reference count, returning true if
+// successful. It returns false if the count has already reached 0, indicating
+// the resource has been cleaned up and cannot be resurrected.
+//
+// WARNING: Avoid calling TryIncrement on hot paths when an active reference is
+// already guaranteed by the caller; use Increment instead to bypass the
+// CompareAndSwap loop overhead. TryIncrement should be reserved for speculative
+// lookups (such as fetching from a cache or map) where the resource might be
+// dead.
+func (rc *RefCounted[T]) TryIncrement() bool {
+ // Utilize a CompareAndSwap loop to prevent race conditions where a concurrent
+ // decrement could drop the count to zero between the read and the increment
+ // operation, which would otherwise inadvertently resurrect a closed resource.
+ for {
+ count := rc.refCount.Load()
+ if count <= 0 {
+ return false // Already dead or dying
+ }
+ if rc.refCount.CompareAndSwap(count, count+1) {
+ return true
+ }
+ }
+}
+
+// Increment increments the reference count.
+//
+// WARNING: Call Increment only when there is a guarantee that an active
+// reference is already present, ensuring the resource is not dead. If there is
+// a possibility that the resource is dead or its reference count might have
+// reached zero, call TryIncrement instead.
+func (rc *RefCounted[T]) Increment() {
+ if rc.refCount.Add(1) <= 1 {
+ logger.Errorf("Resource already closed or dead")
+ }
+}
+
+// Decrement decrements the reference count. If it drops to zero, the onZero
+// callback is executed synchronously before this method returns.
+func (rc *RefCounted[T]) Decrement() {
+ if v := rc.refCount.Add(-1); v < 0 {
+ logger.Errorf("Refcount cannot be negative")
+ } else if v == 0 {
+ rc.onZero()
+ }
+}
diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go b/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go
index b25b0ba..1cc43fc 100644
--- a/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go
+++ b/vendor/google.golang.org/grpc/internal/grpcutil/encode_duration.go
@@ -39,7 +39,6 @@ func div(d, r time.Duration) int64 {
//
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests
func EncodeDuration(t time.Duration) string {
- // TODO: This is simplistic and not bandwidth efficient. Improve it.
if t <= 0 {
return "0n"
}
diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go
index 4b3d563..2b7fa6b 100644
--- a/vendor/google.golang.org/grpc/internal/internal.go
+++ b/vendor/google.golang.org/grpc/internal/internal.go
@@ -245,6 +245,10 @@ var (
AsyncReporterCleanupDelegate = func(cleanup func()) func() {
return cleanup
}
+
+ // XDSFilterWrapperOption returns a ServerOption that sets the internal
+ // stream wrapper used for server-side xDS HTTP filters.
+ XDSFilterWrapperOption any // func(func(grpc.ServerStream) (grpc.ServerStream, error)) grpc.ServerOption
)
// HealthChecker defines the signature of the client-side LB channel health
diff --git a/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go
index 2d83b2e..00aeca4 100644
--- a/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go
+++ b/vendor/google.golang.org/grpc/internal/mem/buffer_pool.go
@@ -26,12 +26,26 @@ import (
"slices"
"sort"
"sync"
+
+ "google.golang.org/grpc/internal"
)
const (
goPageSize = 4 * 1024 // 4KiB. N.B. this must be a power of 2.
)
+var (
+ // BufferPoolingThreshold is the minimum size of a buffer that can be pooled.
+ // This is used to determine whether to pool buffers or allocate them directly.
+ BufferPoolingThreshold = 1 << 10
+)
+
+func init() {
+ internal.SetBufferPoolingThresholdForTesting = func(threshold int) {
+ BufferPoolingThreshold = threshold
+ }
+}
+
var uintSize = bits.UintSize // use a variable for mocking during tests.
// bufferPool is a copy of the public bufferPool interface used to avoid
diff --git a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
index 3db62cc..ead6dda 100644
--- a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
+++ b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go
@@ -24,7 +24,6 @@ import (
"sync"
"google.golang.org/grpc/internal/serviceconfig"
- "google.golang.org/grpc/metadata"
"google.golang.org/grpc/resolver"
)
@@ -43,6 +42,10 @@ type RPCInfo struct {
// efficiency reasons. SelectConfig should not be blocking.
Context context.Context
Method string // i.e. "/Service/Method"
+ // Authority is the target authority (host) name of the RPC. This is required
+ // for HTTP filters (such as external processing) to populate request
+ // attributes.
+ Authority string
}
// RPCConfig describes the configuration to use for each RPC.
@@ -52,83 +55,7 @@ type RPCConfig struct {
Context context.Context
MethodConfig serviceconfig.MethodConfig // configuration to use for this RPC
OnCommitted func() // Called when the RPC has been committed (retries no longer possible)
- Interceptor ClientInterceptor
-}
-
-// ClientStream is the same as grpc.ClientStream, but defined here for circular
-// dependency reasons.
-type ClientStream interface {
- // Header returns the header metadata received from the server if there
- // is any. It blocks if the metadata is not ready to read.
- Header() (metadata.MD, error)
- // Trailer returns the trailer metadata from the server, if there is any.
- // It must only be called after stream.CloseAndRecv has returned, or
- // stream.Recv has returned a non-nil error (including io.EOF).
- Trailer() metadata.MD
- // CloseSend closes the send direction of the stream. It closes the stream
- // when non-nil error is met. It is also not safe to call CloseSend
- // concurrently with SendMsg.
- CloseSend() error
- // Context returns the context for this stream.
- //
- // It should not be called until after Header or RecvMsg has returned. Once
- // called, subsequent client-side retries are disabled.
- Context() context.Context
- // SendMsg is generally called by generated code. On error, SendMsg aborts
- // the stream. If the error was generated by the client, the status is
- // returned directly; otherwise, io.EOF is returned and the status of
- // the stream may be discovered using RecvMsg.
- //
- // SendMsg blocks until:
- // - There is sufficient flow control to schedule m with the transport, or
- // - The stream is done, or
- // - The stream breaks.
- //
- // SendMsg does not wait until the message is received by the server. An
- // untimely stream closure may result in lost messages. To ensure delivery,
- // users should ensure the RPC completed successfully using RecvMsg.
- //
- // It is safe to have a goroutine calling SendMsg and another goroutine
- // calling RecvMsg on the same stream at the same time, but it is not safe
- // to call SendMsg on the same stream in different goroutines. It is also
- // not safe to call CloseSend concurrently with SendMsg.
- SendMsg(m any) error
- // RecvMsg blocks until it receives a message into m or the stream is
- // done. It returns io.EOF when the stream completes successfully. On
- // any other error, the stream is aborted and the error contains the RPC
- // status.
- //
- // It is safe to have a goroutine calling SendMsg and another goroutine
- // calling RecvMsg on the same stream at the same time, but it is not
- // safe to call RecvMsg on the same stream in different goroutines.
- RecvMsg(m any) error
-}
-
-// ClientInterceptor is an interceptor for gRPC client streams.
-type ClientInterceptor interface {
- // NewStream produces a ClientStream for an RPC which may optionally use
- // the provided function to produce a stream for delegation. Note:
- // RPCInfo.Context should not be used (will be nil).
- //
- // done is invoked when the RPC is finished using its connection, or could
- // not be assigned a connection. RPC operations may still occur on
- // ClientStream after done is called, since the interceptor is invoked by
- // application-layer operations. done must never be nil when called.
- NewStream(ctx context.Context, ri RPCInfo, done func(), newStream func(ctx context.Context, done func()) (ClientStream, error)) (ClientStream, error)
- // Close closes the interceptor. Once called, no new calls to NewStream are
- // accepted. Ongoing calls to NewStream are allowed to complete.
- Close()
-}
-
-// ServerInterceptor is an interceptor for incoming RPC's on gRPC server side.
-type ServerInterceptor interface {
- // AllowRPC checks if an incoming RPC is allowed to proceed based on
- // information about connection RPC was received on, and HTTP Headers. This
- // information will be piped into context.
- AllowRPC(ctx context.Context) error // TODO: Make this a real interceptor for filters such as rate limiting.
- // Close closes the interceptor. Once called, no new calls to NewStream are
- // accepted. Ongoing calls to NewStream are allowed to complete.
- Close()
+ Interceptor any
}
type csKeyType string
diff --git a/vendor/google.golang.org/grpc/internal/stats/labels.go b/vendor/google.golang.org/grpc/internal/stats/labels.go
index fd33af5..5ea898c 100644
--- a/vendor/google.golang.org/grpc/internal/stats/labels.go
+++ b/vendor/google.golang.org/grpc/internal/stats/labels.go
@@ -19,24 +19,56 @@
// Package stats provides internal stats related functionality.
package stats
-import "context"
+import (
+ "context"
+ "maps"
+)
-// Labels are the labels for metrics.
-type Labels struct {
- // TelemetryLabels are the telemetry labels to record.
- TelemetryLabels map[string]string
+// LabelCallback is a function that is executed when telemetry
+// label keys are updated.
+type LabelCallback func(map[string]string)
+type telemetryLabelCallbackKey struct{}
+
+// UpdateLabels executes registered telemetry callbacks with the update labels. Labels
+// are copied before being processed by any callbacks to ensure mutations are not
+// shared among derived contexts.
+//
+// It is the responsibility of the registrant to handle conflicts or label resets.
+func UpdateLabels(ctx context.Context, update map[string]string) {
+ executeTelemetryLabelCallbacks(ctx, update)
}
-type labelsKey struct{}
+// RegisterTelemetryLabelCallback registers a callback function that is executed whenever
+// telemetry labels are updated.
+func RegisterTelemetryLabelCallback(ctx context.Context, callback LabelCallback) context.Context {
+ if callback == nil {
+ return ctx
+ }
+
+ callbacks, ok := ctx.Value(telemetryLabelCallbackKey{}).([]LabelCallback)
+ if !ok {
+ return context.WithValue(ctx, telemetryLabelCallbackKey{}, []LabelCallback{callback})
+ }
+ return context.WithValue(ctx, telemetryLabelCallbackKey{}, append(append([]LabelCallback(nil), callbacks...), callback))
-// GetLabels returns the Labels stored in the context, or nil if there is one.
-func GetLabels(ctx context.Context) *Labels {
- labels, _ := ctx.Value(labelsKey{}).(*Labels)
- return labels
}
-// SetLabels sets the Labels in the context.
-func SetLabels(ctx context.Context, labels *Labels) context.Context {
- // could also append
- return context.WithValue(ctx, labelsKey{}, labels)
+// executeTelemetryLabelCallback runs the registered callbacks in the order they were
+// registered on the context with the provided labels. If no callbacks are registered
+// it does nothing.
+//
+// To ensure callbacks do not mutate the state of the provided label map it is copied
+// before execution.
+func executeTelemetryLabelCallbacks(ctx context.Context, labels map[string]string) {
+ callbacks, ok := ctx.Value(telemetryLabelCallbackKey{}).([]LabelCallback)
+ if !ok {
+ return
+ }
+
+ labelsCopy := map[string]string{}
+ maps.Copy(labelsCopy, labels)
+ for _, callback := range callbacks {
+ callback(labelsCopy)
+ }
+
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/client_stream.go b/vendor/google.golang.org/grpc/internal/transport/client_stream.go
index cd8152e..046f0a5 100644
--- a/vendor/google.golang.org/grpc/internal/transport/client_stream.go
+++ b/vendor/google.golang.org/grpc/internal/transport/client_stream.go
@@ -19,6 +19,7 @@
package transport
import (
+ "fmt"
"sync/atomic"
"golang.org/x/net/http2"
@@ -28,13 +29,18 @@ import (
"google.golang.org/grpc/status"
)
+// nonGRPCDataMaxLen is the maximum length of nonGRPCDataBuf.
+//
+// NOTE: If changed this value, you MUST update the corresponding test in:
+// - /test/end2end_test.go:TestHTTPServerSendsNonGRPCHeaderSurfaceFurtherData
+const nonGRPCDataMaxLen = 1024
+
// ClientStream implements streaming functionality for a gRPC client.
type ClientStream struct {
Stream // Embed for common stream functionality.
- ct *http2Client
- done chan struct{} // closed at the end of stream to unblock writers.
- doneFunc func() // invoked at the end of stream.
+ ct *http2Client
+ done chan struct{} // closed at the end of stream to unblock writers.
headerChan chan struct{} // closed to indicate the end of header metadata.
header metadata.MD // the received header metadata
@@ -46,7 +52,11 @@ type ClientStream struct {
// headerValid indicates whether a valid header was received. Only
// meaningful after headerChan is closed (always call waitOnHeader() before
// reading its value).
- headerValid bool
+ headerValid bool
+
+ nonGRPCStatus *status.Status // the initial status from the non-gRPC response header, finalized with collected data before closing.
+ nonGRPCDataBuf []byte // stores the data of a non-gRPC response.
+
noHeaders bool // set if the client never received headers (set only after the stream is done).
headerChanClosed uint32 // set when headerChan is closed. Used to avoid closing headerChan multiple times.
bytesReceived atomic.Bool // indicates whether any bytes have been received on this stream
@@ -54,6 +64,29 @@ type ClientStream struct {
statsHandler stats.Handler // nil for internal streams (e.g., health check, ORCA) where telemetry is not supported.
}
+func (s *ClientStream) startNonGRPCDataCollection(st *status.Status) {
+ s.nonGRPCStatus = st
+ s.nonGRPCDataBuf = make([]byte, 0, nonGRPCDataMaxLen)
+}
+
+// finalizeNonGRPCStatus builds the terminal status by appending the collected
+// response body to the original non-gRPC status message.
+func (s *ClientStream) finalizeNonGRPCStatus() *status.Status {
+ msg := fmt.Sprintf("%s\ndata: %q", s.nonGRPCStatus.Message(), s.nonGRPCDataBuf)
+ return status.New(s.nonGRPCStatus.Code(), msg)
+}
+
+// handleNonGRPCData collects non-gRPC body from the given data frame.
+// It returns non-nil value when the stream should be closed with it.
+func (s *ClientStream) handleNonGRPCData(f *parsedDataFrame) *status.Status {
+ n := min(f.data.Len(), nonGRPCDataMaxLen-len(s.nonGRPCDataBuf))
+ s.nonGRPCDataBuf = append(s.nonGRPCDataBuf, f.data.ReadOnlyData()[0:n]...)
+ if len(s.nonGRPCDataBuf) >= nonGRPCDataMaxLen || f.StreamEnded() {
+ return s.finalizeNonGRPCStatus()
+ }
+ return nil
+}
+
// Read reads an n byte message from the input stream.
func (s *ClientStream) Read(n int) (mem.BufferSlice, error) {
b, err := s.Stream.read(n)
diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
index 7efa524..89c938f 100644
--- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
+++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go
@@ -29,6 +29,7 @@ import (
"golang.org/x/net/http2"
"golang.org/x/net/http2/hpack"
+ "google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/mem"
)
@@ -96,61 +97,70 @@ func (il *itemList) isEmpty() bool {
return il.head == nil
}
-// The following defines various control items which could flow through
-// the control buffer of transport. They represent different aspects of
-// control tasks, e.g., flow control, settings, streaming resetting, etc.
-
-// maxQueuedTransportResponseFrames is the most queued "transport response"
-// frames we will buffer before preventing new reads from occurring on the
-// transport. These are control frames sent in response to client requests,
-// such as RST_STREAM due to bad headers or settings acks.
-const maxQueuedTransportResponseFrames = 50
+// maxQueuedControlBufferItems is the maximum number of frames (other than
+// HEADERS and DATA) that we will buffer before preventing new reads from
+// occurring on the transport. These are control frames sent in response to
+// client requests, or frames that result in work being scheduled, such as
+// RST_STREAM due to bad headers or settings acks.
+var maxQueuedControlBufferItems = int(envconfig.ControlBufferThrottleLimit)
type cbItem interface {
- isTransportResponseFrame() bool
+ isThrottled() bool
}
+// throttledItem represents every item in the controlBuffer to which the overall
+// throttling limit applies, other than outgoing HEADERS and DATA frames.
+type throttledItem struct{}
+
+func (throttledItem) isThrottled() bool { return true }
+
+// The following defines various control items which could flow through
+// the control buffer of transport. They represent different aspects of
+// control tasks, e.g., flow control, settings, streaming resetting, etc.
+
// registerStream is used to register an incoming stream with loopy writer.
type registerStream struct {
+ throttledItem
streamID uint32
wq *writeQuota
}
-func (*registerStream) isTransportResponseFrame() bool { return false }
-
-// headerFrame is also used to register stream on the client-side.
-type headerFrame struct {
+type clientHeaders struct {
streamID uint32
hf []hpack.HeaderField
- endStream bool // Valid on server side.
- initStream func(uint32) error // Used only on the client side.
+ initStream func(uint32) error
onWrite func()
- wq *writeQuota // write quota for the stream created.
- cleanup *cleanupStream // Valid on the server side.
- onOrphaned func(error) // Valid on client-side
+ wq *writeQuota
+ onOrphaned func(error)
}
-func (h *headerFrame) isTransportResponseFrame() bool {
- return h.cleanup != nil && h.cleanup.rst // Results in a RST_STREAM
+func (*clientHeaders) isThrottled() bool { return false }
+
+type serverHeaders struct {
+ streamID uint32
+ hf []hpack.HeaderField
+ endStream bool
+ onWrite func()
+ cleanup *cleanupStream
}
+func (h *serverHeaders) isThrottled() bool { return false }
+
type cleanupStream struct {
+ throttledItem
streamID uint32
rst bool
rstCode http2.ErrCode
onWrite func()
}
-func (c *cleanupStream) isTransportResponseFrame() bool { return c.rst } // Results in a RST_STREAM
-
type earlyAbortStream struct {
+ throttledItem
streamID uint32
rst bool
hf []hpack.HeaderField // Pre-built header fields
}
-func (*earlyAbortStream) isTransportResponseFrame() bool { return false }
-
type dataFrame struct {
streamID uint32
endStream bool
@@ -162,70 +172,71 @@ type dataFrame struct {
onEachWrite func()
}
-func (*dataFrame) isTransportResponseFrame() bool { return false }
+func (*dataFrame) isThrottled() bool { return false }
type incomingWindowUpdate struct {
+ throttledItem
streamID uint32
increment uint32
}
-func (*incomingWindowUpdate) isTransportResponseFrame() bool { return false }
-
type outgoingWindowUpdate struct {
+ throttledItem
streamID uint32
increment uint32
}
-func (*outgoingWindowUpdate) isTransportResponseFrame() bool {
- return false // window updates are throttled by thresholds
-}
-
type incomingSettings struct {
+ throttledItem
ss []http2.Setting
}
-func (*incomingSettings) isTransportResponseFrame() bool { return true } // Results in a settings ACK
-
type outgoingSettings struct {
+ throttledItem
ss []http2.Setting
}
-func (*outgoingSettings) isTransportResponseFrame() bool { return false }
-
type incomingGoAway struct {
+ throttledItem
}
-func (*incomingGoAway) isTransportResponseFrame() bool { return false }
-
type goAway struct {
+ throttledItem
code http2.ErrCode
debugData []byte
headsUp bool
closeConn error // if set, loopyWriter will exit with this error
}
-func (*goAway) isTransportResponseFrame() bool { return false }
-
type ping struct {
+ throttledItem
ack bool
data [8]byte
}
-func (*ping) isTransportResponseFrame() bool { return true }
-
type outFlowControlSizeRequest struct {
+ throttledItem
resp chan uint32
}
-func (*outFlowControlSizeRequest) isTransportResponseFrame() bool { return false }
+// outStreamRequestForTesting is used by tests to retrieve a pointer to an outStream
+// safely inside the loopyWriter goroutine without racing on loopyWriter.estdStreams.
+// By holding the *outStream pointer while streams and transports close down, tests
+// can inspect settled accounting values (such as bytesOutStanding) after loopyWriter
+// has run to completion without any data races.
+type outStreamRequestForTesting struct {
+ throttledItem
+ streamID uint32
+ resp chan *outStream
+}
// closeConnection is an instruction to tell the loopy writer to flush the
// framer and exit, which will cause the transport's connection to be closed
// (by the client or server). The transport itself will close after the reader
// encounters the EOF caused by the connection closure.
-type closeConnection struct{}
-
-func (closeConnection) isTransportResponseFrame() bool { return false }
+type closeConnection struct {
+ throttledItem
+}
type outStreamState int
@@ -379,9 +390,9 @@ func (c *controlBuffer) executeAndPut(f func() bool, it cbItem) (bool, error) {
c.consumerWaiting = false
}
c.list.enqueue(it)
- if it.isTransportResponseFrame() {
+ if it.isThrottled() {
c.transportResponseFrames++
- if c.transportResponseFrames == maxQueuedTransportResponseFrames {
+ if c.transportResponseFrames == maxQueuedControlBufferItems {
// We are adding the frame that puts us over the threshold; create
// a throttling channel.
ch := make(chan struct{})
@@ -436,8 +447,8 @@ func (c *controlBuffer) getOnceLocked() (any, error) {
return nil, nil
}
h := c.list.dequeue().(cbItem)
- if h.isTransportResponseFrame() {
- if c.transportResponseFrames == maxQueuedTransportResponseFrames {
+ if h.isThrottled() {
+ if c.transportResponseFrames == maxQueuedControlBufferItems {
// We are removing the frame that put us over the
// threshold; close and clear the throttling channel.
ch := c.trfChan.Swap(nil)
@@ -464,10 +475,8 @@ func (c *controlBuffer) finish() {
// is still not aware of these yet.
for head := c.list.dequeueAll(); head != nil; head = head.next {
switch v := head.it.(type) {
- case *headerFrame:
- if v.onOrphaned != nil { // It will be nil on the server-side.
- v.onOrphaned(ErrConnClosing)
- }
+ case *clientHeaders:
+ v.onOrphaned(ErrConnClosing)
case *dataFrame:
if !v.processing {
v.data.Free()
@@ -680,42 +689,38 @@ func (l *loopyWriter) registerStreamHandler(h *registerStream) {
l.estdStreams[h.streamID] = str
}
-func (l *loopyWriter) headerHandler(h *headerFrame) error {
- if l.side == serverSide {
- str, ok := l.estdStreams[h.streamID]
- if !ok {
- if l.logger.V(logLevel) {
- l.logger.Infof("Unrecognized streamID %d in loopyWriter", h.streamID)
- }
- return nil
- }
- // Case 1.A: Server is responding back with headers.
- if !h.endStream {
- return l.writeHeader(h.streamID, h.endStream, h.hf, h.onWrite)
+func (l *loopyWriter) serverHeaderHandler(hdr *serverHeaders) error {
+ str, ok := l.estdStreams[hdr.streamID]
+ if !ok {
+ if l.logger.V(logLevel) {
+ l.logger.Infof("Unrecognized streamID %d in loopyWriter", hdr.streamID)
}
- // else: Case 1.B: Server wants to close stream.
+ return nil
+ }
- if str.state != empty { // either active or waiting on stream quota.
- // add it str's list of items.
- str.itl.enqueue(h)
- return nil
- }
- if err := l.writeHeader(h.streamID, h.endStream, h.hf, h.onWrite); err != nil {
- return err
- }
- return l.cleanupStreamHandler(h.cleanup)
+ // Case 1: Server is responding back with headers.
+ if !hdr.endStream {
+ return l.writeHeader(hdr.streamID, hdr.endStream, hdr.hf, hdr.onWrite)
}
- // Case 2: Client wants to originate stream.
+
+ // Case 2: Server is closing the stream.
+ if str.state != empty { // either active or waiting on stream quota.
+ str.itl.enqueue(hdr)
+ return nil
+ }
+ if err := l.writeHeader(hdr.streamID, hdr.endStream, hdr.hf, hdr.onWrite); err != nil {
+ return err
+ }
+ return l.cleanupStreamHandler(hdr.cleanup)
+}
+
+func (l *loopyWriter) clientHeaderHandler(hdr *clientHeaders) error {
str := &outStream{
- id: h.streamID,
+ id: hdr.streamID,
state: empty,
itl: &itemList{},
- wq: h.wq,
+ wq: hdr.wq,
}
- return l.originateStream(str, h)
-}
-
-func (l *loopyWriter) originateStream(str *outStream, hdr *headerFrame) error {
// l.draining is set when handling GoAway. In which case, we want to avoid
// creating new streams.
if l.draining {
@@ -726,7 +731,7 @@ func (l *loopyWriter) originateStream(str *outStream, hdr *headerFrame) error {
if err := hdr.initStream(str.id); err != nil {
return err
}
- if err := l.writeHeader(str.id, hdr.endStream, hdr.hf, hdr.onWrite); err != nil {
+ if err := l.writeHeader(str.id, false, hdr.hf, hdr.onWrite); err != nil {
return err
}
l.estdStreams[str.id] = str
@@ -805,6 +810,10 @@ func (l *loopyWriter) outFlowControlSizeRequestHandler(o *outFlowControlSizeRequ
o.resp <- l.sendQuota
}
+func (l *loopyWriter) outStreamRequestHandler(o *outStreamRequestForTesting) {
+ o.resp <- l.estdStreams[o.streamID]
+}
+
func (l *loopyWriter) cleanupStreamHandler(c *cleanupStream) error {
c.onWrite()
if str, ok := l.estdStreams[c.streamID]; ok {
@@ -882,8 +891,10 @@ func (l *loopyWriter) handle(i any) error {
return l.incomingSettingsHandler(i)
case *outgoingSettings:
return l.outgoingSettingsHandler(i)
- case *headerFrame:
- return l.headerHandler(i)
+ case *clientHeaders:
+ return l.clientHeaderHandler(i)
+ case *serverHeaders:
+ return l.serverHeaderHandler(i)
case *registerStream:
l.registerStreamHandler(i)
case *cleanupStream:
@@ -900,6 +911,8 @@ func (l *loopyWriter) handle(i any) error {
return l.goAwayHandler(i)
case *outFlowControlSizeRequest:
l.outFlowControlSizeRequestHandler(i)
+ case *outStreamRequestForTesting:
+ l.outStreamRequestHandler(i)
case closeConnection:
// Just return a non-I/O error and run() will flush and close the
// connection.
@@ -956,39 +969,16 @@ func (l *loopyWriter) processData() (bool, error) {
// from data is copied to h to make as big as the maximum possible HTTP2 frame
// size.
- if len(dataItem.h) == 0 && reader.Remaining() == 0 { // Empty data frame
- // Client sends out empty data frame with endStream = true
- if err := l.framer.writeData(dataItem.streamID, dataItem.endStream, nil); err != nil {
- return false, err
- }
- str.itl.dequeue() // remove the empty data item from stream
- reader.Close()
- if str.itl.isEmpty() {
- str.state = empty
- } else if trailer, ok := str.itl.peek().(*headerFrame); ok { // the next item is trailers.
- if err := l.writeHeader(trailer.streamID, trailer.endStream, trailer.hf, trailer.onWrite); err != nil {
- return false, err
- }
- if err := l.cleanupStreamHandler(trailer.cleanup); err != nil {
- return false, err
- }
- } else {
- l.activeStreams.enqueue(str)
- }
- return false, nil
- }
-
+ isEmpty := len(dataItem.h) == 0 && reader.Remaining() == 0
// Figure out the maximum size we can send
maxSize := http2MaxFrameLen
- if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota <= 0 { // stream-level flow control.
+ strQuota := int(l.oiws) - str.bytesOutStanding
+ if strQuota <= 0 && !isEmpty { // stream-level flow control.
str.state = waitingOnStreamQuota
return false, nil
- } else if maxSize > strQuota {
- maxSize = strQuota
- }
- if maxSize > int(l.sendQuota) { // connection-level flow control.
- maxSize = int(l.sendQuota)
}
+ maxSize = min(maxSize, max(strQuota, 0))
+ maxSize = min(maxSize, int(l.sendQuota)) // connection-level flow control.
// Compute how much of the header and data we can send within quota and max frame length
hSize := min(maxSize, len(dataItem.h))
dSize := min(maxSize-hSize, reader.Remaining())
@@ -1039,19 +1029,23 @@ func (l *loopyWriter) processData() (bool, error) {
reader.Close()
str.itl.dequeue()
}
+ return false, l.updateStreamAfterWrite(str)
+}
+
+func (l *loopyWriter) updateStreamAfterWrite(str *outStream) error {
if str.itl.isEmpty() {
str.state = empty
- } else if trailer, ok := str.itl.peek().(*headerFrame); ok { // The next item is trailers.
+ } else if trailer, ok := str.itl.peek().(*serverHeaders); ok { // the next item is trailers.
if err := l.writeHeader(trailer.streamID, trailer.endStream, trailer.hf, trailer.onWrite); err != nil {
- return false, err
+ return err
}
if err := l.cleanupStreamHandler(trailer.cleanup); err != nil {
- return false, err
+ return err
}
} else if int(l.oiws)-str.bytesOutStanding <= 0 { // Ran out of stream quota.
str.state = waitingOnStreamQuota
} else { // Otherwise add it back to the list of active streams.
l.activeStreams.enqueue(str)
}
- return false, nil
+ return nil
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go
index 7cfbc96..98cef9e 100644
--- a/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go
+++ b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go
@@ -115,7 +115,6 @@ func (f *trInFlow) getSize() uint32 {
return atomic.LoadUint32(&f.effectiveWindowSize)
}
-// TODO(mmukhi): Simplify this code.
// inFlow deals with inbound flow control
type inFlow struct {
mu sync.Mutex
@@ -174,14 +173,14 @@ func (f *inFlow) maybeAdjust(n uint32) uint32 {
// onData is invoked when some data frame is received. It updates pendingData.
func (f *inFlow) onData(n uint32) error {
f.mu.Lock()
+ defer f.mu.Unlock()
+
f.pendingData += n
if f.pendingData+f.pendingUpdate > f.limit+f.delta {
limit := f.limit
rcvd := f.pendingData + f.pendingUpdate
- f.mu.Unlock()
return fmt.Errorf("received %d-bytes data exceeding the limit %d bytes", rcvd, limit)
}
- f.mu.Unlock()
return nil
}
@@ -189,8 +188,9 @@ func (f *inFlow) onData(n uint32) error {
// to be sent to the peer.
func (f *inFlow) onRead(n uint32) uint32 {
f.mu.Lock()
+ defer f.mu.Unlock()
+
if f.pendingData == 0 {
- f.mu.Unlock()
return 0
}
f.pendingData -= n
@@ -205,9 +205,7 @@ func (f *inFlow) onRead(n uint32) uint32 {
if f.pendingUpdate >= f.limit/4 {
wu := f.pendingUpdate
f.pendingUpdate = 0
- f.mu.Unlock()
return wu
}
- f.mu.Unlock()
return 0
}
diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
index 7ab3422..9cd8d28 100644
--- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go
@@ -424,7 +424,7 @@ func (ht *serverHandlerTransport) HandleStreams(ctx context.Context, startStream
st: ht,
headerWireLength: 0, // won't have access to header wire length until golang/go#18997.
}
- s.Stream.buf.init()
+ s.Stream.buf.init(ht.bufferPool)
s.readRequester = s
s.trReader = transportReader{
reader: recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: &s.buf},
@@ -479,8 +479,8 @@ func (ht *serverHandlerTransport) runStream() {
func (ht *serverHandlerTransport) incrMsgRecv() {}
-func (ht *serverHandlerTransport) Drain(string) {
- panic("Drain() is not implemented")
+func (ht *serverHandlerTransport) Drain(s string) {
+ ht.Close(errors.New(s))
}
// mapRecvMsgError returns the non-nil err into the appropriate
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
index d6bc6a6..720fc4e 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go
@@ -39,6 +39,7 @@ import (
"google.golang.org/grpc/internal"
"google.golang.org/grpc/internal/channelz"
icredentials "google.golang.org/grpc/internal/credentials"
+ "google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/grpcsync"
"google.golang.org/grpc/internal/grpcutil"
@@ -318,7 +319,13 @@ func NewHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
}
writeBufSize := opts.WriteBufferSize
readBufSize := opts.ReadBufferSize
+ // The default header list size is moving from 16MB to 8KB. The 8KB limit
+ // is only used if Enable8KBDefaultHeaderListSize is true; otherwise, the
+ // old 16MB default is used. User-specified options always take precedence.
maxHeaderListSize := defaultClientMaxHeaderListSize
+ if envconfig.Enable8KBDefaultHeaderListSize {
+ maxHeaderListSize = upcomingDefaultHeaderListSize
+ }
if opts.MaxHeaderListSize != nil {
maxHeaderListSize = *opts.MaxHeaderListSize
}
@@ -491,10 +498,9 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr, handler s
ct: t,
done: make(chan struct{}),
headerChan: make(chan struct{}),
- doneFunc: callHdr.DoneFunc,
statsHandler: handler,
}
- s.Stream.buf.init()
+ s.Stream.buf.init(t.bufferPool)
s.Stream.wq.init(defaultWriteQuota, s.done)
s.readRequester = s
// The client side stream context should have exactly the same life cycle with the user provided context.
@@ -548,8 +554,6 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
if err != nil {
return nil, err
}
- // TODO(mmukhi): Benchmark if the performance gets better if count the metadata and other header fields
- // first and create a slice of that exact size.
// Make the slice of certain predictable size to reduce allocations made by append.
hfLen := 7 // :method, :scheme, :path, :authority, content-type, user-agent, te
hfLen += len(authData) + len(callAuthData)
@@ -569,6 +573,21 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
if _, ok := ctx.Deadline(); ok {
hfLen++
}
+ // Count the metadata header fields as well so the slice is not reallocated
+ // while they are appended below. Reserved headers are dropped when writing,
+ // so this may slightly over-count, which is preferable to growing the slice.
+ md, added, mdOK := metadataFromOutgoingContextRaw(ctx)
+ if mdOK {
+ for _, vv := range md {
+ hfLen += len(vv)
+ }
+ for _, vv := range added {
+ hfLen += len(vv) / 2
+ }
+ }
+ for _, vv := range t.md {
+ hfLen += len(vv)
+ }
headerFields := make([]hpack.HeaderField, 0, hfLen)
headerFields = append(headerFields, hpack.HeaderField{Name: ":method", Value: "POST"})
headerFields = append(headerFields, hpack.HeaderField{Name: ":scheme", Value: t.scheme})
@@ -613,7 +632,7 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)})
}
- if md, added, ok := metadataFromOutgoingContextRaw(ctx); ok {
+ if mdOK {
var k string
for k, vv := range md {
// HTTP doesn't allow you to set pseudoheaders after non pseudoheaders were set.
@@ -642,6 +661,9 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr)
if isReservedHeader(k) {
continue
}
+ if err := imetadata.ValidatePair(k, vv...); err != nil {
+ return nil, status.Error(codes.Internal, err.Error())
+ }
for _, v := range vv {
headerFields = append(headerFields, hpack.HeaderField{Name: k, Value: encodeMetadataHeader(k, v)})
}
@@ -685,6 +707,9 @@ func (t *http2Client) getTrAuthData(ctx context.Context, audience string) (map[s
for k, v := range data {
// Capital header names are illegal in HTTP/2.
k = strings.ToLower(k)
+ if err := imetadata.ValidatePair(k, v); err != nil {
+ return nil, status.Error(codes.Internal, err.Error())
+ }
authData[k] = v
}
}
@@ -718,6 +743,9 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call
for k, v := range data {
// Capital header names are illegal in HTTP/2
k = strings.ToLower(k)
+ if err := imetadata.ValidatePair(k, v); err != nil {
+ return nil, status.Error(codes.Internal, err.Error())
+ }
callAuthData[k] = v
}
}
@@ -799,9 +827,8 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr, handler s
close(s.headerChan)
}
}
- hdr := &headerFrame{
- hf: headerFields,
- endStream: false,
+ hdr := &clientHeaders{
+ hf: headerFields,
initStream: func(uint32) error {
t.mu.Lock()
// TODO: handle transport closure in loopy instead and remove this
@@ -879,8 +906,8 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr, handler s
return false
}
}
- if sz > int64(upcomingDefaultHeaderListSize) {
- t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize)
+ if !envconfig.Enable8KBDefaultHeaderListSize && sz > int64(upcomingDefaultHeaderListSize) {
+ t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In release v1.82.0, GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE will be enabled by default, enforcing this limit.", sz, upcomingDefaultHeaderListSize)
}
return true
}
@@ -992,9 +1019,6 @@ func (t *http2Client) closeStream(s *ClientStream, err error, rst bool, rstCode
t.controlBuf.executeAndPut(addBackStreamQuota, cleanup)
// This will unblock write.
close(s.done)
- if s.doneFunc != nil {
- s.doneFunc()
- }
}
// Close kicks off the shutdown process of the transport. This should be called
@@ -1224,10 +1248,33 @@ func (t *http2Client) handleData(f *parsedDataFrame) {
t.closeStream(s, io.EOF, true, http2.ErrCodeFlowControl, status.New(codes.Internal, err.Error()), nil, false)
return
}
+ }
+
+ if s.nonGRPCStatus != nil {
+ // The frame should be handled as a non-gRPC response body. A non-nil
+ // status also covers END_STREAM, so no separate handling is needed below.
+ st := s.handleNonGRPCData(f)
+ if st != nil {
+ t.closeStream(s, st.Err(), true, http2.ErrCodeProtocol, st, nil, true)
+ return
+ }
+ if w := s.fc.onRead(size); w > 0 {
+ t.controlBuf.put(&outgoingWindowUpdate{
+ streamID: s.id,
+ increment: w,
+ })
+ }
+ return
+ }
+
+ if size > 0 {
dataLen := f.data.Len()
if f.Header().Flags.Has(http2.FlagDataPadded) {
if w := s.fc.onRead(size - uint32(dataLen)); w > 0 {
- t.controlBuf.put(&outgoingWindowUpdate{s.id, w})
+ t.controlBuf.put(&outgoingWindowUpdate{
+ streamID: s.id,
+ increment: w,
+ })
}
}
if dataLen > 0 {
@@ -1468,6 +1515,17 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
return
}
+ // If we are collecting non-gRPC response data and receive a trailing
+ // HEADERS frame with END_STREAM, finalize the buffered data and close
+ // the stream.
+ if s.nonGRPCStatus != nil {
+ if endStream {
+ st := s.finalizeNonGRPCStatus()
+ t.closeStream(s, st.Err(), true, http2.ErrCodeProtocol, st, nil, true)
+ }
+ return
+ }
+
var (
// If a gRPC Response-Headers has already been received, then it means
// that the peer is speaking gRPC and we are in gRPC mode.
@@ -1568,7 +1626,12 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
}
se := status.New(grpcErrorCode, strings.Join(errs, "; "))
- t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
+ if endStream {
+ t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, true)
+ return
+ }
+
+ s.startNonGRPCDataCollection(se)
return
}
@@ -1839,7 +1902,7 @@ func (t *http2Client) getOutFlowWindow() int64 {
resp := make(chan uint32, 1)
timer := time.NewTimer(time.Second)
defer timer.Stop()
- t.controlBuf.put(&outFlowControlSizeRequest{resp})
+ t.controlBuf.put(&outFlowControlSizeRequest{resp: resp})
select {
case sz := <-resp:
return int64(sz)
diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
index 3a8c36e..f11e88c 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go
@@ -38,11 +38,13 @@ import (
"google.golang.org/protobuf/proto"
"google.golang.org/grpc/internal"
+ "google.golang.org/grpc/internal/envconfig"
"google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/grpcutil"
"google.golang.org/grpc/internal/pretty"
istatus "google.golang.org/grpc/internal/status"
"google.golang.org/grpc/internal/syscall"
+ transportinternal "google.golang.org/grpc/internal/transport/internal"
"google.golang.org/grpc/mem"
"google.golang.org/grpc/codes"
@@ -165,7 +167,13 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
}
writeBufSize := config.WriteBufferSize
readBufSize := config.ReadBufferSize
+ // The default header list size is moving from 16MB to 8KB. The 8KB limit
+ // is only used if Enable8KBDefaultHeaderListSize is true; otherwise, the
+ // old 16MB default is used. User-specified options always take precedence.
maxHeaderListSize := defaultServerMaxHeaderListSize
+ if envconfig.Enable8KBDefaultHeaderListSize {
+ maxHeaderListSize = upcomingDefaultHeaderListSize
+ }
if config.MaxHeaderListSize != nil {
maxHeaderListSize = *config.MaxHeaderListSize
}
@@ -399,7 +407,7 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade
st: t,
headerWireLength: int(frame.Header().Length),
}
- s.Stream.buf.init()
+ s.Stream.buf.init(t.bufferPool)
var (
// if false, content-type was missing or invalid
isGRPC = false
@@ -514,9 +522,16 @@ func (t *http2Server) operateHeaders(ctx context.Context, frame *http2.MetaHeade
delete(mdata, "host")
}
+ // If :authority is still missing, i.e. no host or :authority header is
+ // present, reject the request as invalid.
+ if len(mdata[":authority"]) == 0 {
+ t.writeEarlyAbort(streamID, s.contentSubtype, status.New(codes.Internal, "no host or :authority header present"), http.StatusBadRequest, !frame.StreamEnded())
+ return nil
+ }
if frame.StreamEnded() {
// s is just created by the caller. No lock needed.
s.state = streamReadDone
+ s.write(recvMsg{err: io.EOF})
}
if timeoutSet {
s.ctx, s.cancel = context.WithTimeout(ctx, timeout)
@@ -802,7 +817,10 @@ func (t *http2Server) handleData(f *parsedDataFrame) {
dataLen := f.data.Len()
if f.Header().Flags.Has(http2.FlagDataPadded) {
if w := s.fc.onRead(size - uint32(dataLen)); w > 0 {
- t.controlBuf.put(&outgoingWindowUpdate{s.id, w})
+ t.controlBuf.put(&outgoingWindowUpdate{
+ streamID: s.id,
+ increment: w,
+ })
}
}
if dataLen > 0 {
@@ -948,8 +966,8 @@ func (t *http2Server) checkForHeaderListSize(hf []hpack.HeaderField) bool {
return false
}
}
- if sz > int64(upcomingDefaultHeaderListSize) {
- t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In a future release, this will be restricted to %d bytes.", sz, upcomingDefaultHeaderListSize, upcomingDefaultHeaderListSize)
+ if !envconfig.Enable8KBDefaultHeaderListSize && sz > int64(upcomingDefaultHeaderListSize) {
+ t.logger.Warningf("Header list size to send (%d bytes) is larger than the upcoming default limit (%d bytes). In release v1.82.0, GRPC_GO_EXPERIMENTAL_ENABLE_8KB_DEFAULT_HEADER_LIST_SIZE will be enabled by default, enforcing this limit.", sz, upcomingDefaultHeaderListSize)
}
return true
}
@@ -1039,7 +1057,7 @@ func (t *http2Server) writeHeaderLocked(s *ServerStream) error {
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: s.sendCompress})
}
headerFields = appendHeaderFieldsFromMD(headerFields, s.header)
- hf := &headerFrame{
+ hf := &serverHeaders{
streamID: s.id,
hf: headerFields,
endStream: false,
@@ -1107,7 +1125,7 @@ func (t *http2Server) writeStatus(s *ServerStream, st *status.Status) error {
// Attach the trailer metadata.
headerFields = appendHeaderFieldsFromMD(headerFields, s.trailer)
- trailingHeader := &headerFrame{
+ trailingHeader := &serverHeaders{
streamID: s.id,
hf: headerFields,
endStream: true,
@@ -1317,7 +1335,7 @@ func (t *http2Server) deleteStream(s *ServerStream, eosReceived bool) {
}
// finishStream closes the stream and puts the trailing headerFrame into controlbuf.
-func (t *http2Server) finishStream(s *ServerStream, rst bool, rstCode http2.ErrCode, hdr *headerFrame, eosReceived bool) {
+func (t *http2Server) finishStream(s *ServerStream, rst bool, rstCode http2.ErrCode, hdr *serverHeaders, eosReceived bool) {
// In case stream sending and receiving are invoked in separate
// goroutines (e.g., bi-directional streaming), cancel needs to be
// called to interrupt the potential blocking on other goroutines.
@@ -1441,14 +1459,14 @@ func (t *http2Server) socketMetrics() *channelz.EphemeralSocketMetrics {
func (t *http2Server) incrMsgSent() {
if channelz.IsOn() {
t.channelz.SocketMetrics.MessagesSent.Add(1)
- t.channelz.SocketMetrics.LastMessageSentTimestamp.Add(1)
+ t.channelz.SocketMetrics.LastMessageSentTimestamp.Store(transportinternal.TimeNowFunc())
}
}
func (t *http2Server) incrMsgRecv() {
if channelz.IsOn() {
t.channelz.SocketMetrics.MessagesReceived.Add(1)
- t.channelz.SocketMetrics.LastMessageReceivedTimestamp.Add(1)
+ t.channelz.SocketMetrics.LastMessageReceivedTimestamp.Store(transportinternal.TimeNowFunc())
}
}
@@ -1456,7 +1474,7 @@ func (t *http2Server) getOutFlowWindow() int64 {
resp := make(chan uint32, 1)
timer := time.NewTimer(time.Second)
defer timer.Stop()
- t.controlBuf.put(&outFlowControlSizeRequest{resp})
+ t.controlBuf.put(&outFlowControlSizeRequest{resp: resp})
select {
case sz := <-resp:
return int64(sz)
diff --git a/vendor/google.golang.org/grpc/internal/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go
index c34975f..faa42f8 100644
--- a/vendor/google.golang.org/grpc/internal/transport/http_util.go
+++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go
@@ -300,24 +300,29 @@ func decodeGrpcMessageUnchecked(msg string) string {
type bufWriter struct {
pool *imem.SimpleBufferPool
- buf []byte
+ bufHandle *[]byte
offset int
batchSize int
conn io.Writer
err error
}
+// unsharedBufWriter keeps the unshared slice header in the writer allocation.
+type unsharedBufWriter struct {
+ bufWriter
+ buf []byte
+}
+
func newBufWriter(conn io.Writer, batchSize int, pool *imem.SimpleBufferPool) *bufWriter {
- w := &bufWriter{
- batchSize: batchSize,
- conn: conn,
- pool: pool,
- }
- // this indicates that we should use non shared buf
- if pool == nil {
- w.buf = make([]byte, batchSize)
+ if pool == nil && batchSize > 0 {
+ w := &unsharedBufWriter{
+ bufWriter: bufWriter{batchSize: batchSize, conn: conn},
+ buf: make([]byte, batchSize),
+ }
+ w.bufHandle = &w.buf
+ return &w.bufWriter
}
- return w
+ return &bufWriter{batchSize: batchSize, conn: conn, pool: pool}
}
func (w *bufWriter) Write(b []byte) (int, error) {
@@ -328,13 +333,13 @@ func (w *bufWriter) Write(b []byte) (int, error) {
n, err := w.conn.Write(b)
return n, toIOError(err)
}
- if w.buf == nil {
- b := w.pool.Get(w.batchSize)
- w.buf = *b
+ if w.bufHandle == nil {
+ w.bufHandle = w.pool.Get(w.batchSize)
}
+ buf := *w.bufHandle
written := 0
for len(b) > 0 {
- copied := copy(w.buf[w.offset:], b)
+ copied := copy(buf[w.offset:], b)
b = b[copied:]
written += copied
w.offset += copied
@@ -350,15 +355,17 @@ func (w *bufWriter) Write(b []byte) (int, error) {
func (w *bufWriter) Flush() error {
err := w.flushKeepBuffer()
- // Only release the buffer if we are in a "shared" mode
- if w.buf != nil && w.pool != nil {
- b := w.buf
- w.pool.Put(&b)
- w.buf = nil
- }
+ w.releaseBuffer()
return err
}
+func (w *bufWriter) releaseBuffer() {
+ if w.pool != nil && w.bufHandle != nil {
+ w.pool.Put(w.bufHandle)
+ w.bufHandle = nil
+ }
+}
+
func (w *bufWriter) flushKeepBuffer() error {
if w.err != nil {
return w.err
@@ -366,9 +373,13 @@ func (w *bufWriter) flushKeepBuffer() error {
if w.offset == 0 {
return nil
}
- _, w.err = w.conn.Write(w.buf[:w.offset])
+ buf := *w.bufHandle
+ _, w.err = w.conn.Write(buf[:w.offset])
w.err = toIOError(w.err)
w.offset = 0
+ if w.err != nil {
+ w.releaseBuffer()
+ }
return w.err
}
diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/regex.go b/vendor/google.golang.org/grpc/internal/transport/internal/internal.go
similarity index 59%
rename from vendor/google.golang.org/grpc/internal/grpcutil/regex.go
rename to vendor/google.golang.org/grpc/internal/transport/internal/internal.go
index 7a092b2..a7c7c7d 100644
--- a/vendor/google.golang.org/grpc/internal/grpcutil/regex.go
+++ b/vendor/google.golang.org/grpc/internal/transport/internal/internal.go
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2021 gRPC authors.
+ * Copyright 2026 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,16 +16,10 @@
*
*/
-package grpcutil
+// Package internal contains functionality internal to the transport package.
+package internal
-import "regexp"
-
-// FullMatchWithRegex returns whether the full text matches the regex provided.
-func FullMatchWithRegex(re *regexp.Regexp, text string) bool {
- if len(text) == 0 {
- return re.MatchString(text)
- }
- re.Longest()
- rem := re.FindString(text)
- return len(rem) == len(text)
-}
+// TimeNowFunc is a variable that can be set to override the default behavior of
+// getting the current time in nanoseconds. It is used in transport code to set
+// channelz timestamps, and is exposed here for testing purposes.
+var TimeNowFunc func() int64
diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go
index 1e22457..fc656b3 100644
--- a/vendor/google.golang.org/grpc/internal/transport/transport.go
+++ b/vendor/google.golang.org/grpc/internal/transport/transport.go
@@ -30,11 +30,15 @@ import (
"sync"
"sync/atomic"
"time"
+ "unsafe"
"golang.org/x/net/http2"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/internal/channelz"
+ "google.golang.org/grpc/internal/envconfig"
+ imem "google.golang.org/grpc/internal/mem"
+ "google.golang.org/grpc/internal/transport/internal"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/mem"
"google.golang.org/grpc/metadata"
@@ -44,7 +48,34 @@ import (
"google.golang.org/grpc/tap"
)
-const logLevel = 2
+const (
+ logLevel = 2
+ // recvMsgSize estimates the memory overhead of a recvMsg in the backlog.
+ // It accounts for the recvMsg struct itself and the slice header of the
+ // underlying buffer's data.
+ recvMsgSize = int(unsafe.Sizeof(recvMsg{}) + unsafe.Sizeof([]byte{}))
+
+ // utilizationFactor controls when we consider memory utilization acceptable.
+ // When backlogHeapSize / payloadSize <= utilizationFactor (meaning at least
+ // 50% of the heap memory is actual payload data), compaction is skipped.
+ utilizationFactor = 2
+)
+
+var (
+ // compactionThreshold is approx 57KB (on 64-bit systems). It allows
+ // accumulating up to 1024 1-byte payloads before triggering compaction.
+ //
+ // Because individual payloads <= 1024 bytes are allocated on the heap
+ // outside mem.BufferPool, waiting for at least 1024 bytes to accumulate
+ // ensures that compaction coalesces those small heap allocations into a
+ // single large buffer from mem.BufferPool, enabling buffer reuse while
+ // avoiding frequent copying for small bursts of frames.
+ compactionThreshold = imem.BufferPoolingThreshold * (recvMsgSize + 1)
+)
+
+func init() {
+ internal.TimeNowFunc = func() int64 { return time.Now().UnixNano() }
+}
// recvMsg represents the received msg from the transport. All transport
// protocol specific info has been removed.
@@ -58,31 +89,39 @@ type recvMsg struct {
// recvBuffer is an unbounded channel of recvMsg structs.
//
-// Note: recvBuffer differs from buffer.Unbounded only in the fact that it
-// holds a channel of recvMsg structs instead of objects implementing "item"
-// interface. recvBuffer is written to much more often and using strict recvMsg
-// structs helps avoid allocation in "recvBuffer.put"
+// Note: recvBuffer differs from buffer.Unbounded in that it provides in-place
+// value initialization (via init) to avoid struct pointer allocations on
+// streams, and automatically frees pooled mem.Buffer payloads when stream
+// errors occur.
type recvBuffer struct {
c chan recvMsg
mu sync.Mutex
backlog []recvMsg
- err error
+ // uncompactedSuffixLen tracks the number of consecutive data messages at
+ // the tail of backlog that have not been compacted.
+ uncompactedSuffixLen int
+ // uncompactedBytes tracks the total payload bytes across the trailing
+ // uncompactedSuffixLen messages.
+ uncompactedBytes int
+ err error
+ bufPool mem.BufferPool
}
// init allows a recvBuffer to be initialized in-place, which is useful
// for resetting a buffer or for avoiding a heap allocation when the buffer
// is embedded in another struct.
-func (b *recvBuffer) init() {
+func (b *recvBuffer) init(pool mem.BufferPool) {
b.c = make(chan recvMsg, 1)
+ b.bufPool = pool
}
func (b *recvBuffer) put(r recvMsg) {
b.mu.Lock()
+ defer b.mu.Unlock()
if b.err != nil {
// drop the buffer on the floor. Since b.err is not nil, any subsequent reads
// will always return an error, making this buffer inaccessible.
r.buffer.Free()
- b.mu.Unlock()
// An error had occurred earlier, don't accept more
// data or errors.
return
@@ -91,13 +130,70 @@ func (b *recvBuffer) put(r recvMsg) {
if len(b.backlog) == 0 {
select {
case b.c <- r:
- b.mu.Unlock()
return
default:
}
}
b.backlog = append(b.backlog, r)
- b.mu.Unlock()
+ b.compactBacklogLocked(r)
+}
+
+func (b *recvBuffer) compactBacklogLocked(r recvMsg) {
+ if !envconfig.EnableReceiveBufferCompaction {
+ return
+ }
+ if r.buffer == nil {
+ b.uncompactedBytes = 0
+ b.uncompactedSuffixLen = 0
+ return
+ }
+
+ b.uncompactedSuffixLen++
+ b.uncompactedBytes += r.buffer.Len()
+ backlogHeapSize := b.uncompactedSuffixLen*recvMsgSize + b.uncompactedBytes
+
+ // If the memory overhead is less than 50% of the heap usage (e.g., because
+ // a large DATA frame arrived), the average message size in the suffix is
+ // large enough that memory bloat is not a concern. Reset suffix tracking.
+ if backlogHeapSize <= utilizationFactor*b.uncompactedBytes {
+ b.uncompactedBytes = 0
+ b.uncompactedSuffixLen = 0
+ return
+ }
+ // Avoid compacting too frequently for short bursts of small frames.
+ // Wait until we have accumulated at least ~1024 small messages (~57 KB).
+ if backlogHeapSize <= compactionThreshold {
+ // Still can accumulate more payloads.
+ return
+ }
+
+ // Since the memory utilization is less than 50%, the average payload size
+ // of each recvMsg must be less than recvMsgSize (approx 56 bytes).
+ // In the worst case for bytes copied (where the average payload is just
+ // below recvMsgSize), compaction will occur once every:
+ // compactionThreshold / (recvMsgSize + avg_payload) = ~520 messages,
+ // copying ~29KB of data.
+
+ start := 0
+ newBuf := b.bufPool.Get(b.uncompactedBytes)
+ startIdx := len(b.backlog) - b.uncompactedSuffixLen
+
+ for i := startIdx; i < len(b.backlog); i++ {
+ m := b.backlog[i]
+ b.backlog[i] = recvMsg{}
+ start += copy((*newBuf)[start:], m.buffer.ReadOnlyData())
+ m.buffer.Free()
+ }
+ b.backlog[startIdx] = recvMsg{
+ buffer: mem.NewBuffer(newBuf, b.bufPool),
+ }
+ b.backlog = b.backlog[:startIdx+1]
+ // After compaction, the suffix is replaced with a single message containing
+ // the combined payload. The new utilization is close to 1.0 (overhead of
+ // one recvMsg relative to the large compacted payload), which is well
+ // below the utilization factor of 2.
+ b.uncompactedBytes = 0
+ b.uncompactedSuffixLen = 0
}
func (b *recvBuffer) load() {
@@ -105,6 +201,13 @@ func (b *recvBuffer) load() {
if len(b.backlog) > 0 {
select {
case b.c <- b.backlog[0]:
+ // backlog[0] is only part of the tracked uncompacted suffix if the
+ // entire backlog currently consists of the suffix. If an earlier
+ // compaction or reset occurred, backlog[0] is already compacted.
+ if envconfig.EnableReceiveBufferCompaction && b.uncompactedSuffixLen == len(b.backlog) {
+ b.uncompactedSuffixLen--
+ b.uncompactedBytes -= b.backlog[0].buffer.Len()
+ }
b.backlog[0] = recvMsg{}
b.backlog = b.backlog[1:]
default:
@@ -363,15 +466,18 @@ func (s *Stream) ReadMessageHeader(header []byte) (err error) {
return er
}
s.readRequester.requestRead(len(header))
+ bytesRead := 0
for len(header) != 0 {
n, err := s.trReader.ReadMessageHeader(header)
+ bytesRead += n
header = header[n:]
if len(header) == 0 {
err = nil
}
if err != nil {
- if n > 0 && err == io.EOF {
+ if bytesRead > 0 && err == io.EOF {
err = io.ErrUnexpectedEOF
+ s.trReader.er = err
}
return err
}
@@ -402,19 +508,22 @@ func (s *Stream) read(n int) (data mem.BufferSlice, err error) {
allocCap := min(ceil(n, http2MaxFrameLen), 128)
data = make(mem.BufferSlice, 0, allocCap)
s.readRequester.requestRead(n)
+ bytesRead := 0
for n != 0 {
buf, err := s.trReader.Read(n)
var bufLen int
if buf != nil {
bufLen = buf.Len()
}
+ bytesRead += bufLen
n -= bufLen
if n == 0 {
err = nil
}
if err != nil {
- if bufLen > 0 && err == io.EOF {
+ if bytesRead > 0 && err == io.EOF {
err = io.ErrUnexpectedEOF
+ s.trReader.er = err
}
data.Free()
return nil, err
@@ -589,8 +698,6 @@ type CallHdr struct {
PreviousAttempts int // value of grpc-previous-rpc-attempts header to set
- DoneFunc func() // called when the stream is finished
-
// Authority is used to explicitly override the `:authority` header.
//
// This value comes from one of two sources:
diff --git a/vendor/google.golang.org/grpc/mem/buffer_pool.go b/vendor/google.golang.org/grpc/mem/buffer_pool.go
index 3b02b90..aa12137 100644
--- a/vendor/google.golang.org/grpc/mem/buffer_pool.go
+++ b/vendor/google.golang.org/grpc/mem/buffer_pool.go
@@ -59,10 +59,6 @@ func init() {
internal.SetDefaultBufferPool = func(pool BufferPool) {
defaultBufferPool = pool
}
-
- internal.SetBufferPoolingThresholdForTesting = func(threshold int) {
- bufferPoolingThreshold = threshold
- }
}
// DefaultBufferPool returns the current default buffer pool. It is a BufferPool
diff --git a/vendor/google.golang.org/grpc/mem/buffers.go b/vendor/google.golang.org/grpc/mem/buffers.go
index 2b410b1..9b355d4 100644
--- a/vendor/google.golang.org/grpc/mem/buffers.go
+++ b/vendor/google.golang.org/grpc/mem/buffers.go
@@ -29,6 +29,8 @@ import (
"fmt"
"sync"
"sync/atomic"
+
+ "google.golang.org/grpc/internal/mem"
)
// A Buffer represents a reference counted piece of data (in bytes) that can be
@@ -63,8 +65,6 @@ type Buffer interface {
}
var (
- bufferPoolingThreshold = 1 << 10
-
bufferObjectPool = sync.Pool{New: func() any { return new(buffer) }}
)
@@ -72,7 +72,7 @@ var (
// equal to the threshold for buffer pooling. This is used to determine whether
// to pool buffers or allocate them directly.
func IsBelowBufferPoolingThreshold(size int) bool {
- return size <= bufferPoolingThreshold
+ return size <= mem.BufferPoolingThreshold
}
type buffer struct {
diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go
index d2e1525..2b79204 100644
--- a/vendor/google.golang.org/grpc/metadata/metadata.go
+++ b/vendor/google.golang.org/grpc/metadata/metadata.go
@@ -24,6 +24,7 @@ package metadata // import "google.golang.org/grpc/metadata"
import (
"context"
"fmt"
+ "sort"
"strings"
"google.golang.org/grpc/internal"
@@ -90,6 +91,76 @@ func Pairs(kv ...string) MD {
return md
}
+// loggableMetadataKeys is the set of metadata keys whose values are known not
+// to carry credentials or other sensitive data, and are therefore safe to print
+// verbatim in String. Values for any key not in this set are redacted. Keys are
+// in metadata's canonical lowercase form.
+//
+// The list is intentionally restricted to standardized gRPC and HTTP/2 protocol
+// headers. Everything else, including all application-defined keys, is
+// censored.
+// Note that this list might change as we add/remove support for
+// metadata types.
+var loggableMetadataKeys = map[string]bool{
+ "content-type": true,
+ "te": true,
+ "user-agent": true,
+ "grpc-encoding": true,
+ "grpc-accept-encoding": true,
+ "grpc-timeout": true,
+ "grpc-status": true,
+ "grpc-message-type": true,
+ "grpc-previous-rpc-attempts": true,
+ "grpc-retry-pushback-ms": true,
+}
+
+// String implements fmt.Stringer to allow metadata to be printed when stored in
+// a context.
+//
+// To avoid accidentally leaking credentials or other sensitive data (for
+// example via log(md), or by logging a value that happens to contain metadata),
+// String reports only keys on an allowlist of standardized, non-sensitive
+// protocol headers (see loggableMetadataKeys). Every other key is omitted
+// entirely, along with its values, because a key name may itself be sensitive;
+// only the number of omitted keys is reported, as "". This is a
+// best-effort guard against accidents, not a security boundary: a caller that
+// genuinely wants the full contents can still print map[string][]string(md)
+// directly.
+//
+// Note that this only affects verbs that use the Stringer, such as %v and %s.
+// The %#v verb prints the underlying map with all values and is not redacted.
+// Users should not rely on the output of this method to be stable
+// # Experimental
+//
+// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
+// release.
+func (md MD) String() string {
+ keys := make([]string, 0, len(md))
+ for k := range md {
+ if loggableMetadataKeys[strings.ToLower(k)] {
+ keys = append(keys, k)
+ }
+ }
+ sort.Strings(keys)
+
+ var sb strings.Builder
+ sb.WriteString("map[")
+ for i, k := range keys {
+ if i > 0 {
+ sb.WriteByte(' ')
+ }
+ fmt.Fprintf(&sb, "%s:%v", k, md[k])
+ }
+ if redacted := len(md) - len(keys); redacted > 0 {
+ if len(keys) > 0 {
+ sb.WriteByte(' ')
+ }
+ fmt.Fprintf(&sb, "<%d redacted>", redacted)
+ }
+ sb.WriteByte(']')
+ return sb.String()
+}
+
// Len returns the number of items in md.
func (md MD) Len() int {
return len(md)
diff --git a/vendor/google.golang.org/grpc/resolver_wrapper.go b/vendor/google.golang.org/grpc/resolver_wrapper.go
index 6e61376..f8b0fd3 100644
--- a/vendor/google.golang.org/grpc/resolver_wrapper.go
+++ b/vendor/google.golang.org/grpc/resolver_wrapper.go
@@ -188,7 +188,7 @@ func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.P
// addChannelzTraceEvent adds a channelz trace event containing the new
// state received from resolver implementations.
func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) {
- if !logger.V(0) && !channelz.IsOn() {
+ if !logger.V(2) && !channelz.IsOn() {
return
}
var updates []string
diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go
index ee7f7de..52f4ea5 100644
--- a/vendor/google.golang.org/grpc/rpc_util.go
+++ b/vendor/google.golang.org/grpc/rpc_util.go
@@ -128,6 +128,16 @@ func NewGZIPDecompressor() Decompressor {
}
func (d *gzipDecompressor) Do(r io.Reader) ([]byte, error) {
+ return d.doWithMaxSize(r, math.MaxInt64)
+}
+
+// doWithMaxSize behaves like Do but caps the size of the decompressed
+// payload at maxMessageSize+1 bytes. The Decompressor interface does not
+// allow extra parameters, so callers inside the package type-assert to
+// *gzipDecompressor to invoke this method directly. The +1 byte makes it
+// possible for the caller to detect that the limit was exceeded and
+// return ResourceExhausted instead of materializing an unbounded payload.
+func (d *gzipDecompressor) doWithMaxSize(r io.Reader, maxMessageSize int64) ([]byte, error) {
var z *gzip.Reader
switch maybeZ := d.pool.Get().(type) {
case nil:
@@ -148,7 +158,11 @@ func (d *gzipDecompressor) Do(r io.Reader) ([]byte, error) {
z.Close()
d.pool.Put(z)
}()
- return io.ReadAll(z)
+ var src io.Reader = z
+ if maxMessageSize < math.MaxInt64 {
+ src = io.LimitReader(z, maxMessageSize+1)
+ }
+ return io.ReadAll(src)
}
func (d *gzipDecompressor) Type() string {
@@ -830,15 +844,15 @@ func compress(in mem.BufferSlice, cp Compressor, compressor encoding.Compressor,
if compressor != nil {
z, err := compressor.Compress(w)
if err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
for _, b := range in {
if _, err := z.Write(b.ReadOnlyData()); err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
}
if err := z.Close(); err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
} else {
// This is obviously really inefficient since it fully materializes the data, but
@@ -848,7 +862,7 @@ func compress(in mem.BufferSlice, cp Compressor, compressor encoding.Compressor,
buf := in.MaterializeToBuffer(pool)
defer buf.Free()
if err := cp.Do(w, buf.ReadOnlyData()); err != nil {
- return nil, 0, wrapErr(err)
+ return nil, compressionNone, wrapErr(err)
}
}
return out, compressionMade, nil
@@ -971,7 +985,20 @@ func recvAndDecompress(p *parser, s recvCompressor, dc Decompressor, maxReceiveM
func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompressor, maxReceiveMessageSize int, pool mem.BufferPool) (mem.BufferSlice, error) {
if dc != nil {
r := d.Reader()
- uncompressed, err := dc.Do(r)
+ // For the built-in gzip decompressor, bound the decompressed output
+ // at maxReceiveMessageSize+1 so that a small but highly compressed
+ // payload (a "zip bomb") cannot expand to gigabytes in memory before
+ // the post-decompression size check below has a chance to fire. The
+ // Decompressor interface does not accept an extra size parameter,
+ // so we type-assert to invoke a size-aware helper. Third-party
+ // Decompressor implementations keep the original Do behavior.
+ var uncompressed []byte
+ var err error
+ if gd, ok := dc.(*gzipDecompressor); ok {
+ uncompressed, err = gd.doWithMaxSize(r, int64(maxReceiveMessageSize))
+ } else {
+ uncompressed, err = dc.Do(r)
+ }
if err != nil {
r.Close() // ensure buffers are reused
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err)
@@ -989,6 +1016,9 @@ func decompress(compressor encoding.Compressor, d mem.BufferSlice, dc Decompress
r.Close() // ensure buffers are reused
return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", err)
}
+ if closer, ok := dcReader.(io.Closer); ok {
+ defer closer.Close()
+ }
// Read at most one byte more than the limit from the decompressor.
// Unless the limit is MaxInt64, in which case, that's impossible, so
diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go
index 5229adf..4ab5411 100644
--- a/vendor/google.golang.org/grpc/server.go
+++ b/vendor/google.golang.org/grpc/server.go
@@ -28,6 +28,7 @@ import (
"net/http"
"reflect"
"runtime"
+ "runtime/pprof"
"strings"
"sync"
"sync/atomic"
@@ -88,6 +89,7 @@ func init() {
internal.MetricsRecorderForServer = func(srv *Server) estats.MetricsRecorder {
return istats.NewMetricsRecorderList(srv.opts.statsHandlers)
}
+ internal.XDSFilterWrapperOption = xdsFilterWrapperOption
}
var statusOK = status.New(codes.OK, "")
@@ -116,10 +118,8 @@ type ServiceDesc struct {
// serviceInfo wraps information about a service. It is very similar to
// ServiceDesc and is constructed from it for internal purposes.
type serviceInfo struct {
- // Contains the implementation for the methods in this service.
- serviceImpl any
- methods map[string]*MethodDesc
- streams map[string]*StreamDesc
+ serviceImpl any // Implementation for the methods in this service.
+ streams map[string]*StreamDesc // Streaming descriptors and wrapped unary descriptors for this service.
mdata any
}
@@ -150,8 +150,6 @@ type Server struct {
serverWorkerChannel chan func()
serverWorkerChannelClose func()
-
- strictPathCheckingLogEmitted atomic.Bool
}
type serverOptions struct {
@@ -184,6 +182,7 @@ type serverOptions struct {
bufferPool mem.BufferPool
waitForHandlers bool
staticWindowSize bool
+ streamWrapper func(ServerStream) (ServerStream, error)
}
var defaultServerOptions = serverOptions{
@@ -250,10 +249,8 @@ func newJoinServerOption(opts ...ServerOption) ServerOption {
// If this option is set to true every connection will release the buffer after
// flushing the data on the wire.
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a
-// later release.
+// Deprecated: shared write buffer is enabled by default. SharedWriteBuffer
+// will be removed in a future release.
func SharedWriteBuffer(val bool) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.sharedWriteBuffer = val
@@ -302,6 +299,14 @@ func InitialConnWindowSize(s int32) ServerOption {
// window size to the value provided and disables dynamic flow control.
// The lower bound for window size is 64K and any value smaller than that
// will be ignored.
+//
+// Note that this also disables dynamic flow control for the connection,
+// falling back to a default static connection-level window of 64KB. To
+// use a larger connection-level window, you must also use the
+// [StaticConnWindowSize] ServerOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func StaticStreamWindowSize(s int32) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.initialWindowSize = s
@@ -313,6 +318,14 @@ func StaticStreamWindowSize(s int32) ServerOption {
// window size to the value provided and disables dynamic flow control.
// The lower bound for window size is 64K and any value smaller than that
// will be ignored.
+//
+// Note that this also disables dynamic flow control for individual streams,
+// falling back to a default static connection-level window of 64KB. To
+// explicitly configure the stream-level window size, you must also use the
+// [StaticStreamWindowSize] ServerOption.
+//
+// Most users should not configure static flow control windows unless
+// operating in a memory-constrained environment.
func StaticConnWindowSize(s int32) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.initialConnWindowSize = s
@@ -650,6 +663,14 @@ func bufferPool(bufferPool mem.BufferPool) ServerOption {
})
}
+// xdsFilterWrapperOption returns a ServerOption that sets the server-level
+// stream wrapper (used internally by xDS server filters).
+func xdsFilterWrapperOption(w func(ServerStream) (ServerStream, error)) ServerOption {
+ return newFuncServerOption(func(o *serverOptions) {
+ o.streamWrapper = w
+ })
+}
+
// serverWorkerResetThreshold defines how often the stack must be reset. Every
// N requests, by spawning a new goroutine in its place, a worker can reset its
// stack so that large stacks don't live in memory forever. 2^16 should allow
@@ -777,18 +798,22 @@ func (s *Server) register(sd *ServiceDesc, ss any) {
}
info := &serviceInfo{
serviceImpl: ss,
- methods: make(map[string]*MethodDesc),
streams: make(map[string]*StreamDesc),
mdata: sd.Metadata,
}
- for i := range sd.Methods {
- d := &sd.Methods[i]
- info.methods[d.MethodName] = d
- }
for i := range sd.Streams {
d := &sd.Streams[i]
info.streams[d.StreamName] = d
}
+ for i := range sd.Methods {
+ d := &sd.Methods[i]
+ info.streams[d.MethodName] = &StreamDesc{
+ StreamName: d.MethodName,
+ Handler: s.wrapUnaryHandler(d),
+ ServerStreams: false,
+ ClientStreams: false,
+ }
+ }
s.services[sd.ServiceName] = info
}
@@ -814,20 +839,26 @@ type ServiceInfo struct {
func (s *Server) GetServiceInfo() map[string]ServiceInfo {
ret := make(map[string]ServiceInfo)
for n, srv := range s.services {
- methods := make([]MethodInfo, 0, len(srv.methods)+len(srv.streams))
- for m := range srv.methods {
- methods = append(methods, MethodInfo{
- Name: m,
- IsClientStream: false,
- IsServerStream: false,
- })
+ methods := make([]MethodInfo, 0, len(srv.streams))
+ // Iterate over unary methods first to maintain backward compatibility of order.
+ for m, d := range srv.streams {
+ if !d.ClientStreams && !d.ServerStreams {
+ methods = append(methods, MethodInfo{
+ Name: m,
+ IsClientStream: false,
+ IsServerStream: false,
+ })
+ }
}
+ // Iterate over streaming methods.
for m, d := range srv.streams {
- methods = append(methods, MethodInfo{
- Name: m,
- IsClientStream: d.ClientStreams,
- IsServerStream: d.ServerStreams,
- })
+ if d.ClientStreams || d.ServerStreams {
+ methods = append(methods, MethodInfo{
+ Name: m,
+ IsClientStream: d.ClientStreams,
+ IsServerStream: d.ServerStreams,
+ })
+ }
}
ret[n] = ServiceInfo{
@@ -1172,42 +1203,6 @@ func (s *Server) incrCallsFailed() {
s.channelz.ServerMetrics.CallsFailed.Add(1)
}
-func (s *Server) sendResponse(ctx context.Context, stream *transport.ServerStream, msg any, cp Compressor, opts *transport.WriteOptions, comp encoding.Compressor) error {
- data, err := encode(s.getCodec(stream.ContentSubtype()), msg)
- if err != nil {
- channelz.Error(logger, s.channelz, "grpc: server failed to encode response: ", err)
- return err
- }
-
- compData, pf, err := compress(data, cp, comp, s.opts.bufferPool)
- if err != nil {
- data.Free()
- channelz.Error(logger, s.channelz, "grpc: server failed to compress response: ", err)
- return err
- }
-
- hdr, payload := msgHeader(data, compData, pf)
-
- defer func() {
- compData.Free()
- data.Free()
- // payload does not need to be freed here, it is either data or compData, both of
- // which are already freed.
- }()
-
- dataLen := data.Len()
- payloadLen := payload.Len()
- // TODO(dfawley): should we be checking len(data) instead?
- if payloadLen > s.opts.maxSendMessageSize {
- return status.Errorf(codes.ResourceExhausted, "grpc: trying to send message larger than max (%d vs. %d)", payloadLen, s.opts.maxSendMessageSize)
- }
- err = stream.Write(hdr, payload, opts)
- if err == nil && s.statsHandler != nil {
- s.statsHandler.HandleRPC(ctx, outPayload(false, msg, dataLen, payloadLen, time.Now()))
- }
- return err
-}
-
// chainUnaryServerInterceptors chains all unary server interceptors into one.
func chainUnaryServerInterceptors(s *Server) {
// Prepend opts.unaryInt to the chaining interceptors if it exists, since unaryInt will
@@ -1244,300 +1239,6 @@ func getChainUnaryHandler(interceptors []UnaryServerInterceptor, curr int, info
}
}
-func (s *Server) processUnaryRPC(ctx context.Context, stream *transport.ServerStream, info *serviceInfo, md *MethodDesc, trInfo *traceInfo) (err error) {
- sh := s.statsHandler
- if sh != nil || trInfo != nil || channelz.IsOn() {
- if channelz.IsOn() {
- s.incrCallsStarted()
- }
- var statsBegin *stats.Begin
- if sh != nil {
- statsBegin = &stats.Begin{
- BeginTime: time.Now(),
- IsClientStream: false,
- IsServerStream: false,
- }
- sh.HandleRPC(ctx, statsBegin)
- }
- if trInfo != nil {
- trInfo.tr.LazyLog(&trInfo.firstLine, false)
- }
- // The deferred error handling for tracing, stats handler and channelz are
- // combined into one function to reduce stack usage -- a defer takes ~56-64
- // bytes on the stack, so overflowing the stack will require a stack
- // re-allocation, which is expensive.
- //
- // To maintain behavior similar to separate deferred statements, statements
- // should be executed in the reverse order. That is, tracing first, stats
- // handler second, and channelz last. Note that panics *within* defers will
- // lead to different behavior, but that's an acceptable compromise; that
- // would be undefined behavior territory anyway.
- defer func() {
- if trInfo != nil {
- if err != nil && err != io.EOF {
- trInfo.tr.LazyLog(&fmtStringer{"%v", []any{err}}, true)
- trInfo.tr.SetError()
- }
- trInfo.tr.Finish()
- }
-
- if sh != nil {
- end := &stats.End{
- BeginTime: statsBegin.BeginTime,
- EndTime: time.Now(),
- }
- if err != nil && err != io.EOF {
- end.Error = toRPCErr(err)
- }
- sh.HandleRPC(ctx, end)
- }
-
- if channelz.IsOn() {
- if err != nil && err != io.EOF {
- s.incrCallsFailed()
- } else {
- s.incrCallsSucceeded()
- }
- }
- }()
- }
- var binlogs []binarylog.MethodLogger
- if ml := binarylog.GetMethodLogger(stream.Method()); ml != nil {
- binlogs = append(binlogs, ml)
- }
- if s.opts.binaryLogger != nil {
- if ml := s.opts.binaryLogger.GetMethodLogger(stream.Method()); ml != nil {
- binlogs = append(binlogs, ml)
- }
- }
- if len(binlogs) != 0 {
- md, _ := metadata.FromIncomingContext(ctx)
- logEntry := &binarylog.ClientHeader{
- Header: md,
- MethodName: stream.Method(),
- PeerAddr: nil,
- }
- if deadline, ok := ctx.Deadline(); ok {
- logEntry.Timeout = time.Until(deadline)
- if logEntry.Timeout < 0 {
- logEntry.Timeout = 0
- }
- }
- if a := md[":authority"]; len(a) > 0 {
- logEntry.Authority = a[0]
- }
- if peer, ok := peer.FromContext(ctx); ok {
- logEntry.PeerAddr = peer.Addr
- }
- for _, binlog := range binlogs {
- binlog.Log(ctx, logEntry)
- }
- }
-
- // comp and cp are used for compression. decomp and dc are used for
- // decompression. If comp and decomp are both set, they are the same;
- // however they are kept separate to ensure that at most one of the
- // compressor/decompressor variable pairs are set for use later.
- var comp, decomp encoding.Compressor
- var cp Compressor
- var dc Decompressor
- var sendCompressorName string
-
- // If dc is set and matches the stream's compression, use it. Otherwise, try
- // to find a matching registered compressor for decomp.
- if rc := stream.RecvCompress(); s.opts.dc != nil && s.opts.dc.Type() == rc {
- dc = s.opts.dc
- } else if rc != "" && rc != encoding.Identity {
- decomp = encoding.GetCompressor(rc)
- if decomp == nil {
- st := status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", rc)
- stream.WriteStatus(st)
- return st.Err()
- }
- }
-
- // If cp is set, use it. Otherwise, attempt to compress the response using
- // the incoming message compression method.
- //
- // NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686.
- if s.opts.cp != nil {
- cp = s.opts.cp
- sendCompressorName = cp.Type()
- } else if rc := stream.RecvCompress(); rc != "" && rc != encoding.Identity {
- // Legacy compressor not specified; attempt to respond with same encoding.
- comp = encoding.GetCompressor(rc)
- if comp != nil {
- sendCompressorName = comp.Name()
- }
- }
-
- if sendCompressorName != "" {
- if err := stream.SetSendCompress(sendCompressorName); err != nil {
- return status.Errorf(codes.Internal, "grpc: failed to set send compressor: %v", err)
- }
- }
-
- var payInfo *payloadInfo
- if sh != nil || len(binlogs) != 0 {
- payInfo = &payloadInfo{}
- defer payInfo.free()
- }
-
- d, err := recvAndDecompress(&parser{r: stream, bufferPool: s.opts.bufferPool}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp, true)
- if err != nil {
- if e := stream.WriteStatus(status.Convert(err)); e != nil {
- channelz.Warningf(logger, s.channelz, "grpc: Server.processUnaryRPC failed to write status: %v", e)
- }
- return err
- }
- freed := false
- dataFree := func() {
- if !freed {
- d.Free()
- freed = true
- }
- }
- defer dataFree()
- df := func(v any) error {
- defer dataFree()
- if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil {
- return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err)
- }
-
- if sh != nil {
- sh.HandleRPC(ctx, &stats.InPayload{
- RecvTime: time.Now(),
- Payload: v,
- Length: d.Len(),
- WireLength: payInfo.compressedLength + headerLen,
- CompressedLength: payInfo.compressedLength,
- })
- }
- if len(binlogs) != 0 {
- cm := &binarylog.ClientMessage{
- Message: d.Materialize(),
- }
- for _, binlog := range binlogs {
- binlog.Log(ctx, cm)
- }
- }
- if trInfo != nil {
- trInfo.tr.LazyLog(&payload{sent: false, msg: v}, true)
- }
- return nil
- }
- ctx = NewContextWithServerTransportStream(ctx, stream)
- reply, appErr := md.Handler(info.serviceImpl, ctx, df, s.opts.unaryInt)
- if appErr != nil {
- appStatus, ok := status.FromError(appErr)
- if !ok {
- // Convert non-status application error to a status error with code
- // Unknown, but handle context errors specifically.
- appStatus = status.FromContextError(appErr)
- appErr = appStatus.Err()
- }
- if trInfo != nil {
- trInfo.tr.LazyLog(stringer(appStatus.Message()), true)
- trInfo.tr.SetError()
- }
- if e := stream.WriteStatus(appStatus); e != nil {
- channelz.Warningf(logger, s.channelz, "grpc: Server.processUnaryRPC failed to write status: %v", e)
- }
- if len(binlogs) != 0 {
- if h, _ := stream.Header(); h.Len() > 0 {
- // Only log serverHeader if there was header. Otherwise it can
- // be trailer only.
- sh := &binarylog.ServerHeader{
- Header: h,
- }
- for _, binlog := range binlogs {
- binlog.Log(ctx, sh)
- }
- }
- st := &binarylog.ServerTrailer{
- Trailer: stream.Trailer(),
- Err: appErr,
- }
- for _, binlog := range binlogs {
- binlog.Log(ctx, st)
- }
- }
- return appErr
- }
- if trInfo != nil {
- trInfo.tr.LazyLog(stringer("OK"), false)
- }
- opts := &transport.WriteOptions{Last: true}
-
- // Server handler could have set new compressor by calling SetSendCompressor.
- // In case it is set, we need to use it for compressing outbound message.
- if stream.SendCompress() != sendCompressorName {
- comp = encoding.GetCompressor(stream.SendCompress())
- }
- if err := s.sendResponse(ctx, stream, reply, cp, opts, comp); err != nil {
- if err == io.EOF {
- // The entire stream is done (for unary RPC only).
- return err
- }
- if sts, ok := status.FromError(err); ok {
- if e := stream.WriteStatus(sts); e != nil {
- channelz.Warningf(logger, s.channelz, "grpc: Server.processUnaryRPC failed to write status: %v", e)
- }
- } else {
- switch st := err.(type) {
- case transport.ConnectionError:
- // Nothing to do here.
- default:
- panic(fmt.Sprintf("grpc: Unexpected error (%T) from sendResponse: %v", st, st))
- }
- }
- if len(binlogs) != 0 {
- h, _ := stream.Header()
- sh := &binarylog.ServerHeader{
- Header: h,
- }
- st := &binarylog.ServerTrailer{
- Trailer: stream.Trailer(),
- Err: appErr,
- }
- for _, binlog := range binlogs {
- binlog.Log(ctx, sh)
- binlog.Log(ctx, st)
- }
- }
- return err
- }
- if len(binlogs) != 0 {
- h, _ := stream.Header()
- sh := &binarylog.ServerHeader{
- Header: h,
- }
- sm := &binarylog.ServerMessage{
- Message: reply,
- }
- for _, binlog := range binlogs {
- binlog.Log(ctx, sh)
- binlog.Log(ctx, sm)
- }
- }
- if trInfo != nil {
- trInfo.tr.LazyLog(&payload{sent: true, msg: reply}, true)
- }
- // TODO: Should we be logging if writing status failed here, like above?
- // Should the logging be in WriteStatus? Should we ignore the WriteStatus
- // error or allow the stats handler to see it?
- if len(binlogs) != 0 {
- st := &binarylog.ServerTrailer{
- Trailer: stream.Trailer(),
- Err: appErr,
- }
- for _, binlog := range binlogs {
- binlog.Log(ctx, st)
- }
- }
- return stream.WriteStatus(statusOK)
-}
-
// chainStreamServerInterceptors chains all stream server interceptors into one.
func chainStreamServerInterceptors(s *Server) {
// Prepend opts.streamInt to the chaining interceptors if it exists, since streamInt will
@@ -1574,7 +1275,21 @@ func getChainStreamHandler(interceptors []StreamServerInterceptor, curr int, inf
}
}
-func (s *Server) processStreamingRPC(ctx context.Context, stream *transport.ServerStream, info *serviceInfo, sd *StreamDesc, trInfo *traceInfo) (err error) {
+// wrapUnaryHandler converts a standard Unary Method Descriptor into a
+// StreamHandler, allowing Unary RPCs to be processed via the same unified
+// pipeline as Streaming RPCs.
+func (s *Server) wrapUnaryHandler(md *MethodDesc) StreamHandler {
+ return func(srv any, stream ServerStream) error {
+ df := func(v any) error { return stream.RecvMsg(v) }
+ reply, err := md.Handler(srv, stream.Context(), df, s.opts.unaryInt)
+ if err != nil {
+ return err
+ }
+ return stream.SendMsg(reply)
+ }
+}
+
+func (s *Server) processRPC(ctx context.Context, stream *transport.ServerStream, info *serviceInfo, sd *StreamDesc, trInfo *traceInfo) (err error) {
if channelz.IsOn() {
s.incrCallsStarted()
}
@@ -1602,7 +1317,16 @@ func (s *Server) processStreamingRPC(ctx context.Context, stream *transport.Serv
}
if sh != nil || trInfo != nil || channelz.IsOn() {
- // See comment in processUnaryRPC on defers.
+ // The deferred error handling for tracing, stats handler and channelz are
+ // combined into one function to reduce stack usage -- a defer takes ~56-64
+ // bytes on the stack, so overflowing the stack will require a stack
+ // re-allocation, which is expensive.
+ //
+ // To maintain behavior similar to separate deferred statements, statements
+ // should be executed in the reverse order. That is, tracing first, stats
+ // handler second, and channelz last. Note that panics *within* defers will
+ // lead to different behavior, but that's an acceptable compromise; that
+ // would be undefined behavior territory anyway.
defer func() {
if trInfo != nil {
ss.mu.Lock()
@@ -1676,7 +1400,7 @@ func (s *Server) processStreamingRPC(ctx context.Context, stream *transport.Serv
ss.decompressorV1 = encoding.GetCompressor(rc)
if ss.decompressorV1 == nil {
st := status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", rc)
- ss.s.WriteStatus(st)
+ ss.writeStatus(st)
return st.Err()
}
}
@@ -1704,23 +1428,34 @@ func (s *Server) processStreamingRPC(ctx context.Context, stream *transport.Serv
ss.ctx = newContextWithRPCInfo(ss.ctx, false, ss.codec, ss.compressorV0, ss.compressorV1)
- if trInfo != nil {
- trInfo.tr.LazyLog(&trInfo.firstLine, false)
- }
+ // Execute the xDS HTTP filter interceptors.
var appErr error
- var server any
- if info != nil {
- server = info.serviceImpl
+ var wrappedStream ServerStream = ss
+ if s.opts.streamWrapper != nil {
+ wrappedStream, appErr = s.opts.streamWrapper(ss)
}
- if s.opts.streamInt == nil {
- appErr = sd.Handler(server, ss)
- } else {
- info := &StreamServerInfo{
- FullMethod: stream.Method(),
- IsClientStream: sd.ClientStreams,
- IsServerStream: sd.ServerStreams,
+
+ if appErr == nil {
+ if trInfo != nil {
+ trInfo.tr.LazyLog(&trInfo.firstLine, false)
+ }
+ var server any
+ if info != nil {
+ server = info.serviceImpl
+ }
+ if s.opts.streamInt == nil || (!sd.ClientStreams && !sd.ServerStreams) {
+ // If there is no stream interceptor, or if this is a unary RPC, call
+ // the handler directly. The wrapped unary handler will call the unary
+ // interceptor if it exists.
+ appErr = sd.Handler(server, wrappedStream)
+ } else {
+ info := &StreamServerInfo{
+ FullMethod: stream.Method(),
+ IsClientStream: sd.ClientStreams,
+ IsServerStream: sd.ServerStreams,
+ }
+ appErr = s.opts.streamInt(server, wrappedStream, info, sd.Handler)
}
- appErr = s.opts.streamInt(server, ss, info, sd.Handler)
}
if appErr != nil {
appStatus, ok := status.FromError(appErr)
@@ -1737,6 +1472,17 @@ func (s *Server) processStreamingRPC(ctx context.Context, stream *transport.Serv
ss.mu.Unlock()
}
if len(ss.binlogs) != 0 {
+ if !ss.serverHeaderBinlogged {
+ if h, _ := ss.s.Header(); h.Len() > 0 {
+ sh := &binarylog.ServerHeader{
+ Header: h,
+ }
+ ss.serverHeaderBinlogged = true
+ for _, binlog := range ss.binlogs {
+ binlog.Log(ctx, sh)
+ }
+ }
+ }
st := &binarylog.ServerTrailer{
Trailer: ss.s.Trailer(),
Err: appErr,
@@ -1745,8 +1491,9 @@ func (s *Server) processStreamingRPC(ctx context.Context, stream *transport.Serv
binlog.Log(ctx, st)
}
}
- ss.s.WriteStatus(appStatus)
- // TODO: Should we log an error from WriteStatus here and below?
+ if err := ss.writeStatus(appStatus); err != nil {
+ channelz.Warningf(logger, s.channelz, "grpc: Server.processRPC failed to write status: %v", err)
+ }
return appErr
}
if trInfo != nil {
@@ -1763,7 +1510,10 @@ func (s *Server) processStreamingRPC(ctx context.Context, stream *transport.Serv
binlog.Log(ctx, st)
}
}
- return ss.s.WriteStatus(statusOK)
+ if err := ss.writeStatus(statusOK); err != nil {
+ channelz.Warningf(logger, s.channelz, "grpc: Server.processRPC failed to write status: %v", err)
+ }
+ return err
}
func (s *Server) handleMalformedMethodName(stream *transport.ServerStream, ti *traceInfo) {
@@ -1787,6 +1537,12 @@ func (s *Server) handleMalformedMethodName(stream *transport.ServerStream, ti *t
func (s *Server) handleStream(t transport.ServerTransport, stream *transport.ServerStream) {
ctx := stream.Context()
ctx = contextWithServer(ctx, s)
+ if envconfig.LabelServerGoroutines&envconfig.GoroutineLabelServerMethod != 0 {
+ // This method always runs in its own goroutine, so we can set a
+ // goroutine label without needing to restore a previous context.
+ ctx = pprof.WithLabels(ctx, pprof.Labels("grpc.method", stream.Method()))
+ pprof.SetGoroutineLabels(ctx)
+ }
var ti *traceInfo
if EnableTracing {
tr := newTrace("grpc.Recv."+methodFamily(stream.Method()), stream.Method())
@@ -1803,28 +1559,11 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Ser
}
}
- sm := stream.Method()
- if sm == "" {
+ sm, found := strings.CutPrefix(stream.Method(), "/")
+ if !found {
s.handleMalformedMethodName(stream, ti)
return
}
- if sm[0] != '/' {
- // TODO(easwars): Add a link to the CVE in the below log messages once
- // published.
- if envconfig.DisableStrictPathChecking {
- if old := s.strictPathCheckingLogEmitted.Swap(true); !old {
- channelz.Warningf(logger, s.channelz, "grpc: Server.handleStream received malformed method name %q. Allowing it because the environment variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING is set to true, but this option will be removed in a future release.", sm)
- }
- } else {
- if old := s.strictPathCheckingLogEmitted.Swap(true); !old {
- channelz.Warningf(logger, s.channelz, "grpc: Server.handleStream rejected malformed method name %q. To temporarily allow such requests, set the environment variable GRPC_GO_EXPERIMENTAL_DISABLE_STRICT_PATH_CHECKING to true. Note that this is not recommended as it may allow requests to bypass security policies.", sm)
- }
- s.handleMalformedMethodName(stream, ti)
- return
- }
- } else {
- sm = sm[1:]
- }
pos := strings.LastIndex(sm, "/")
if pos == -1 {
s.handleMalformedMethodName(stream, ti)
@@ -1852,18 +1591,14 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Ser
srv, knownService := s.services[service]
if knownService {
- if md, ok := srv.methods[method]; ok {
- s.processUnaryRPC(ctx, stream, srv, md, ti)
- return
- }
if sd, ok := srv.streams[method]; ok {
- s.processStreamingRPC(ctx, stream, srv, sd, ti)
+ s.processRPC(ctx, stream, srv, sd, ti)
return
}
}
// Unknown service, or known server unknown method.
if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil {
- s.processStreamingRPC(ctx, stream, nil, unknownDesc, ti)
+ s.processRPC(ctx, stream, nil, unknownDesc, ti)
return
}
var errDesc string
@@ -2067,9 +1802,6 @@ func (s *Server) isRegisteredMethod(serviceMethod string) bool {
method := serviceMethod[pos+1:]
srv, knownService := s.services[service]
if knownService {
- if _, ok := srv.methods[method]; ok {
- return true
- }
if _, ok := srv.streams[method]; ok {
return true
}
diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go
index 4aac644..52e59f2 100644
--- a/vendor/google.golang.org/grpc/stream.go
+++ b/vendor/google.golang.org/grpc/stream.go
@@ -28,6 +28,7 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
"google.golang.org/grpc/balancer"
@@ -148,6 +149,94 @@ type ClientStream interface {
RecvMsg(m any) error
}
+// clientStreamWrapper wraps a ClientStream and handles SendMsg, CloseSend, and
+// RecvMsg parities based on the nature of stream.
+type clientStreamWrapper struct {
+ ClientStream
+ desc *StreamDesc
+ closeSendCalled atomic.Bool
+}
+
+// CloseSend closes the send direction of the stream. The implementation ensures
+// that CloseSend is only called once on the underlying ClientStream, even if
+// CloseSend is called multiple times on the wrapper.
+func (w *clientStreamWrapper) CloseSend() error {
+ if w.closeSendCalled.Swap(true) {
+ return nil
+ }
+ return w.ClientStream.CloseSend()
+}
+
+// SendMsg sends message m across the stream. For RPCs where client can call
+// SendMsg only once, i.e. only server-streaming RPCs, it converts io.EOF to nil
+// and immediately calls CloseSend to trigger any interceptor hooks.
+func (w *clientStreamWrapper) SendMsg(m any) error {
+ err := w.ClientStream.SendMsg(m)
+ // If the RPC is a client-streaming RPC, the client can send multiple
+ // messages. In this case, the client should handle any type of
+ // error,including io.EOF and call CloseSend once it is done sending messages.
+ if w.desc.ClientStreams {
+ return err
+ }
+
+ if err == io.EOF {
+ // For non-client-streaming RPCs, we return nil instead of EOF on error
+ // because the generated code requires it. finish is not called; RecvMsg()
+ // will call it with the stream's status independently.
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ // In some scenarios (e.g., xDS), the same interceptors process both unary and
+ // streaming RPCs, relying on CloseSend to signal that no more messages are on
+ // the way. Although protobuf-generated stubs already invoke CloseSend for
+ // server-streaming RPCs, it is explicitly called here to ensure downstream
+ // interceptors are also notified when callers interact with the ClientStream
+ // API directly.
+ if err := w.CloseSend(); err != nil && err != io.EOF {
+ return err
+ }
+ return nil
+
+}
+
+// RecvMsg receives message m from the stream. For RPCs that call RecvMsg only
+// once i.e. only client streaming RPCs, it calls the underlying RecvMsg a
+// second time after receiving the first message to get the trailers.
+func (w *clientStreamWrapper) RecvMsg(m any) error {
+ err := w.ClientStream.RecvMsg(m)
+ if err != nil {
+ return err
+ }
+ if w.desc.ServerStreams {
+ return nil
+ }
+ // Call RecvMsg again for non-server streaming RPCs to get the trailers and
+ // ensure RPC has completed successfully.
+ err = w.ClientStream.RecvMsg(m)
+ if err == io.EOF {
+ return nil
+ }
+ if err == nil {
+ return status.Error(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message")
+ }
+ return err
+}
+
+// defaultStreamInterceptor is a StreamClientInterceptor which wraps the
+// ClientStream and is always invoked as the first interceptor. It consolidates
+// behavior for different RPC types at the level closest to the application,
+// which simplifies the underlying stream implementation and other interceptors
+// by avoiding duplicate or scattered handling.
+func defaultStreamInterceptor(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, streamer Streamer, opts ...CallOption) (ClientStream, error) {
+ cs, err := streamer(ctx, desc, cc, method, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &clientStreamWrapper{ClientStream: cs, desc: desc}, nil
+}
+
// NewStream creates a new Stream for the client side. This is typically
// called by generated code. ctx is used for the lifetime of the stream.
//
@@ -201,6 +290,15 @@ func endOfClientStream(cc *ClientConn, err error, opts ...CallOption) {
}
}
+// clientInterceptor is structurally identical to the ClientInterceptor defined
+// in internal/xds/httpfilter/httpfilter.go. It is defined locally here so that
+// we can type-assert the generic Interceptor field in iresolver.RPCConfig
+// without introducing a dependency on xDS packages.
+type clientInterceptor interface {
+ NewStream(ctx context.Context, ri iresolver.RPCInfo, newStream func(ctx context.Context, opts ...CallOption) (ClientStream, error), opts ...CallOption) (ClientStream, error)
+ Close()
+}
+
func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) {
if channelz.IsOn() {
cc.incrCallsStarted()
@@ -244,11 +342,11 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
mc := &emptyMethodConfig
var onCommit func()
- newStream := func(ctx context.Context, done func()) (iresolver.ClientStream, error) {
- return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, done, nameResolutionDelayed, opts...)
+ newStream := func(ctx context.Context, opts ...CallOption) (ClientStream, error) {
+ return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, nameResolutionDelayed, opts...)
}
- rpcInfo := iresolver.RPCInfo{Context: ctx, Method: method}
+ rpcInfo := iresolver.RPCInfo{Context: ctx, Method: method, Authority: cc.authority}
rpcConfig, err := cc.safeConfigSelector.SelectConfig(rpcInfo)
if err != nil {
if st, ok := status.FromError(err); ok {
@@ -266,24 +364,38 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
ctx = rpcConfig.Context
}
mc = &rpcConfig.MethodConfig
- onCommit = rpcConfig.OnCommitted
+
+ if rpcConfig.OnCommitted != nil {
+ onCommit = rpcConfig.OnCommitted
+ // Register an OnFinish CallOption with the OnCommitted callback to
+ // ensure it is invoked on stream termination, even if the stream
+ // fails early before committing. Implementations of OnCommitted are
+ // expected to be idempotent (e.g., guarded by sync.Once), since both
+ // onCommit and OnFinish may run for a single RPC.
+ opts = append(opts, OnFinish(func(error) { rpcConfig.OnCommitted() }))
+ }
+
if rpcConfig.Interceptor != nil {
rpcInfo.Context = nil
ns := newStream
- newStream = func(ctx context.Context, done func()) (iresolver.ClientStream, error) {
- cs, err := rpcConfig.Interceptor.NewStream(ctx, rpcInfo, done, ns)
- if err != nil {
- return nil, toRPCErr(err)
+ if interceptor, ok := rpcConfig.Interceptor.(clientInterceptor); ok {
+ newStream = func(ctx context.Context, opts ...CallOption) (ClientStream, error) {
+ cs, err := interceptor.NewStream(ctx, rpcInfo, ns, opts...)
+ if err != nil {
+ return nil, toRPCErr(err)
+ }
+ return cs, nil
}
- return cs, nil
+ } else {
+ return nil, status.Errorf(codes.Internal, "invalid client interceptor type %T", rpcConfig.Interceptor)
}
}
}
- return newStream(ctx, func() {})
+ return newStream(ctx, opts...)
}
-func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit, doneFunc func(), nameResolutionDelayed bool, opts ...CallOption) (_ iresolver.ClientStream, err error) {
+func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit func(), nameResolutionDelayed bool, opts ...CallOption) (_ ClientStream, err error) {
callInfo := defaultCallInfo()
if mc.WaitForReady != nil {
callInfo.failFast = !*mc.WaitForReady
@@ -321,7 +433,6 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client
Host: cc.authority,
Method: method,
ContentSubtype: callInfo.contentSubtype,
- DoneFunc: doneFunc,
Authority: callInfo.authority,
}
if allowed := callInfo.acceptedResponseCompressors; len(allowed) > 0 {
@@ -528,6 +639,9 @@ func (a *csAttempt) newStream() error {
// maintained in it are local to the attempt. When the attempt has to be
// retried, a new instance of csAttempt will be created.
if a.pickResult.Metadata != nil {
+ if err := imetadata.Validate(a.pickResult.Metadata); err != nil {
+ return status.Error(codes.Internal, err.Error())
+ }
// We currently do not have a function it the metadata package which
// merges given metadata with existing metadata in a context. Existing
// function `AppendToOutgoingContext()` takes a variadic argument of key
@@ -1029,8 +1143,8 @@ func (cs *clientStream) RecvMsg(m any) error {
binlog.Log(cs.ctx, sm)
}
}
- if err != nil || !cs.desc.ServerStreams {
- // err != nil or non-server-streaming indicates end of stream.
+ if err != nil {
+ // err != nil indicates end of stream.
cs.finish(err)
}
return err
@@ -1078,7 +1192,8 @@ func (cs *clientStream) finish(err error) {
}
cs.finished = true
cs.commitAttemptLocked()
- if cs.attempt != nil {
+ attemptCreated := cs.attempt != nil
+ if attemptCreated {
cs.attempt.finish(err)
// after functions all rely upon having a stream.
if cs.attempt.transportStream != nil {
@@ -1116,7 +1231,13 @@ func (cs *clientStream) finish(err error) {
if err == nil {
cs.retryThrottler.successfulRPC()
}
- endOfClientStream(cs.cc, err, cs.opts...)
+ // If no attempt was ever created, stream creation has failed, and the
+ // cleanup is left to newClientStream, whose deferred cleanup invokes
+ // endOfClientStream if the call fails. Invoking it here as well would
+ // run the cleanup twice for the same call.
+ if attemptCreated {
+ endOfClientStream(cs.cc, err, cs.opts...)
+ }
cs.cancel()
}
@@ -1130,12 +1251,6 @@ func (a *csAttempt) sendMsg(m any, hdr []byte, payld mem.BufferSlice, dataLength
a.mu.Unlock()
}
if err := a.transportStream.Write(hdr, payld, &transport.WriteOptions{Last: !cs.desc.ClientStreams}); err != nil {
- if !cs.desc.ClientStreams {
- // For non-client-streaming RPCs, we return nil instead of EOF on error
- // because the generated code requires it. finish is not called; RecvMsg()
- // will call it with the stream's status independently.
- return nil
- }
return io.EOF
}
if a.statsHandler != nil {
@@ -1203,18 +1318,7 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
Length: payInfo.uncompressedBytes.Len(),
})
}
- if cs.desc.ServerStreams {
- // Subsequent messages should be received by subsequent RecvMsg calls.
- return nil
- }
- // Special handling for non-server-stream rpcs.
- // This recv expects EOF or errors, so we don't collect inPayload.
- if err := recv(&a.parser, cs.codec, a.transportStream, a.decompressorV0, m, *cs.callInfo.maxReceiveMessageSize, nil, a.decompressorV1, false); err == io.EOF {
- return a.transportStream.Status().Err() // non-server streaming Recv returns nil on success
- } else if err != nil {
- return toRPCErr(err)
- }
- return status.Error(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message")
+ return nil
}
func (a *csAttempt) finish(err error) {
@@ -1384,7 +1488,7 @@ func newNonRetryClientStream(ctx context.Context, desc *StreamDesc, method strin
}
}()
}
- return as, nil
+ return &clientStreamWrapper{ClientStream: as, desc: desc}, nil
}
type addrConnStream struct {
@@ -1482,12 +1586,6 @@ func (as *addrConnStream) SendMsg(m any) (err error) {
}
if err := as.transportStream.Write(hdr, payload, &transport.WriteOptions{Last: !as.desc.ClientStreams}); err != nil {
- if !as.desc.ClientStreams {
- // For non-client-streaming RPCs, we return nil instead of EOF on error
- // because the generated code requires it. finish is not called; RecvMsg()
- // will call it with the stream's status independently.
- return nil
- }
return io.EOF
}
@@ -1496,8 +1594,8 @@ func (as *addrConnStream) SendMsg(m any) (err error) {
func (as *addrConnStream) RecvMsg(m any) (err error) {
defer func() {
- if err != nil || !as.desc.ServerStreams {
- // err != nil or non-server-streaming indicates end of stream.
+ if err != nil {
+ // err != nil indicates end of stream.
as.finish(err)
}
}()
@@ -1536,20 +1634,7 @@ func (as *addrConnStream) RecvMsg(m any) (err error) {
return toRPCErr(err)
}
as.receivedFirstMsg = true
-
- if as.desc.ServerStreams {
- // Subsequent messages should be received by subsequent RecvMsg calls.
- return nil
- }
-
- // Special handling for non-server-stream rpcs.
- // This recv expects EOF or errors, so we don't collect inPayload.
- if err := recv(&as.parser, as.codec, as.transportStream, as.decompressorV0, m, *as.callInfo.maxReceiveMessageSize, nil, as.decompressorV1, false); err == io.EOF {
- return as.transportStream.Status().Err() // non-server streaming Recv returns nil on success
- } else if err != nil {
- return toRPCErr(err)
- }
- return status.Error(codes.Internal, "cardinality violation: expected for non server-streaming RPCs, but received another message")
+ return nil
}
func (as *addrConnStream) finish(err error) {
@@ -1660,6 +1745,8 @@ type serverStream struct {
// synchronized.
serverHeaderBinlogged bool
+ statusWritten atomic.Bool // True if status has been written to the transport.
+
mu sync.Mutex // protects trInfo.tr after the service handler runs.
}
@@ -1708,6 +1795,16 @@ func (ss *serverStream) SetTrailer(md metadata.MD) {
ss.s.SetTrailer(md)
}
+// writeStatus sends the status of a stream to the client. It uses an atomic
+// CAS to guarantee that the status is written to the transport exactly once,
+// even if called concurrently.
+func (ss *serverStream) writeStatus(st *status.Status) error {
+ if !ss.statusWritten.CompareAndSwap(false, true) {
+ return nil
+ }
+ return ss.s.WriteStatus(st)
+}
+
func (ss *serverStream) SendMsg(m any) (err error) {
defer func() {
if ss.trInfo != nil {
@@ -1724,7 +1821,7 @@ func (ss *serverStream) SendMsg(m any) (err error) {
}
if err != nil && err != io.EOF {
st, _ := status.FromError(toRPCErr(err))
- ss.s.WriteStatus(st)
+ ss.writeStatus(st)
// Non-user specified status was sent out. This should be an error
// case (as a server side Cancel maybe).
//
@@ -1807,7 +1904,7 @@ func (ss *serverStream) RecvMsg(m any) (err error) {
}
if err != nil && err != io.EOF {
st, _ := status.FromError(toRPCErr(err))
- ss.s.WriteStatus(st)
+ ss.writeStatus(st)
// Non-user specified status was sent out. This should be an error
// case (as a server side Cancel maybe).
//
diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go
index 3ccfe51..75f8ef5 100644
--- a/vendor/google.golang.org/grpc/version.go
+++ b/vendor/google.golang.org/grpc/version.go
@@ -19,4 +19,4 @@
package grpc
// Version is the current grpc version.
-const Version = "1.81.1"
+const Version = "1.84.0"
diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/decode.go b/vendor/google.golang.org/protobuf/encoding/protojson/decode.go
index 737d687..1d6608d 100644
--- a/vendor/google.golang.org/protobuf/encoding/protojson/decode.go
+++ b/vendor/google.golang.org/protobuf/encoding/protojson/decode.go
@@ -365,6 +365,10 @@ func unmarshalInt(tok json.Token, bitSize int) (protoreflect.Value, bool) {
if err != nil {
return protoreflect.Value{}, false
}
+ // Ensure there is no non-number content in this string.
+ if next, err := dec.Read(); err != nil || next.Kind() != json.EOF {
+ return protoreflect.Value{}, false
+ }
return getInt(tok, bitSize)
}
return protoreflect.Value{}, false
@@ -397,6 +401,10 @@ func unmarshalUint(tok json.Token, bitSize int) (protoreflect.Value, bool) {
if err != nil {
return protoreflect.Value{}, false
}
+ // Ensure there is no non-number content in this string.
+ if next, err := dec.Read(); err != nil || next.Kind() != json.EOF {
+ return protoreflect.Value{}, false
+ }
return getUint(tok, bitSize)
}
return protoreflect.Value{}, false
@@ -447,6 +455,10 @@ func unmarshalFloat(tok json.Token, bitSize int) (protoreflect.Value, bool) {
if err != nil {
return protoreflect.Value{}, false
}
+ // Ensure there is no non-number content in this string.
+ if next, err := dec.Read(); err != nil || next.Kind() != json.EOF {
+ return protoreflect.Value{}, false
+ }
return getFloat(tok, bitSize)
}
return protoreflect.Value{}, false
diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go b/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go
index e9fe103..d2eab46 100644
--- a/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go
+++ b/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go
@@ -52,7 +52,10 @@ func wellKnownTypeMarshaler(name protoreflect.FullName) marshalFunc {
case genid.FieldMask_message_name:
return encoder.marshalFieldMask
case genid.Empty_message_name:
- return encoder.marshalEmpty
+ // The spec explicitly specifies that the Empty message
+ // is not considered to have any special JSON mapping:
+ // https://protobuf.dev/programming-guides/json/#any
+ return nil
}
}
return nil
diff --git a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go
index b538050..20ec09e 100644
--- a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go
+++ b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go
@@ -8,6 +8,7 @@ import (
"fmt"
"unicode/utf8"
+ "google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/encoding/messageset"
"google.golang.org/protobuf/internal/encoding/text"
"google.golang.org/protobuf/internal/errors"
@@ -49,12 +50,19 @@ type UnmarshalOptions struct {
protoregistry.MessageTypeResolver
protoregistry.ExtensionTypeResolver
}
+
+ // RecursionLimit limits how deeply messages may be nested.
+ // If zero, a default limit is applied.
+ RecursionLimit int
}
// Unmarshal reads the given []byte and populates the given [proto.Message]
// using options in the UnmarshalOptions object.
// The provided message must be mutable (e.g., a non-nil pointer to a message).
func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error {
+ if o.RecursionLimit == 0 {
+ o.RecursionLimit = protowire.DefaultRecursionLimit
+ }
return o.unmarshal(b, m)
}
@@ -102,8 +110,14 @@ func (d decoder) syntaxError(pos int, f string, x ...any) error {
return errors.New(head+f, x...)
}
+var errRecursionDepth = errors.New("exceeded maximum recursion depth")
+
// unmarshalMessage unmarshals into the given protoreflect.Message.
func (d decoder) unmarshalMessage(m protoreflect.Message, checkDelims bool) error {
+ if d.opts.RecursionLimit--; d.opts.RecursionLimit < 0 {
+ return errRecursionDepth
+ }
+
messageDesc := m.Descriptor()
if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
return errors.New("no support for proto1 MessageSets")
@@ -437,6 +451,10 @@ func (d decoder) unmarshalList(fd protoreflect.FieldDescriptor, list protoreflec
// unmarshalMap unmarshals into given protoreflect.Map. A map value is a
// textproto message containing {key: , value: }.
func (d decoder) unmarshalMap(fd protoreflect.FieldDescriptor, mmap protoreflect.Map) error {
+ if d.opts.RecursionLimit--; d.opts.RecursionLimit < 0 {
+ return errRecursionDepth
+ }
+
// Determine ahead whether map entry is a scalar type or a message type in
// order to call the appropriate unmarshalMapValue func inside
// unmarshalMapEntry.
diff --git a/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go b/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go
index 87e46bd..0b0dfac 100644
--- a/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go
+++ b/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go
@@ -83,12 +83,13 @@ func formatListOpt(vs list, isRoot, allowMulti bool) string {
case protoreflect.FileImports:
for i := 0; i < vs.Len(); i++ {
var rs records
- rv := reflect.ValueOf(vs.Get(i))
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Path"), "Path"},
- {rv.MethodByName("Package"), "Package"},
- {rv.MethodByName("IsPublic"), "IsPublic"},
- {rv.MethodByName("IsWeak"), "IsWeak"},
+ fi := vs.Get(i)
+ rv := reflect.ValueOf(fi)
+ rs.Append(rv, []attrAndName{
+ {fi.Path(), "Path"},
+ {fi.Package(), "Package"},
+ {fi.IsPublic, "IsPublic"},
+ {fi.IsWeak, "IsWeak"},
}...)
ss = append(ss, "{"+rs.Join()+"}")
}
@@ -104,9 +105,9 @@ func formatListOpt(vs list, isRoot, allowMulti bool) string {
}
}
-type methodAndName struct {
- method reflect.Value
- name string
+type attrAndName struct {
+ attr any
+ name string
}
func FormatDesc(s fmt.State, r rune, t protoreflect.Descriptor) {
@@ -126,58 +127,58 @@ func formatDescOpt(t protoreflect.Descriptor, isRoot, allowMulti bool, record fu
start = rt.Name() + "{"
}
- _, isFile := t.(protoreflect.FileDescriptor)
+ fd, isFile := t.(protoreflect.FileDescriptor)
rs := records{
allowMulti: allowMulti,
record: record,
}
if t.IsPlaceholder() {
if isFile {
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Path"), "Path"},
- {rv.MethodByName("Package"), "Package"},
- {rv.MethodByName("IsPlaceholder"), "IsPlaceholder"},
+ rs.Append(rv, []attrAndName{
+ {fd.Path(), "Path"},
+ {fd.Package(), "Package"},
+ {fd.IsPlaceholder(), "IsPlaceholder"},
}...)
} else {
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("FullName"), "FullName"},
- {rv.MethodByName("IsPlaceholder"), "IsPlaceholder"},
+ rs.Append(rv, []attrAndName{
+ {t.FullName(), "FullName"},
+ {t.IsPlaceholder(), "IsPlaceholder"},
}...)
}
} else {
switch {
case isFile:
- rs.Append(rv, methodAndName{rv.MethodByName("Syntax"), "Syntax"})
+ rs.Append(rv, attrAndName{fd.Syntax(), "Syntax"})
case isRoot:
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Syntax"), "Syntax"},
- {rv.MethodByName("FullName"), "FullName"},
+ rs.Append(rv, []attrAndName{
+ {t.Syntax(), "Syntax"},
+ {t.FullName(), "FullName"},
}...)
default:
- rs.Append(rv, methodAndName{rv.MethodByName("Name"), "Name"})
+ rs.Append(rv, attrAndName{t.Name(), "Name"})
}
switch t := t.(type) {
case protoreflect.FieldDescriptor:
- accessors := []methodAndName{
- {rv.MethodByName("Number"), "Number"},
- {rv.MethodByName("Cardinality"), "Cardinality"},
- {rv.MethodByName("Kind"), "Kind"},
- {rv.MethodByName("HasJSONName"), "HasJSONName"},
- {rv.MethodByName("JSONName"), "JSONName"},
- {rv.MethodByName("HasPresence"), "HasPresence"},
- {rv.MethodByName("IsExtension"), "IsExtension"},
- {rv.MethodByName("IsPacked"), "IsPacked"},
- {rv.MethodByName("IsWeak"), "IsWeak"},
- {rv.MethodByName("IsList"), "IsList"},
- {rv.MethodByName("IsMap"), "IsMap"},
- {rv.MethodByName("MapKey"), "MapKey"},
- {rv.MethodByName("MapValue"), "MapValue"},
- {rv.MethodByName("HasDefault"), "HasDefault"},
- {rv.MethodByName("Default"), "Default"},
- {rv.MethodByName("ContainingOneof"), "ContainingOneof"},
- {rv.MethodByName("ContainingMessage"), "ContainingMessage"},
- {rv.MethodByName("Message"), "Message"},
- {rv.MethodByName("Enum"), "Enum"},
+ accessors := []attrAndName{
+ {t.Number(), "Number"},
+ {t.Cardinality(), "Cardinality"},
+ {t.Kind(), "Kind"},
+ {t.HasJSONName(), "HasJSONName"},
+ {t.JSONName(), "JSONName"},
+ {t.HasPresence(), "HasPresence"},
+ {t.IsExtension(), "IsExtension"},
+ {t.IsPacked(), "IsPacked"},
+ {t.IsWeak(), "IsWeak"},
+ {t.IsList(), "IsList"},
+ {t.IsMap(), "IsMap"},
+ {t.MapKey(), "MapKey"},
+ {t.MapValue(), "MapValue"},
+ {t.HasDefault(), "HasDefault"},
+ {t.Default(), "Default"},
+ {t.ContainingOneof(), "ContainingOneof"},
+ {t.ContainingMessage(), "ContainingMessage"},
+ {t.Message(), "Message"},
+ {t.Enum(), "Enum"},
}
for _, s := range accessors {
switch s.name {
@@ -223,58 +224,54 @@ func formatDescOpt(t protoreflect.Descriptor, isRoot, allowMulti bool, record fu
}
case protoreflect.FileDescriptor:
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Path"), "Path"},
- {rv.MethodByName("Package"), "Package"},
- {rv.MethodByName("Imports"), "Imports"},
- {rv.MethodByName("Messages"), "Messages"},
- {rv.MethodByName("Enums"), "Enums"},
- {rv.MethodByName("Extensions"), "Extensions"},
- {rv.MethodByName("Services"), "Services"},
+ rs.Append(rv, []attrAndName{
+ {t.Path(), "Path"},
+ {t.Package(), "Package"},
+ {t.Imports(), "Imports"},
+ {t.Messages(), "Messages"},
+ {t.Enums(), "Enums"},
+ {t.Extensions(), "Extensions"},
+ {t.Services(), "Services"},
}...)
case protoreflect.MessageDescriptor:
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("IsMapEntry"), "IsMapEntry"},
- {rv.MethodByName("Fields"), "Fields"},
- {rv.MethodByName("Oneofs"), "Oneofs"},
- {rv.MethodByName("ReservedNames"), "ReservedNames"},
- {rv.MethodByName("ReservedRanges"), "ReservedRanges"},
- {rv.MethodByName("RequiredNumbers"), "RequiredNumbers"},
- {rv.MethodByName("ExtensionRanges"), "ExtensionRanges"},
- {rv.MethodByName("Messages"), "Messages"},
- {rv.MethodByName("Enums"), "Enums"},
- {rv.MethodByName("Extensions"), "Extensions"},
+ rs.Append(rv, []attrAndName{
+ {t.IsMapEntry(), "IsMapEntry"},
+ {t.Fields(), "Fields"},
+ {t.Oneofs(), "Oneofs"},
+ {t.ReservedNames(), "ReservedNames"},
+ {t.ReservedRanges(), "ReservedRanges"},
+ {t.RequiredNumbers(), "RequiredNumbers"},
+ {t.ExtensionRanges(), "ExtensionRanges"},
+ {t.Messages(), "Messages"},
+ {t.Enums(), "Enums"},
+ {t.Extensions(), "Extensions"},
}...)
case protoreflect.EnumDescriptor:
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Values"), "Values"},
- {rv.MethodByName("ReservedNames"), "ReservedNames"},
- {rv.MethodByName("ReservedRanges"), "ReservedRanges"},
- {rv.MethodByName("IsClosed"), "IsClosed"},
+ rs.Append(rv, []attrAndName{
+ {t.Values(), "Values"},
+ {t.ReservedNames(), "ReservedNames"},
+ {t.ReservedRanges(), "ReservedRanges"},
+ {t.IsClosed(), "IsClosed"},
}...)
case protoreflect.EnumValueDescriptor:
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Number"), "Number"},
- }...)
+ rs.Append(rv, attrAndName{t.Number(), "Number"})
case protoreflect.ServiceDescriptor:
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Methods"), "Methods"},
- }...)
+ rs.Append(rv, attrAndName{t.Methods(), "Methods"})
case protoreflect.MethodDescriptor:
- rs.Append(rv, []methodAndName{
- {rv.MethodByName("Input"), "Input"},
- {rv.MethodByName("Output"), "Output"},
- {rv.MethodByName("IsStreamingClient"), "IsStreamingClient"},
- {rv.MethodByName("IsStreamingServer"), "IsStreamingServer"},
+ rs.Append(rv, []attrAndName{
+ {t.Input(), "Input"},
+ {t.Output(), "Output"},
+ {t.IsStreamingClient(), "IsStreamingClient"},
+ {t.IsStreamingServer(), "IsStreamingServer"},
}...)
}
- if m := rv.MethodByName("GoType"); m.IsValid() {
- rs.Append(rv, methodAndName{m, "GoType"})
+ if m, ok := t.(interface{ GoType() reflect.Type }); ok {
+ rs.Append(rv, attrAndName{m.GoType(), "GoType"})
}
}
return start + rs.Join() + end
@@ -297,68 +294,66 @@ func (rs *records) AppendRecs(fieldName string, newRecs [2]string) {
rs.recs = append(rs.recs, newRecs)
}
-func (rs *records) Append(v reflect.Value, accessors ...methodAndName) {
- for _, a := range accessors {
- if rs.record != nil {
- rs.record(a.name)
- }
- var rv reflect.Value
- if a.method.IsValid() {
- rv = a.method.Call(nil)[0]
- }
- if v.Kind() == reflect.Struct && !rv.IsValid() {
- rv = v.FieldByName(a.name)
- }
- if !rv.IsValid() {
- panic(fmt.Sprintf("unknown accessor: %v.%s", v.Type(), a.name))
- }
- if _, ok := rv.Interface().(protoreflect.Value); ok {
- rv = rv.MethodByName("Interface").Call(nil)[0]
- if !rv.IsNil() {
- rv = rv.Elem()
- }
- }
+func (rs *records) Append(v reflect.Value, results ...attrAndName) {
+ for _, r := range results {
+ rs.appendAttribute(v, r.name, r.attr)
+ }
+}
- // Ignore zero values.
- var isZero bool
- switch rv.Kind() {
- case reflect.Interface, reflect.Slice:
- isZero = rv.IsNil()
- case reflect.Bool:
- isZero = rv.Bool() == false
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- isZero = rv.Int() == 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- isZero = rv.Uint() == 0
- case reflect.String:
- isZero = rv.String() == ""
- }
- if n, ok := rv.Interface().(list); ok {
- isZero = n.Len() == 0
- }
- if isZero {
- continue
+func (rs *records) appendAttribute(val reflect.Value, name string, attrVal any) {
+ if rs.record != nil {
+ rs.record(name)
+ }
+ if attrVal == nil {
+ return
+ }
+ rv := reflect.ValueOf(attrVal)
+ if _, ok := rv.Interface().(protoreflect.Value); ok {
+ rv = rv.MethodByName("Interface").Call(nil)[0]
+ if !rv.IsNil() {
+ rv = rv.Elem()
}
+ }
- // Format the value.
- var s string
- v := rv.Interface()
- switch v := v.(type) {
- case list:
- s = formatListOpt(v, false, rs.allowMulti)
- case protoreflect.FieldDescriptor, protoreflect.OneofDescriptor, protoreflect.EnumValueDescriptor, protoreflect.MethodDescriptor:
- s = string(v.(protoreflect.Descriptor).Name())
- case protoreflect.Descriptor:
- s = string(v.FullName())
- case string:
- s = strconv.Quote(v)
- case []byte:
- s = fmt.Sprintf("%q", v)
- default:
- s = fmt.Sprint(v)
- }
- rs.recs = append(rs.recs, [2]string{a.name, s})
+ // Ignore zero values.
+ var isZero bool
+ switch rv.Kind() {
+ case reflect.Interface, reflect.Slice:
+ isZero = rv.IsNil()
+ case reflect.Bool:
+ isZero = rv.Bool() == false
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ isZero = rv.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ isZero = rv.Uint() == 0
+ case reflect.String:
+ isZero = rv.String() == ""
+ }
+ if n, ok := rv.Interface().(list); ok {
+ isZero = n.Len() == 0
+ }
+ if isZero {
+ return
+ }
+
+ // Format the value.
+ var s string
+ v := rv.Interface()
+ switch v := v.(type) {
+ case list:
+ s = formatListOpt(v, false, rs.allowMulti)
+ case protoreflect.FieldDescriptor, protoreflect.OneofDescriptor, protoreflect.EnumValueDescriptor, protoreflect.MethodDescriptor:
+ s = string(v.(protoreflect.Descriptor).Name())
+ case protoreflect.Descriptor:
+ s = string(v.FullName())
+ case string:
+ s = strconv.Quote(v)
+ case []byte:
+ s = fmt.Sprintf("%q", v)
+ default:
+ s = fmt.Sprint(v)
}
+ rs.recs = append(rs.recs, [2]string{name, s})
}
func (rs *records) Join() string {
diff --git a/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb b/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb
index 0469635..ad35ea4 100644
Binary files a/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb and b/vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb differ
diff --git a/vendor/google.golang.org/protobuf/internal/encoding/defval/default.go b/vendor/google.golang.org/protobuf/internal/encoding/defval/default.go
index 328dc73..079a53d 100644
--- a/vendor/google.golang.org/protobuf/internal/encoding/defval/default.go
+++ b/vendor/google.golang.org/protobuf/internal/encoding/defval/default.go
@@ -69,19 +69,19 @@ func Unmarshal(s string, k protoreflect.Kind, evs protoreflect.EnumValueDescript
}
}
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
- if v, err := strconv.ParseInt(s, 10, 32); err == nil {
+ if v, err := strconv.ParseInt(s, 0, 32); err == nil {
return protoreflect.ValueOfInt32(int32(v)), nil, nil
}
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
- if v, err := strconv.ParseInt(s, 10, 64); err == nil {
+ if v, err := strconv.ParseInt(s, 0, 64); err == nil {
return protoreflect.ValueOfInt64(int64(v)), nil, nil
}
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
- if v, err := strconv.ParseUint(s, 10, 32); err == nil {
+ if v, err := strconv.ParseUint(s, 0, 32); err == nil {
return protoreflect.ValueOfUint32(uint32(v)), nil, nil
}
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
- if v, err := strconv.ParseUint(s, 10, 64); err == nil {
+ if v, err := strconv.ParseUint(s, 0, 64); err == nil {
return protoreflect.ValueOfUint64(uint64(v)), nil, nil
}
case protoreflect.FloatKind, protoreflect.DoubleKind:
diff --git a/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go b/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go
index 65aaf4d..58aeff8 100644
--- a/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go
+++ b/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go
@@ -26,6 +26,7 @@ const (
Edition_EDITION_PROTO3_enum_value = 999
Edition_EDITION_2023_enum_value = 1000
Edition_EDITION_2024_enum_value = 1001
+ Edition_EDITION_2026_enum_value = 1002
Edition_EDITION_UNSTABLE_enum_value = 9999
Edition_EDITION_1_TEST_ONLY_enum_value = 1
Edition_EDITION_2_TEST_ONLY_enum_value = 2
@@ -806,11 +807,13 @@ const (
FieldOptions_FeatureSupport_EditionDeprecated_field_name protoreflect.Name = "edition_deprecated"
FieldOptions_FeatureSupport_DeprecationWarning_field_name protoreflect.Name = "deprecation_warning"
FieldOptions_FeatureSupport_EditionRemoved_field_name protoreflect.Name = "edition_removed"
+ FieldOptions_FeatureSupport_RemovalError_field_name protoreflect.Name = "removal_error"
FieldOptions_FeatureSupport_EditionIntroduced_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.edition_introduced"
FieldOptions_FeatureSupport_EditionDeprecated_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.edition_deprecated"
FieldOptions_FeatureSupport_DeprecationWarning_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.deprecation_warning"
FieldOptions_FeatureSupport_EditionRemoved_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.edition_removed"
+ FieldOptions_FeatureSupport_RemovalError_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.FeatureSupport.removal_error"
)
// Field numbers for google.protobuf.FieldOptions.FeatureSupport.
@@ -819,6 +822,7 @@ const (
FieldOptions_FeatureSupport_EditionDeprecated_field_number protoreflect.FieldNumber = 2
FieldOptions_FeatureSupport_DeprecationWarning_field_number protoreflect.FieldNumber = 3
FieldOptions_FeatureSupport_EditionRemoved_field_number protoreflect.FieldNumber = 4
+ FieldOptions_FeatureSupport_RemovalError_field_number protoreflect.FieldNumber = 5
)
// Names for google.protobuf.OneofOptions.
@@ -1152,6 +1156,7 @@ const (
FeatureSet_ENFORCE_NAMING_STYLE_UNKNOWN_enum_value = 0
FeatureSet_STYLE2024_enum_value = 1
FeatureSet_STYLE_LEGACY_enum_value = 2
+ FeatureSet_STYLE2026_enum_value = 3
)
// Names for google.protobuf.FeatureSet.VisibilityFeature.
diff --git a/vendor/google.golang.org/protobuf/internal/version/version.go b/vendor/google.golang.org/protobuf/internal/version/version.go
index 763fd82..58ff0e2 100644
--- a/vendor/google.golang.org/protobuf/internal/version/version.go
+++ b/vendor/google.golang.org/protobuf/internal/version/version.go
@@ -52,7 +52,7 @@ import (
const (
Major = 1
Minor = 36
- Patch = 11
+ Patch = 12
PreRelease = ""
)
diff --git a/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go b/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go
index c826ad0..84a3228 100644
--- a/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go
+++ b/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go
@@ -201,6 +201,7 @@ func (r descsByName) initExtensionDeclarations(xds []*descriptorpb.FieldDescript
return nil, err
}
x.L1.EditionFeatures = mergeEditionFeatures(parent, xd.GetOptions().GetFeatures())
+ x.L2.IsProto3Optional = xd.GetProto3Optional()
if opts := xd.GetOptions(); opts != nil {
opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
x.L2.Options = func() protoreflect.ProtoMessage { return opts }
diff --git a/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go b/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go
index 730331e..86f0d09 100644
--- a/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go
+++ b/vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go
@@ -546,6 +546,8 @@ func (p *SourcePath) appendFieldOptions_FeatureSupport(b []byte) []byte {
b = p.appendSingularField(b, "deprecation_warning", nil)
case 4:
b = p.appendSingularField(b, "edition_removed", nil)
+ case 5:
+ b = p.appendSingularField(b, "removal_error", nil)
}
return b
}
diff --git a/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go b/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go
index 0b23faa..a51cb1e 100644
--- a/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go
+++ b/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go
@@ -1,32 +1,9 @@
// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
+// Copyright 2008 Google LLC. 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.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
@@ -69,6 +46,7 @@ const (
// comparison.
Edition_EDITION_2023 Edition = 1000
Edition_EDITION_2024 Edition = 1001
+ Edition_EDITION_2026 Edition = 1002
// A placeholder edition for developing and testing unscheduled features.
Edition_EDITION_UNSTABLE Edition = 9999
// Placeholder editions for testing feature resolution. These should not be
@@ -93,6 +71,7 @@ var (
999: "EDITION_PROTO3",
1000: "EDITION_2023",
1001: "EDITION_2024",
+ 1002: "EDITION_2026",
9999: "EDITION_UNSTABLE",
1: "EDITION_1_TEST_ONLY",
2: "EDITION_2_TEST_ONLY",
@@ -108,6 +87,7 @@ var (
"EDITION_PROTO3": 999,
"EDITION_2023": 1000,
"EDITION_2024": 1001,
+ "EDITION_2026": 1002,
"EDITION_UNSTABLE": 9999,
"EDITION_1_TEST_ONLY": 1,
"EDITION_2_TEST_ONLY": 2,
@@ -1213,6 +1193,7 @@ const (
FeatureSet_ENFORCE_NAMING_STYLE_UNKNOWN FeatureSet_EnforceNamingStyle = 0
FeatureSet_STYLE2024 FeatureSet_EnforceNamingStyle = 1
FeatureSet_STYLE_LEGACY FeatureSet_EnforceNamingStyle = 2
+ FeatureSet_STYLE2026 FeatureSet_EnforceNamingStyle = 3
)
// Enum value maps for FeatureSet_EnforceNamingStyle.
@@ -1221,11 +1202,13 @@ var (
0: "ENFORCE_NAMING_STYLE_UNKNOWN",
1: "STYLE2024",
2: "STYLE_LEGACY",
+ 3: "STYLE2026",
}
FeatureSet_EnforceNamingStyle_value = map[string]int32{
"ENFORCE_NAMING_STYLE_UNKNOWN": 0,
"STYLE2024": 1,
"STYLE_LEGACY": 2,
+ "STYLE2026": 3,
}
)
@@ -4204,8 +4187,11 @@ type FieldOptions_FeatureSupport struct {
// this one, the last default assigned will be used, and proto files will
// not be able to override it.
EditionRemoved *Edition `protobuf:"varint,4,opt,name=edition_removed,json=editionRemoved,enum=google.protobuf.Edition" json:"edition_removed,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
+ // The removal error text if this feature is used after the edition it was
+ // removed in.
+ RemovalError *string `protobuf:"bytes,5,opt,name=removal_error,json=removalError" json:"removal_error,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *FieldOptions_FeatureSupport) Reset() {
@@ -4266,6 +4252,13 @@ func (x *FieldOptions_FeatureSupport) GetEditionRemoved() Edition {
return Edition_EDITION_UNKNOWN
}
+func (x *FieldOptions_FeatureSupport) GetRemovalError() string {
+ if x != nil && x.RemovalError != nil {
+ return *x.RemovalError
+ }
+ return ""
+}
+
// The name of the uninterpreted option. Each string represents a segment in
// a dot-separated name. is_extension is true iff a segment represents an
// extension (denoted with parentheses in options specs in .proto files).
@@ -4719,7 +4712,7 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\aoptions\x18\x03 \x01(\v2&.google.protobuf.ExtensionRangeOptionsR\aoptions\x1a7\n" +
"\rReservedRange\x12\x14\n" +
"\x05start\x18\x01 \x01(\x05R\x05start\x12\x10\n" +
- "\x03end\x18\x02 \x01(\x05R\x03end\"\xcc\x04\n" +
+ "\x03end\x18\x02 \x01(\x05R\x03end\"\xd4\x04\n" +
"\x15ExtensionRangeOptions\x12X\n" +
"\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption\x12Y\n" +
"\vdeclaration\x18\x02 \x03(\v22.google.protobuf.ExtensionRangeOptions.DeclarationB\x03\x88\x01\x02R\vdeclaration\x127\n" +
@@ -4735,7 +4728,7 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\x11VerificationState\x12\x0f\n" +
"\vDECLARATION\x10\x00\x12\x0e\n" +
"\n" +
- "UNVERIFIED\x10\x01*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\xc1\x06\n" +
+ "UNVERIFIED\x10\x01*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\xc1\x06\n" +
"\x14FieldDescriptorProto\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" +
"\x06number\x18\x03 \x01(\x05R\x06number\x12A\n" +
@@ -4810,12 +4803,13 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"outputType\x128\n" +
"\aoptions\x18\x04 \x01(\v2\x1e.google.protobuf.MethodOptionsR\aoptions\x120\n" +
"\x10client_streaming\x18\x05 \x01(\b:\x05falseR\x0fclientStreaming\x120\n" +
- "\x10server_streaming\x18\x06 \x01(\b:\x05falseR\x0fserverStreaming\"\xad\t\n" +
+ "\x10server_streaming\x18\x06 \x01(\b:\x05falseR\x0fserverStreaming\"\xfa\n" +
+ "\n" +
"\vFileOptions\x12!\n" +
"\fjava_package\x18\x01 \x01(\tR\vjavaPackage\x120\n" +
- "\x14java_outer_classname\x18\b \x01(\tR\x12javaOuterClassname\x125\n" +
+ "\x14java_outer_classname\x18\b \x01(\tR\x12javaOuterClassname\x12\xf9\x01\n" +
"\x13java_multiple_files\x18\n" +
- " \x01(\b:\x05falseR\x11javaMultipleFiles\x12D\n" +
+ " \x01(\b:\x05falseB\xc1\x01\xb2\x01\xbd\x01\b\xe6\a \xe9\a*\xb4\x01This behavior is enabled by default in editions 2024 and above. To disable it, you can set `features.(pb.java).nest_in_file_class = YES` on individual messages, enums, or services.R\x11javaMultipleFiles\x12D\n" +
"\x1djava_generate_equals_and_hash\x18\x14 \x01(\bB\x02\x18\x01R\x19javaGenerateEqualsAndHash\x12:\n" +
"\x16java_string_check_utf8\x18\x1b \x01(\b:\x05falseR\x13javaStringCheckUtf8\x12S\n" +
"\foptimize_for\x18\t \x01(\x0e2).google.protobuf.FileOptions.OptimizeMode:\x05SPEEDR\voptimizeFor\x12\x1d\n" +
@@ -4840,7 +4834,7 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\fOptimizeMode\x12\t\n" +
"\x05SPEED\x10\x01\x12\r\n" +
"\tCODE_SIZE\x10\x02\x12\x10\n" +
- "\fLITE_RUNTIME\x10\x03*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b*\x10+J\x04\b&\x10'R\x14php_generic_services\"\xf4\x03\n" +
+ "\fLITE_RUNTIME\x10\x03*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b*\x10+J\x04\b&\x10'R\x14php_generic_services\"\xfc\x03\n" +
"\x0eMessageOptions\x12<\n" +
"\x17message_set_wire_format\x18\x01 \x01(\b:\x05falseR\x14messageSetWireFormat\x12L\n" +
"\x1fno_standard_descriptor_accessor\x18\x02 \x01(\b:\x05falseR\x1cnoStandardDescriptorAccessor\x12%\n" +
@@ -4850,8 +4844,8 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\tmap_entry\x18\a \x01(\bR\bmapEntry\x12V\n" +
"&deprecated_legacy_json_field_conflicts\x18\v \x01(\bB\x02\x18\x01R\"deprecatedLegacyJsonFieldConflicts\x127\n" +
"\bfeatures\x18\f \x01(\v2\x1b.google.protobuf.FeatureSetR\bfeatures\x12X\n" +
- "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b\x04\x10\x05J\x04\b\x05\x10\x06J\x04\b\x06\x10\aJ\x04\b\b\x10\tJ\x04\b\t\x10\n" +
- "\"\xa1\r\n" +
+ "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b\x04\x10\x05J\x04\b\x05\x10\x06J\x04\b\x06\x10\aJ\x04\b\b\x10\tJ\x04\b\t\x10\n" +
+ "\"\xce\r\n" +
"\fFieldOptions\x12A\n" +
"\x05ctype\x18\x01 \x01(\x0e2#.google.protobuf.FieldOptions.CType:\x06STRINGR\x05ctype\x12\x16\n" +
"\x06packed\x18\x02 \x01(\bR\x06packed\x12G\n" +
@@ -4872,12 +4866,13 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption\x1aZ\n" +
"\x0eEditionDefault\x122\n" +
"\aedition\x18\x03 \x01(\x0e2\x18.google.protobuf.EditionR\aedition\x12\x14\n" +
- "\x05value\x18\x02 \x01(\tR\x05value\x1a\x96\x02\n" +
+ "\x05value\x18\x02 \x01(\tR\x05value\x1a\xbb\x02\n" +
"\x0eFeatureSupport\x12G\n" +
"\x12edition_introduced\x18\x01 \x01(\x0e2\x18.google.protobuf.EditionR\x11editionIntroduced\x12G\n" +
"\x12edition_deprecated\x18\x02 \x01(\x0e2\x18.google.protobuf.EditionR\x11editionDeprecated\x12/\n" +
"\x13deprecation_warning\x18\x03 \x01(\tR\x12deprecationWarning\x12A\n" +
- "\x0fedition_removed\x18\x04 \x01(\x0e2\x18.google.protobuf.EditionR\x0eeditionRemoved\"/\n" +
+ "\x0fedition_removed\x18\x04 \x01(\x0e2\x18.google.protobuf.EditionR\x0eeditionRemoved\x12#\n" +
+ "\rremoval_error\x18\x05 \x01(\tR\fremovalError\"/\n" +
"\x05CType\x12\n" +
"\n" +
"\x06STRING\x10\x00\x12\b\n" +
@@ -4901,10 +4896,10 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\x10TARGET_TYPE_ENUM\x10\x06\x12\x1a\n" +
"\x16TARGET_TYPE_ENUM_ENTRY\x10\a\x12\x17\n" +
"\x13TARGET_TYPE_SERVICE\x10\b\x12\x16\n" +
- "\x12TARGET_TYPE_METHOD\x10\t*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b\x04\x10\x05J\x04\b\x12\x10\x13\"\xac\x01\n" +
+ "\x12TARGET_TYPE_METHOD\x10\t*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b\x04\x10\x05J\x04\b\x12\x10\x13\"\xb4\x01\n" +
"\fOneofOptions\x127\n" +
"\bfeatures\x18\x01 \x01(\v2\x1b.google.protobuf.FeatureSetR\bfeatures\x12X\n" +
- "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\xd1\x02\n" +
+ "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\xd9\x02\n" +
"\vEnumOptions\x12\x1f\n" +
"\vallow_alias\x18\x02 \x01(\bR\n" +
"allowAlias\x12%\n" +
@@ -4913,7 +4908,7 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"deprecated\x12V\n" +
"&deprecated_legacy_json_field_conflicts\x18\x06 \x01(\bB\x02\x18\x01R\"deprecatedLegacyJsonFieldConflicts\x127\n" +
"\bfeatures\x18\a \x01(\v2\x1b.google.protobuf.FeatureSetR\bfeatures\x12X\n" +
- "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b\x05\x10\x06\"\xd8\x02\n" +
+ "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02J\x04\b\x05\x10\x06\"\xe0\x02\n" +
"\x10EnumValueOptions\x12%\n" +
"\n" +
"deprecated\x18\x01 \x01(\b:\x05falseR\n" +
@@ -4921,13 +4916,13 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\bfeatures\x18\x02 \x01(\v2\x1b.google.protobuf.FeatureSetR\bfeatures\x12(\n" +
"\fdebug_redact\x18\x03 \x01(\b:\x05falseR\vdebugRedact\x12U\n" +
"\x0ffeature_support\x18\x04 \x01(\v2,.google.protobuf.FieldOptions.FeatureSupportR\x0efeatureSupport\x12X\n" +
- "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\xd5\x01\n" +
+ "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\xdd\x01\n" +
"\x0eServiceOptions\x127\n" +
"\bfeatures\x18\" \x01(\v2\x1b.google.protobuf.FeatureSetR\bfeatures\x12%\n" +
"\n" +
"deprecated\x18! \x01(\b:\x05falseR\n" +
"deprecated\x12X\n" +
- "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\x99\x03\n" +
+ "\x14uninterpreted_option\x18\xe7\a \x03(\v2$.google.protobuf.UninterpretedOptionR\x13uninterpretedOption*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\xa1\x03\n" +
"\rMethodOptions\x12%\n" +
"\n" +
"deprecated\x18! \x01(\b:\x05falseR\n" +
@@ -4939,7 +4934,7 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\x13IDEMPOTENCY_UNKNOWN\x10\x00\x12\x13\n" +
"\x0fNO_SIDE_EFFECTS\x10\x01\x12\x0e\n" +
"\n" +
- "IDEMPOTENT\x10\x02*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\x9a\x03\n" +
+ "IDEMPOTENT\x10\x02*\x06\b\xde\a\x10\xe7\a*\t\b\xe8\a\x10\x80\x80\x80\x80\x02\"\x9a\x03\n" +
"\x13UninterpretedOption\x12A\n" +
"\x04name\x18\x02 \x03(\v2-.google.protobuf.UninterpretedOption.NamePartR\x04name\x12)\n" +
"\x10identifier_value\x18\x03 \x01(\tR\x0fidentifierValue\x12,\n" +
@@ -4950,7 +4945,7 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\x0faggregate_value\x18\b \x01(\tR\x0eaggregateValue\x1aJ\n" +
"\bNamePart\x12\x1b\n" +
"\tname_part\x18\x01 \x02(\tR\bnamePart\x12!\n" +
- "\fis_extension\x18\x02 \x02(\bR\visExtension\"\x8e\x0f\n" +
+ "\fis_extension\x18\x02 \x02(\bR\visExtension\"\xae\x0f\n" +
"\n" +
"FeatureSet\x12\x91\x01\n" +
"\x0efield_presence\x18\x01 \x01(\x0e2).google.protobuf.FeatureSet.FieldPresenceB?\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\r\x12\bEXPLICIT\x18\x84\a\xa2\x01\r\x12\bIMPLICIT\x18\xe7\a\xa2\x01\r\x12\bEXPLICIT\x18\xe8\a\xb2\x01\x03\b\xe8\aR\rfieldPresence\x12l\n" +
@@ -4960,8 +4955,8 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\x10message_encoding\x18\x05 \x01(\x0e2+.google.protobuf.FeatureSet.MessageEncodingB&\x88\x01\x01\x98\x01\x04\x98\x01\x01\xa2\x01\x14\x12\x0fLENGTH_PREFIXED\x18\x84\a\xb2\x01\x03\b\xe8\aR\x0fmessageEncoding\x12\x82\x01\n" +
"\vjson_format\x18\x06 \x01(\x0e2&.google.protobuf.FeatureSet.JsonFormatB9\x88\x01\x01\x98\x01\x03\x98\x01\x06\x98\x01\x01\xa2\x01\x17\x12\x12LEGACY_BEST_EFFORT\x18\x84\a\xa2\x01\n" +
"\x12\x05ALLOW\x18\xe7\a\xb2\x01\x03\b\xe8\aR\n" +
- "jsonFormat\x12\xab\x01\n" +
- "\x14enforce_naming_style\x18\a \x01(\x0e2..google.protobuf.FeatureSet.EnforceNamingStyleBI\x88\x01\x02\x98\x01\x01\x98\x01\x02\x98\x01\x03\x98\x01\x04\x98\x01\x05\x98\x01\x06\x98\x01\a\x98\x01\b\x98\x01\t\xa2\x01\x11\x12\fSTYLE_LEGACY\x18\x84\a\xa2\x01\x0e\x12\tSTYLE2024\x18\xe9\a\xb2\x01\x03\b\xe9\aR\x12enforceNamingStyle\x12\xb9\x01\n" +
+ "jsonFormat\x12\xbc\x01\n" +
+ "\x14enforce_naming_style\x18\a \x01(\x0e2..google.protobuf.FeatureSet.EnforceNamingStyleBZ\x88\x01\x02\x98\x01\x01\x98\x01\x02\x98\x01\x03\x98\x01\x04\x98\x01\x05\x98\x01\x06\x98\x01\a\x98\x01\b\x98\x01\t\xa2\x01\x11\x12\fSTYLE_LEGACY\x18\x84\a\xa2\x01\x0e\x12\tSTYLE2024\x18\xe9\a\xa2\x01\x0e\x12\tSTYLE2026\x18\x8fN\xb2\x01\x03\b\xe9\aR\x12enforceNamingStyle\x12\xb9\x01\n" +
"\x19default_symbol_visibility\x18\b \x01(\x0e2E.google.protobuf.FeatureSet.VisibilityFeature.DefaultSymbolVisibilityB6\x88\x01\x02\x98\x01\x01\xa2\x01\x0f\x12\n" +
"EXPORT_ALL\x18\x84\a\xa2\x01\x15\x12\x10EXPORT_TOP_LEVEL\x18\xe9\a\xb2\x01\x03\b\xe9\aR\x17defaultSymbolVisibility\x1a\xa1\x01\n" +
"\x11VisibilityFeature\"\x81\x01\n" +
@@ -5001,11 +4996,12 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"JsonFormat\x12\x17\n" +
"\x13JSON_FORMAT_UNKNOWN\x10\x00\x12\t\n" +
"\x05ALLOW\x10\x01\x12\x16\n" +
- "\x12LEGACY_BEST_EFFORT\x10\x02\"W\n" +
+ "\x12LEGACY_BEST_EFFORT\x10\x02\"f\n" +
"\x12EnforceNamingStyle\x12 \n" +
"\x1cENFORCE_NAMING_STYLE_UNKNOWN\x10\x00\x12\r\n" +
"\tSTYLE2024\x10\x01\x12\x10\n" +
- "\fSTYLE_LEGACY\x10\x02*\x06\b\xe8\a\x10\x8bN*\x06\b\x8bN\x10\x90N*\x06\b\x90N\x10\x91NJ\x06\b\xe7\a\x10\xe8\a\"\xef\x03\n" +
+ "\fSTYLE_LEGACY\x10\x02\x12\r\n" +
+ "\tSTYLE2026\x10\x03*\x06\b\xe8\a\x10\x8bN*\x06\b\x8bN\x10\x90N*\x06\b\x90N\x10\x91NJ\x06\b\xe7\a\x10\xe8\a\"\xef\x03\n" +
"\x12FeatureSetDefaults\x12X\n" +
"\bdefaults\x18\x01 \x03(\v2<.google.protobuf.FeatureSetDefaults.FeatureSetEditionDefaultR\bdefaults\x12A\n" +
"\x0fminimum_edition\x18\x04 \x01(\x0e2\x18.google.protobuf.EditionR\x0eminimumEdition\x12A\n" +
@@ -5037,14 +5033,15 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" +
"\bSemantic\x12\b\n" +
"\x04NONE\x10\x00\x12\a\n" +
"\x03SET\x10\x01\x12\t\n" +
- "\x05ALIAS\x10\x02*\xbe\x02\n" +
+ "\x05ALIAS\x10\x02*\xd1\x02\n" +
"\aEdition\x12\x13\n" +
"\x0fEDITION_UNKNOWN\x10\x00\x12\x13\n" +
"\x0eEDITION_LEGACY\x10\x84\a\x12\x13\n" +
"\x0eEDITION_PROTO2\x10\xe6\a\x12\x13\n" +
"\x0eEDITION_PROTO3\x10\xe7\a\x12\x11\n" +
"\fEDITION_2023\x10\xe8\a\x12\x11\n" +
- "\fEDITION_2024\x10\xe9\a\x12\x15\n" +
+ "\fEDITION_2024\x10\xe9\a\x12\x11\n" +
+ "\fEDITION_2026\x10\xea\a\x12\x15\n" +
"\x10EDITION_UNSTABLE\x10\x8fN\x12\x17\n" +
"\x13EDITION_1_TEST_ONLY\x10\x01\x12\x17\n" +
"\x13EDITION_2_TEST_ONLY\x10\x02\x12\x1d\n" +
diff --git a/vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go b/vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go
index 1ff0d14..510894f 100644
--- a/vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go
+++ b/vendor/google.golang.org/protobuf/types/known/anypb/any.pb.go
@@ -128,120 +128,66 @@ import (
// `Any` contains an arbitrary serialized protocol buffer message along with a
// URL that describes the type of the serialized message.
//
-// Protobuf library provides support to pack/unpack Any values in the form
-// of utility functions or additional generated methods of the Any type.
-//
-// Example 1: Pack and unpack a message in C++.
-//
-// Foo foo = ...;
-// Any any;
-// any.PackFrom(foo);
-// ...
-// if (any.UnpackTo(&foo)) {
-// ...
-// }
-//
-// Example 2: Pack and unpack a message in Java.
-//
-// Foo foo = ...;
-// Any any = Any.pack(foo);
-// ...
-// if (any.is(Foo.class)) {
-// foo = any.unpack(Foo.class);
-// }
-// // or ...
-// if (any.isSameTypeAs(Foo.getDefaultInstance())) {
-// foo = any.unpack(Foo.getDefaultInstance());
-// }
-//
-// Example 3: Pack and unpack a message in Python.
-//
-// foo = Foo(...)
-// any = Any()
-// any.Pack(foo)
-// ...
-// if any.Is(Foo.DESCRIPTOR):
-// any.Unpack(foo)
-// ...
-//
-// Example 4: Pack and unpack a message in Go
-//
-// foo := &pb.Foo{...}
-// any, err := anypb.New(foo)
-// if err != nil {
-// ...
-// }
-// ...
-// foo := &pb.Foo{}
-// if err := any.UnmarshalTo(foo); err != nil {
-// ...
-// }
-//
-// The pack methods provided by protobuf library will by default use
-// 'type.googleapis.com/full.type.name' as the type URL and the unpack
-// methods only use the fully qualified type name after the last '/'
-// in the type URL, for example "foo.bar.com/x/y.z" will yield type
-// name "y.z".
-//
-// JSON
-// ====
-// The JSON representation of an `Any` value uses the regular
-// representation of the deserialized, embedded message, with an
-// additional field `@type` which contains the type URL. Example:
-//
-// package google.profile;
-// message Person {
-// string first_name = 1;
-// string last_name = 2;
-// }
-//
-// {
-// "@type": "type.googleapis.com/google.profile.Person",
-// "firstName": ,
-// "lastName":
-// }
-//
-// If the embedded message type is well-known and has a custom JSON
-// representation, that representation will be embedded adding a field
-// `value` which holds the custom JSON in addition to the `@type`
-// field. Example (for message [google.protobuf.Duration][]):
-//
-// {
-// "@type": "type.googleapis.com/google.protobuf.Duration",
-// "value": "1.212s"
-// }
+// In its binary encoding, an `Any` is an ordinary message; but in other wire
+// forms like JSON, it has a special encoding. The format of the type URL is
+// described on the `type_url` field.
+//
+// Protobuf APIs provide utilities to interact with `Any` values:
+//
+// - A 'pack' operation accepts a message and constructs a generic `Any` wrapper
+// around it.
+// - An 'unpack' operation reads the content of an `Any` message, either into an
+// existing message or a new one. Unpack operations must check the type of the
+// value they unpack against the declared `type_url`.
+// - An 'is' operation decides whether an `Any` contains a message of the given
+// type, i.e. whether it can 'unpack' that type.
+//
+// The JSON format representation of an `Any` follows one of these cases:
+//
+// - For types without special-cased JSON encodings, the JSON format
+// representation of the `Any` is the same as that of the message, with an
+// additional `@type` field which contains the type URL.
+// - For types with special-cased JSON encodings (typically called 'well-known'
+// types, listed in https://protobuf.dev/programming-guides/json/#any), the
+// JSON format representation has a key `@type` which contains the type URL
+// and a key `value` which contains the JSON-serialized value.
+//
+// The text format representation of an `Any` is like a message with one field
+// whose name is the type URL in brackets. For example, an `Any` containing a
+// `foo.Bar` message may be written `[type.googleapis.com/foo.Bar] { a: 2 }`.
type Any struct {
state protoimpl.MessageState `protogen:"open.v1"`
- // A URL/resource name that uniquely identifies the type of the serialized
- // protocol buffer message. This string must contain at least
- // one "/" character. The last segment of the URL's path must represent
- // the fully qualified name of the type (as in
- // `path/google.protobuf.Duration`). The name should be in a canonical form
- // (e.g., leading "." is not accepted).
+ // Identifies the type of the serialized Protobuf message with a URI reference
+ // consisting of a prefix ending in a slash and the fully-qualified type name.
+ //
+ // Example: type.googleapis.com/google.protobuf.StringValue
//
- // In practice, teams usually precompile into the binary all types that they
- // expect it to use in the context of Any. However, for URLs which use the
- // scheme `http`, `https`, or no scheme, one can optionally set up a type
- // server that maps type URLs to message definitions as follows:
+ // This string must contain at least one `/` character, and the content after
+ // the last `/` must be the fully-qualified name of the type in canonical
+ // form, without a leading dot. Do not write a scheme on these URI references
+ // so that clients do not attempt to contact them.
//
- // - If no scheme is provided, `https` is assumed.
- // - An HTTP GET on the URL must yield a [google.protobuf.Type][]
- // value in binary format, or produce an error.
- // - Applications are allowed to cache lookup results based on the
- // URL, or have them precompiled into a binary to avoid any
- // lookup. Therefore, binary compatibility needs to be preserved
- // on changes to types. (Use versioned type names to manage
- // breaking changes.)
+ // The prefix is arbitrary and Protobuf implementations are expected to
+ // simply strip off everything up to and including the last `/` to identify
+ // the type. `type.googleapis.com/` is a common default prefix that some
+ // legacy implementations require. This prefix does not indicate the origin of
+ // the type, and URIs containing it are not expected to respond to any
+ // requests.
//
- // Note: this functionality is not currently available in the official
- // protobuf release, and it is not used for type URLs beginning with
- // type.googleapis.com. As of May 2023, there are no widely used type server
- // implementations and no plans to implement one.
+ // All type URL strings must be legal URI references with the additional
+ // restriction (for the text format) that the content of the reference
+ // must consist only of alphanumeric characters, percent-encoded escapes, and
+ // characters in the following set (not including the outer backticks):
+ // `/-.~_!$&()*+,;=`. Despite our allowing percent encodings, implementations
+ // should not unescape them to prevent confusion with existing parsers. For
+ // example, `type.googleapis.com%2FFoo` should be rejected.
//
- // Schemes other than `http`, `https` (or the empty scheme) might be
- // used with implementation specific semantics.
+ // In the original design of `Any`, the possibility of launching a type
+ // resolution service at these type URLs was considered but Protobuf never
+ // implemented one and considers contacting these URLs to be problematic and
+ // a potential security issue. Do not attempt to contact type URLs.
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
- // Must be a valid serialized protocol buffer of the above specified type.
+ // Holds a Protobuf serialization of the type described by type_url.
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
diff --git a/vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go b/vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go
index 91ee89a..4a04379 100644
--- a/vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go
+++ b/vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go
@@ -197,24 +197,22 @@ import (
// An implementation may provide options to override this default behavior for
// repeated and message fields.
//
-// In order to reset a field's value to the default, the field must
-// be in the mask and set to the default value in the provided resource.
-// Hence, in order to reset all fields of a resource, provide a default
-// instance of the resource and set all fields in the mask, or do
-// not provide a mask as described below.
-//
-// If a field mask is not present on update, the operation applies to
-// all fields (as if a field mask of all fields has been specified).
-// Note that in the presence of schema evolution, this may mean that
-// fields the client does not know and has therefore not filled into
-// the request will be reset to their default. If this is unwanted
-// behavior, a specific service may require a client to always specify
-// a field mask, producing an error if not.
-//
-// As with get operations, the location of the resource which
-// describes the updated values in the request message depends on the
-// operation kind. In any case, the effect of the field mask is
-// required to be honored by the API.
+// Note that libraries which implement FieldMask resolution have various
+// different behaviors in the face of empty masks or the special "*" mask.
+// When implementing a service you should confirm these cases have the
+// appropriate behavior in the underlying FieldMask library that you desire,
+// and you may need to special case those cases in your application code if
+// the underlying field mask library behavior differs from your intended
+// service semantics.
+//
+// Update methods implementing https://google.aip.dev/134
+// - MUST support the special value * meaning "full replace"
+// - MUST treat an omitted field mask as "replace fields which are present".
+//
+// Other methods implementing https://google.aip.dev/157
+// - SHOULD support the special value "*" to mean "get all".
+// - MUST treat an omitted field mask to mean "get all", unless otherwise
+// documented.
//
// ## Considerations for HTTP REST
//
diff --git a/vendor/google.golang.org/protobuf/types/known/structpb/struct.pb.go b/vendor/google.golang.org/protobuf/types/known/structpb/struct.pb.go
index 30411b7..8325a50 100644
--- a/vendor/google.golang.org/protobuf/types/known/structpb/struct.pb.go
+++ b/vendor/google.golang.org/protobuf/types/known/structpb/struct.pb.go
@@ -131,10 +131,15 @@ import (
unsafe "unsafe"
)
-// `NullValue` is a singleton enumeration to represent the null value for the
-// `Value` type union.
+// Represents a JSON `null`.
//
-// The JSON representation for `NullValue` is JSON `null`.
+// `NullValue` is a sentinel, using an enum with only one value to represent
+// the null value for the `Value` type union.
+//
+// A field of type `NullValue` with any value other than `0` is considered
+// invalid. Most ProtoJSON serializers will emit a Value with a `null_value` set
+// as a JSON `null` regardless of the integer value, and so will round trip to
+// a `0` value.
type NullValue int32
const (
@@ -179,14 +184,19 @@ func (NullValue) EnumDescriptor() ([]byte, []int) {
return file_google_protobuf_struct_proto_rawDescGZIP(), []int{0}
}
-// `Struct` represents a structured data value, consisting of fields
-// which map to dynamically typed values. In some languages, `Struct`
-// might be supported by a native representation. For example, in
-// scripting languages like JS a struct is represented as an
-// object. The details of that representation are described together
-// with the proto support for the language.
+// Represents a JSON object.
+//
+// An unordered key-value map, intending to perfectly capture the semantics of a
+// JSON object. This enables parsing any arbitrary JSON payload as a message
+// field in ProtoJSON format.
+//
+// This follows RFC 8259 guidelines for interoperable JSON: notably this type
+// cannot represent large Int64 values or `NaN`/`Infinity` numbers,
+// since the JSON format generally does not support those values in its number
+// type.
//
-// The JSON representation for `Struct` is JSON object.
+// If you do not intend to parse arbitrary JSON into your message, a custom
+// typed message should be preferred instead of using this type.
type Struct struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Unordered map of dynamically typed values.
@@ -269,12 +279,12 @@ func (x *Struct) GetFields() map[string]*Value {
return nil
}
+// Represents a JSON value.
+//
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of these
-// variants. Absence of any variant indicates an error.
-//
-// The JSON representation for `Value` is JSON value.
+// variants. Absence of any variant is an invalid state.
type Value struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The kind of value.
@@ -548,32 +558,35 @@ type isValue_Kind interface {
}
type Value_NullValue struct {
- // Represents a null value.
+ // Represents a JSON `null`.
NullValue NullValue `protobuf:"varint,1,opt,name=null_value,json=nullValue,proto3,enum=google.protobuf.NullValue,oneof"`
}
type Value_NumberValue struct {
- // Represents a double value.
+ // Represents a JSON number. Must not be `NaN`, `Infinity` or
+ // `-Infinity`, since those are not supported in JSON. This also cannot
+ // represent large Int64 values, since JSON format generally does not
+ // support them in its number type.
NumberValue float64 `protobuf:"fixed64,2,opt,name=number_value,json=numberValue,proto3,oneof"`
}
type Value_StringValue struct {
- // Represents a string value.
+ // Represents a JSON string.
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof"`
}
type Value_BoolValue struct {
- // Represents a boolean value.
+ // Represents a JSON boolean (`true` or `false` literal in JSON).
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof"`
}
type Value_StructValue struct {
- // Represents a structured value.
+ // Represents a JSON object.
StructValue *Struct `protobuf:"bytes,5,opt,name=struct_value,json=structValue,proto3,oneof"`
}
type Value_ListValue struct {
- // Represents a repeated `Value`.
+ // Represents a JSON array.
ListValue *ListValue `protobuf:"bytes,6,opt,name=list_value,json=listValue,proto3,oneof"`
}
@@ -589,9 +602,7 @@ func (*Value_StructValue) isValue_Kind() {}
func (*Value_ListValue) isValue_Kind() {}
-// `ListValue` is a wrapper around a repeated field of values.
-//
-// The JSON representation for `ListValue` is JSON array.
+// Represents a JSON array.
type ListValue struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Repeated field of dynamically typed values.
diff --git a/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go b/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go
index 484c21f..2cd6094 100644
--- a/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go
+++ b/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go
@@ -153,8 +153,8 @@ import (
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
-// is required. A proto3 JSON serializer should always use UTC (as indicated by
-// "Z") when printing the Timestamp type and a proto3 JSON parser should be
+// is required. A ProtoJSON serializer should always use UTC (as indicated by
+// "Z") when printing the Timestamp type and a ProtoJSON parser should be
// able to accept both UTC and other timezones (as indicated by an offset).
//
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
@@ -173,7 +173,7 @@ import (
type Timestamp struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must
- // be between -315576000000 and 315576000000 inclusive (which corresponds to
+ // be between -62135596800 and 253402300799 inclusive (which corresponds to
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z).
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
// Non-negative fractions of a second at nanosecond resolution. This field is
diff --git a/vendor/modules.txt b/vendor/modules.txt
index bb8b1ba..51df1a6 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -4,21 +4,22 @@ github.com/clipperhouse/uax29/v2/graphemes
# github.com/google/jsonschema-go v0.4.3
## explicit; go 1.23.0
github.com/google/jsonschema-go/jsonschema
-# github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
-## explicit; go 1.25.0
+# github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0
+## explicit; go 1.26.0
github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule
github.com/grpc-ecosystem/grpc-gateway/v2/runtime
github.com/grpc-ecosystem/grpc-gateway/v2/utilities
-# github.com/jedib0t/go-pretty/v6 v6.8.0
+# github.com/jedib0t/go-pretty/v6 v6.8.3
## explicit; go 1.18
github.com/jedib0t/go-pretty/v6/table
github.com/jedib0t/go-pretty/v6/text
-# github.com/mattn/go-runewidth v0.0.24
-## explicit; go 1.20
+# github.com/mattn/go-runewidth v0.0.30
+## explicit; go 1.23
github.com/mattn/go-runewidth
-# github.com/modelcontextprotocol/go-sdk v1.6.1
+# github.com/modelcontextprotocol/go-sdk v1.8.0
## explicit; go 1.25.0
github.com/modelcontextprotocol/go-sdk/auth
+github.com/modelcontextprotocol/go-sdk/internal/authutil
github.com/modelcontextprotocol/go-sdk/internal/json
github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2
github.com/modelcontextprotocol/go-sdk/internal/mcpgodebug
@@ -27,7 +28,7 @@ github.com/modelcontextprotocol/go-sdk/internal/xcontext
github.com/modelcontextprotocol/go-sdk/jsonrpc
github.com/modelcontextprotocol/go-sdk/mcp
github.com/modelcontextprotocol/go-sdk/oauthex
-# github.com/olcf/s3m-apis v0.0.0-00010101000000-000000000000 => ./internal/pkg/s3m-apis
+# github.com/olcf/s3m-apis v0.4.0 => ./internal/pkg/s3m-apis
## explicit; go 1.26
github.com/olcf/s3m-apis/common/v1alpha
github.com/olcf/s3m-apis/pkg/s3mutil
@@ -53,14 +54,14 @@ github.com/segmentio/asm/keyset
github.com/segmentio/encoding/ascii
github.com/segmentio/encoding/iso8601
github.com/segmentio/encoding/json
-# github.com/urfave/cli/v3 v3.9.0
+# github.com/urfave/cli/v3 v3.13.0
## explicit; go 1.22
github.com/urfave/cli/v3
# github.com/yosida95/uritemplate/v3 v3.0.2
## explicit; go 1.14
github.com/yosida95/uritemplate/v3
-# golang.org/x/net v0.55.0
-## explicit; go 1.25.0
+# golang.org/x/net v0.59.0
+## explicit; go 1.26.0
golang.org/x/net/http/httpguts
golang.org/x/net/http2
golang.org/x/net/http2/hpack
@@ -69,35 +70,41 @@ golang.org/x/net/internal/httpcommon
golang.org/x/net/internal/httpsfv
golang.org/x/net/internal/timeseries
golang.org/x/net/trace
-# golang.org/x/oauth2 v0.36.0
-## explicit; go 1.25.0
+# golang.org/x/oauth2 v0.37.0
+## explicit; go 1.26.0
golang.org/x/oauth2
golang.org/x/oauth2/internal
-# golang.org/x/sys v0.46.0
-## explicit; go 1.25.0
+# golang.org/x/sync v0.23.0
+## explicit; go 1.26.0
+golang.org/x/sync/errgroup
+# golang.org/x/sys v0.48.0
+## explicit; go 1.26.0
golang.org/x/sys/cpu
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/term v0.44.0
-## explicit; go 1.25.0
+# golang.org/x/term v0.46.0
+## explicit; go 1.26.0
golang.org/x/term
-# golang.org/x/text v0.38.0
-## explicit; go 1.25.0
+# golang.org/x/text v0.42.0
+## explicit; go 1.26.0
golang.org/x/text/secure/bidirule
golang.org/x/text/transform
golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm
golang.org/x/text/width
-# google.golang.org/genproto/googleapis/api v0.0.0-20260608224507-4308a22a1bab
-## explicit; go 1.25.0
+# golang.org/x/time v0.16.0
+## explicit; go 1.26.0
+golang.org/x/time/rate
+# google.golang.org/genproto/googleapis/api v0.0.0-20260921155816-b14227669459
+## explicit; go 1.26.0
google.golang.org/genproto/googleapis/api
google.golang.org/genproto/googleapis/api/annotations
google.golang.org/genproto/googleapis/api/httpbody
-# google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab
-## explicit; go 1.25.0
+# google.golang.org/genproto/googleapis/rpc v0.0.0-20260921155816-b14227669459
+## explicit; go 1.26.0
google.golang.org/genproto/googleapis/rpc/status
-# google.golang.org/grpc v1.81.1
+# google.golang.org/grpc v1.84.0
## explicit; go 1.25.0
google.golang.org/grpc
google.golang.org/grpc/attributes
@@ -118,6 +125,7 @@ google.golang.org/grpc/credentials/insecure
google.golang.org/grpc/encoding
google.golang.org/grpc/encoding/internal
google.golang.org/grpc/encoding/proto
+google.golang.org/grpc/experimental/balancer/weight
google.golang.org/grpc/experimental/stats
google.golang.org/grpc/grpclog
google.golang.org/grpc/grpclog/internal
@@ -125,7 +133,6 @@ google.golang.org/grpc/health/grpc_health_v1
google.golang.org/grpc/internal
google.golang.org/grpc/internal/backoff
google.golang.org/grpc/internal/balancer/gracefulswitch
-google.golang.org/grpc/internal/balancer/weight
google.golang.org/grpc/internal/balancerload
google.golang.org/grpc/internal/binarylog
google.golang.org/grpc/internal/buffer
@@ -151,6 +158,7 @@ google.golang.org/grpc/internal/stats
google.golang.org/grpc/internal/status
google.golang.org/grpc/internal/syscall
google.golang.org/grpc/internal/transport
+google.golang.org/grpc/internal/transport/internal
google.golang.org/grpc/internal/transport/networktype
google.golang.org/grpc/internal/transport/readyreader
google.golang.org/grpc/keepalive
@@ -164,7 +172,7 @@ google.golang.org/grpc/stats
google.golang.org/grpc/status
google.golang.org/grpc/tap
google.golang.org/grpc/test/bufconn
-# google.golang.org/protobuf v1.36.11
+# google.golang.org/protobuf v1.36.12
## explicit; go 1.23
google.golang.org/protobuf/encoding/protojson
google.golang.org/protobuf/encoding/prototext