소스 검색

SVI Исправления, вендоринг

SVI 1 주 전
부모
커밋
a9c2af8856
100개의 변경된 파일5609개의 추가작업 그리고 1771개의 파일을 삭제
  1. 10 13
      cmd/arch/main.go
  2. 18 19
      go.mod
  3. 32 35
      go.sum
  4. 1 1
      lev0/types/icoord.go
  5. 1 1
      lev0/types/ielem_base.go
  6. 1 1
      lev0/types/ielem_drawer.go
  7. 1 1
      lev0/types/ilabel.go
  8. 1 1
      lev0/types/ilinker.go
  9. 1 1
      lev0/types/ioffset.go
  10. 5 1
      lev0/types/iservice.go
  11. 1 1
      lev0/types/iuse_case.go
  12. 1 1
      lev0/types/iuse_group_link.go
  13. 2 0
      lev2/lev2.go
  14. 0 0
      lev2/mod_http/index.html
  15. 32 46
      lev2/mod_http/serv_http.go
  16. 7 10
      lev3/fabrics/fabric_service.go
  17. 15 13
      lev3/service/service.go
  18. 1 1
      local.env
  19. 2 2
      pkg/elems/actor/actor.go
  20. 1 1
      pkg/elems/canvas/canvas.go
  21. 1 1
      pkg/elems/coord/coord.go
  22. 2 2
      pkg/elems/elem_base/elem_base.go
  23. 4 4
      pkg/elems/label/label.go
  24. 1 1
      pkg/elems/offset/offset.go
  25. 1 1
      pkg/elems/size/size.go
  26. 5 5
      pkg/elems/use_case/use_case.go
  27. 4 4
      pkg/elems/use_group/use_group.go
  28. 3 3
      pkg/elems/use_group_link/use_group_link.go
  29. 5 5
      pkg/elems/use_link/use_link.go
  30. 3 3
      pkg/views/view_actor/view_actor.go
  31. 3 3
      pkg/views/view_link/view_link.go
  32. 3 3
      pkg/views/view_use_case/view_use_case.go
  33. 3 3
      pkg/views/view_use_group/view_use_group.go
  34. 0 0
      static/js/htmx.min.js
  35. 9 4
      vendor/github.com/andybalholm/brotli/README.md
  36. 87 191
      vendor/github.com/andybalholm/brotli/brotli_bit_stream.go
  37. 2 2
      vendor/github.com/andybalholm/brotli/encoder.go
  38. 197 0
      vendor/github.com/andybalholm/brotli/encoder_fast.go
  39. 27 0
      vendor/github.com/andybalholm/brotli/flate/LICENSE
  40. 2 0
      vendor/github.com/andybalholm/brotli/flate/README.md
  41. 65 0
      vendor/github.com/andybalholm/brotli/flate/gzip.go
  42. 517 0
      vendor/github.com/andybalholm/brotli/flate/huffman_bit_writer.go
  43. 346 0
      vendor/github.com/andybalholm/brotli/flate/huffman_code.go
  44. 80 0
      vendor/github.com/andybalholm/brotli/flate/token.go
  45. 66 0
      vendor/github.com/andybalholm/brotli/flate/writer.go
  46. 8 3
      vendor/github.com/andybalholm/brotli/http.go
  47. 212 0
      vendor/github.com/andybalholm/brotli/matchfinder/bargain1.go
  48. 248 0
      vendor/github.com/andybalholm/brotli/matchfinder/bargain2.go
  49. 278 0
      vendor/github.com/andybalholm/brotli/matchfinder/bargain3.go
  50. 12 6
      vendor/github.com/andybalholm/brotli/matchfinder/m0.go
  51. 1 0
      vendor/github.com/andybalholm/brotli/matchfinder/m4.go
  52. 326 0
      vendor/github.com/andybalholm/brotli/matchfinder/trio.go
  53. 258 0
      vendor/github.com/andybalholm/brotli/matchfinder/zdfast.go
  54. 206 0
      vendor/github.com/andybalholm/brotli/matchfinder/zfast.go
  55. 301 0
      vendor/github.com/andybalholm/brotli/matchfinder/zm.go
  56. 1 1
      vendor/github.com/andybalholm/brotli/metablock_command.go
  57. 1 1
      vendor/github.com/andybalholm/brotli/metablock_distance.go
  58. 1 1
      vendor/github.com/andybalholm/brotli/metablock_literal.go
  59. 27 39
      vendor/github.com/andybalholm/brotli/writer.go
  60. 0 2
      vendor/github.com/clipperhouse/stringish/.gitignore
  61. 0 21
      vendor/github.com/clipperhouse/stringish/LICENSE
  62. 0 64
      vendor/github.com/clipperhouse/stringish/README.md
  63. 0 5
      vendor/github.com/clipperhouse/stringish/interface.go
  64. 50 24
      vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md
  65. 138 0
      vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go
  66. 79 0
      vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go
  67. 129 16
      vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go
  68. 39 8
      vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go
  69. 1235 930
      vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go
  70. 0 100
      vendor/github.com/clipperhouse/uax29/v2/internal/iterators/iterator.go
  71. 261 102
      vendor/github.com/dgraph-io/badger/v4/CHANGELOG.md
  72. 2 2
      vendor/github.com/dgraph-io/badger/v4/CODE_OF_CONDUCT.md
  73. 9 7
      vendor/github.com/dgraph-io/badger/v4/CONTRIBUTING.md
  74. 1 1
      vendor/github.com/dgraph-io/badger/v4/Makefile
  75. 35 16
      vendor/github.com/dgraph-io/badger/v4/README.md
  76. 1 1
      vendor/github.com/dgraph-io/badger/v4/SECURITY.md
  77. 1 1
      vendor/github.com/dgraph-io/badger/v4/backup.go
  78. 1 1
      vendor/github.com/dgraph-io/badger/v4/batch.go
  79. 1 1
      vendor/github.com/dgraph-io/badger/v4/changes.sh
  80. 1 1
      vendor/github.com/dgraph-io/badger/v4/compaction.go
  81. 2 2
      vendor/github.com/dgraph-io/badger/v4/db.go
  82. 144 0
      vendor/github.com/dgraph-io/badger/v4/dir_aix.go
  83. 1 1
      vendor/github.com/dgraph-io/badger/v4/dir_other.go
  84. 1 1
      vendor/github.com/dgraph-io/badger/v4/dir_plan9.go
  85. 3 3
      vendor/github.com/dgraph-io/badger/v4/dir_unix.go
  86. 3 3
      vendor/github.com/dgraph-io/badger/v4/dir_windows.go
  87. 1 1
      vendor/github.com/dgraph-io/badger/v4/discard.go
  88. 2 2
      vendor/github.com/dgraph-io/badger/v4/errors.go
  89. 1 1
      vendor/github.com/dgraph-io/badger/v4/fb/flatbuffer.fbs
  90. 1 1
      vendor/github.com/dgraph-io/badger/v4/histogram.go
  91. 2 2
      vendor/github.com/dgraph-io/badger/v4/iterator.go
  92. 3 3
      vendor/github.com/dgraph-io/badger/v4/key_registry.go
  93. 1 1
      vendor/github.com/dgraph-io/badger/v4/level_handler.go
  94. 2 2
      vendor/github.com/dgraph-io/badger/v4/levels.go
  95. 1 1
      vendor/github.com/dgraph-io/badger/v4/logger.go
  96. 1 1
      vendor/github.com/dgraph-io/badger/v4/managed_db.go
  97. 5 5
      vendor/github.com/dgraph-io/badger/v4/manifest.go
  98. 1 1
      vendor/github.com/dgraph-io/badger/v4/memtable.go
  99. 1 1
      vendor/github.com/dgraph-io/badger/v4/merge.go
  100. 1 1
      vendor/github.com/dgraph-io/badger/v4/options.go

+ 10 - 13
cmd/arch/main.go

@@ -2,21 +2,18 @@
 package main
 
 import (
-	"log"
-	"os"
+	"gitp78su.ipnodns.ru/svi/kern/v3/kc/log_buf"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev3/fabrics"
+	"gitp78su.ipnodns.ru/svi/goarch/lev3/fabrics"
 )
 
 func main() {
-	log.Println("main()")
-	serv, err := fabrics.NewService()
-	if err != nil {
-		log.Printf("main(): in NewService(), err=\n\t%v\n", err)
-		os.Exit(1)
-	}
-	if err := serv.Run(); err != nil {
-		log.Printf("main(): in IService.Run(), err=\n\t%v\n", err)
-		os.Exit(2)
-	}
+	optTerm := log_buf.OptIsTerm(true)
+	optPref := log_buf.OptPrefix("main")
+	log := log_buf.NewLogBuf(optPref, optTerm)
+	log.Info("main()")
+	serv := fabrics.NewService()
+
+	resServ := serv.Run()
+	resServ.Hassert("main(): in IService.Run()")
 }

+ 18 - 19
go.mod

@@ -1,36 +1,35 @@
-module gitp78su.ipnodns.ru/svi/test_arch
+module gitp78su.ipnodns.ru/svi/goarch
 
-go 1.24.4
+go 1.26.2
 
 require (
 	github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b
-	github.com/gofiber/fiber/v2 v2.52.10
+	github.com/gofiber/fiber/v2 v2.52.13
 	gitp78su.ipnodns.ru/svi/kern/v3 v3.1.1
 )
 
 require (
-	github.com/andybalholm/brotli v1.2.0 // indirect
+	github.com/andybalholm/brotli v1.2.1 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
-	github.com/clipperhouse/stringish v0.1.1 // indirect
-	github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
-	github.com/dgraph-io/badger/v4 v4.8.0 // indirect
-	github.com/dgraph-io/ristretto/v2 v2.3.0 // indirect
+	github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
+	github.com/dgraph-io/badger/v4 v4.9.1 // indirect
+	github.com/dgraph-io/ristretto/v2 v2.4.0 // indirect
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/go-logr/logr v1.4.3 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
-	github.com/google/flatbuffers v25.9.23+incompatible // indirect
+	github.com/google/flatbuffers v25.12.19+incompatible // indirect
 	github.com/google/uuid v1.6.0 // indirect
-	github.com/klauspost/compress v1.18.1 // indirect
+	github.com/klauspost/compress v1.18.6 // indirect
 	github.com/mattn/go-colorable v0.1.14 // indirect
-	github.com/mattn/go-isatty v0.0.20 // indirect
-	github.com/mattn/go-runewidth v0.0.19 // indirect
+	github.com/mattn/go-isatty v0.0.22 // indirect
+	github.com/mattn/go-runewidth v0.0.23 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
-	github.com/valyala/fasthttp v1.68.0 // indirect
+	github.com/valyala/fasthttp v1.71.0 // indirect
 	go.opentelemetry.io/auto/sdk v1.2.1 // indirect
-	go.opentelemetry.io/otel v1.38.0 // indirect
-	go.opentelemetry.io/otel/metric v1.38.0 // indirect
-	go.opentelemetry.io/otel/trace v1.38.0 // indirect
-	golang.org/x/net v0.47.0 // indirect
-	golang.org/x/sys v0.38.0 // indirect
-	google.golang.org/protobuf v1.36.10 // indirect
+	go.opentelemetry.io/otel v1.43.0 // indirect
+	go.opentelemetry.io/otel/metric v1.43.0 // indirect
+	go.opentelemetry.io/otel/trace v1.43.0 // indirect
+	golang.org/x/net v0.53.0 // indirect
+	golang.org/x/sys v0.43.0 // indirect
+	google.golang.org/protobuf v1.36.11 // indirect
 )

+ 32 - 35
go.sum

@@ -3,20 +3,18 @@ github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm
 github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
 github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
 github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
-github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
-github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
+github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
+github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
 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/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
-github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
-github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4=
-github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
+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/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yhN/bs=
-github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w=
-github.com/dgraph-io/ristretto/v2 v2.3.0 h1:qTQ38m7oIyd4GAed/QkUZyPFNMnvVWyazGXRwvOt5zk=
-github.com/dgraph-io/ristretto/v2 v2.3.0/go.mod h1:gpoRV3VzrEY1a9dWAYV6T1U7YzfgttXdd/ZzL1s9OZM=
+github.com/dgraph-io/badger/v4 v4.9.1 h1:DocZXZkg5JJHJPtUErA0ibyHxOVUDVoXLSCV6t8NC8w=
+github.com/dgraph-io/badger/v4 v4.9.1/go.mod h1:5/MEx97uzdPUHR4KtkNt8asfI2T4JiEiQlV7kWUo8c0=
+github.com/dgraph-io/ristretto/v2 v2.4.0 h1:I/w09yLjhdcVD2QV192UJcq8dPBaAJb9pOuMyNy0XlU=
+github.com/dgraph-io/ristretto/v2 v2.4.0/go.mod h1:0KsrXtXvnv0EqnzyowllbVJB8yBonswa2lTCK2gGo9E=
 github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
 github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -26,31 +24,31 @@ 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/gofiber/fiber/v2 v2.52.10 h1:jRHROi2BuNti6NYXmZ6gbNSfT3zj/8c0xy94GOU5elY=
-github.com/gofiber/fiber/v2 v2.52.10/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
-github.com/google/flatbuffers v25.9.23+incompatible h1:rGZKv+wOb6QPzIdkM2KxhBZCDrA0DeN6DNmRDrqIsQU=
-github.com/google/flatbuffers v25.9.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/gofiber/fiber/v2 v2.52.13 h1:TOKP64iqC9b5P49VrBW5tHhUOvDyrtJ0xePEfzJbCbk=
+github.com/gofiber/fiber/v2 v2.52.13/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
+github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs=
+github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
 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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
-github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
+github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
+github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
 github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
 github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
-github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
+github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
+github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
+github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
 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/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
 github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.68.0 h1:v12Nx16iepr8r9ySOwqI+5RBJ/DqTxhOy1HrHoDFnok=
-github.com/valyala/fasthttp v1.68.0/go.mod h1:5EXiRfYQAoiO/khu4oU9VISC/eVY6JqmSpPJoHCKsz4=
+github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY3k=
+github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA=
 github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
 github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -58,12 +56,12 @@ gitp78su.ipnodns.ru/svi/kern/v3 v3.1.1 h1:1ymYrax2WuEB13JSj0aA9pUQJU/VGRI7CpqTyF
 gitp78su.ipnodns.ru/svi/kern/v3 v3.1.1/go.mod h1:hq6dlAu+6/x2HJAA1yXKRRILaBXFzywBdgXIL5uwEwg=
 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.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
-go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
-go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
-go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
-go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
-go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
+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/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/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -71,17 +69,16 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
-golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
+golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
+golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
-golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
+golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -90,8 +87,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
-google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+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=
 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=

+ 1 - 1
lev0/types/icoord.go

@@ -1,6 +1,6 @@
 package types
 
-import "gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+import "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 
 // ICoord -- интерфейс координат
 type ICoord interface {

+ 1 - 1
lev0/types/ielem_base.go

@@ -1,7 +1,7 @@
 package types
 
 import (
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 )
 
 // IElemBase -- интерфейс элемента схемы

+ 1 - 1
lev0/types/ielem_drawer.go

@@ -3,7 +3,7 @@ package types
 import (
 	svg "github.com/ajstarks/svgo"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 )
 
 // IElemDrawer -- интерфейс элемента схемы для рисования

+ 1 - 1
lev0/types/ilabel.go

@@ -1,7 +1,7 @@
 package types
 
 import (
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 )
 
 // ILabel -- надпись с координатами XY

+ 1 - 1
lev0/types/ilinker.go

@@ -1,6 +1,6 @@
 package types
 
-import "gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+import "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 
 // ILinker -- интерфейс связи между объектами
 type ILinker interface {

+ 1 - 1
lev0/types/ioffset.go

@@ -1,6 +1,6 @@
 package types
 
-import "gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+import "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 
 // IOffset -- интерфейс смещения
 type IOffset interface {

+ 5 - 1
lev0/types/iservice.go

@@ -1,8 +1,12 @@
 // package types -- интерфейсы сервиса
 package types
 
+import (
+	"gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
+)
+
 // IService -- интерфейс сервиса
 type IService interface {
 	// Run -- запуск сервиса
-	Run() error
+	Run() ktypes.Result[bool]
 }

+ 1 - 1
lev0/types/iuse_case.go

@@ -1,6 +1,6 @@
 package types
 
-import "gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+import "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 
 // IUseCase -- интерфейс к вариантам использования
 type IUseCase interface {

+ 1 - 1
lev0/types/iuse_group_link.go

@@ -1,6 +1,6 @@
 package types
 
-import "gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+import "gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 
 // IUseGroupLink -- интерфейс группы ссылок
 type IUseGroupLink interface {

+ 2 - 0
lev2/lev2.go

@@ -0,0 +1,2 @@
+// package lev2 -- уровень модулей
+package lev2

+ 0 - 0
internal/serv_http/index.html → lev2/mod_http/index.html


+ 32 - 46
internal/serv_http/serv_http.go → lev2/mod_http/serv_http.go

@@ -1,5 +1,5 @@
-// package serv_http -- http-сервис для архитектуры
-package serv_http
+// package mod_http -- http-модуль для архитектуры
+package mod_http
 
 import (
 	"bytes"
@@ -11,61 +11,47 @@ import (
 
 	svg "github.com/ajstarks/svgo"
 	"github.com/gofiber/fiber/v2"
-	"github.com/gofiber/fiber/v2/middleware/compress"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/cons"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/canvas"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/views/view_actor"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/views/view_link"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/views/view_use_case"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/views/view_use_group"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/cons"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/canvas"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/views/view_actor"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/views/view_link"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/views/view_use_case"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/views/view_use_group"
+	"gitp78su.ipnodns.ru/svi/kern/v3"
+	"gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
 )
 
 //go:embed index.html
 var indexHtml []byte
 
-// ServHttp -- http-сервис для архитектуры
-type ServHttp struct {
-	fibApp     *fiber.App
+// ModHttp -- http-модуль для архитектуры
+type ModHttp struct {
+	// fibApp     *fiber.App
+	kCtx       ktypes.IKernelCtx
 	diaMode    string // Режим диаграммы
 	oldBinArch []byte // Кеш старой архитектуры
 }
 
-// NewServHttp -- возвращает новый сервис
-func NewServHttp() (*ServHttp, error) {
-	fibConf := fiber.Config{
-		ServerHeader:      "Server: test_arch",
-		UnescapePath:      true,
-		Network:           fiber.NetworkTCP4,
-		EnablePrintRoutes: true,
-	}
-	fibApp := fiber.New(fibConf)
-	sf := &ServHttp{
-		fibApp:  fibApp,
+// NewModHttp -- возвращает новый сервис
+func NewModHttp() *ModHttp {
+	sf := &ModHttp{
+		kCtx:    kern.GetKernelCtx(),
 		diaMode: cons.ModeUseCase,
 	}
-	sf.fibApp.Use(compress.New(compress.Config{
-		Level: compress.LevelBestSpeed, // 1
-	}))
-	sf.fibApp.Static("/static", "./static", fiber.Static{
+	sHttp := kern.GetKernelServerHttp()
+	fibApp := sHttp.Fiber()
+	fibApp.Static("/static", "./static", fiber.Static{
 		Compress:      true,
 		Browse:        true,
 		CacheDuration: time.Second * 10,
 	})
-	sf.fibApp.Get("/", sf.indexGet)
-	sf.fibApp.Get("/use_case", sf.setModeUseCase)
-	sf.fibApp.Post("/arch", sf.archPost)
-	return sf, nil
-}
-
-// Run -- запуск http-сервиса
-func (sf *ServHttp) Run() error {
-	if err := sf.fibApp.Listen(":8100"); err != nil {
-		return fmt.Errorf("ServHttp.Run(): in listen, err=\n\t%w", err)
-	}
-	return nil
+	fibApp.Get("/", sf.indexGet)
+	fibApp.Get("/use_case", sf.setModeUseCase)
+	fibApp.Post("/arch", sf.archPost)
+	return sf
 }
 
 // FormArch -- извлекает данные из текстового поля для обновления
@@ -74,7 +60,7 @@ type FormArch struct {
 }
 
 // Возвращает новый холст
-func (sf *ServHttp) canvas(wr *bytes.Buffer, lstElem []map[string]interface{}) (*svg.SVG, error) {
+func (sf *ModHttp) canvas(wr *bytes.Buffer, lstElem []map[string]interface{}) (*svg.SVG, error) {
 	var (
 		elem         map[string]interface{}
 		isFind, isOk bool
@@ -106,7 +92,7 @@ func (sf *ServHttp) canvas(wr *bytes.Buffer, lstElem []map[string]interface{}) (
 }
 
 // По запросы парсит, что получилось -- обновляет архитектуру
-func (sf *ServHttp) archPost(ctx *fiber.Ctx) error {
+func (sf *ModHttp) archPost(ctx *fiber.Ctx) error {
 	form := &FormArch{}
 	if err := ctx.BodyParser(form); err != nil {
 		return ctx.SendString(fmt.Sprintf("ServHttp.archPost(): in BodyParser, err=<br>%v", err))
@@ -140,7 +126,7 @@ func (sf *ServHttp) archPost(ctx *fiber.Ctx) error {
 }
 
 // Формирует варианты использования
-func (sf *ServHttp) useCase(canvas *svg.SVG, lstElem []map[string]interface{}) error {
+func (sf *ModHttp) useCase(canvas *svg.SVG, lstElem []map[string]interface{}) error {
 	mapDraw := make(map[alias.Id]types.IElemDrawer)
 	for _, elem := range lstElem {
 		_id, isOk := elem["id"]
@@ -209,13 +195,13 @@ func (sf *ServHttp) useCase(canvas *svg.SVG, lstElem []map[string]interface{}) e
 }
 
 // Возвращает картинку архитектуры
-func (sf *ServHttp) setModeUseCase(ctx *fiber.Ctx) error {
+func (sf *ModHttp) setModeUseCase(ctx *fiber.Ctx) error {
 	sf.diaMode = cons.ModeUseCase
 	return ctx.SendString("[mode='" + sf.diaMode + "']")
 }
 
 // Возвращает главную страницу сервиса
-func (sf *ServHttp) indexGet(ctx *fiber.Ctx) error {
+func (sf *ModHttp) indexGet(ctx *fiber.Ctx) error {
 	ctx.Response().Header.Set("Content-Type", "text/html")
 	return ctx.Send(indexHtml)
 }

+ 7 - 10
lev3/fabrics/fabric_service.go

@@ -2,18 +2,15 @@
 package fabrics
 
 import (
-	"fmt"
+	// "fmt"
+	// "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev3/service"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/lev3/service"
 )
 
 // NewService -- возвращает новый сервис
-func NewService() (types.IService, error) {
-	sf, err := service.NewService()
-	if err != nil {
-		return nil, fmt.Errorf("NewService(): in create IService, err=\n\t%w", err)
-	}
-
-	return sf, nil
+func NewService() types.IService {
+	sf := service.NewService()
+	return sf
 }

+ 15 - 13
lev3/service/service.go

@@ -2,31 +2,33 @@
 package service
 
 import (
+	"gitp78su.ipnodns.ru/svi/goarch/lev2/mod_http"
 	"gitp78su.ipnodns.ru/svi/kern/v3"
+	"gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
 	. "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes"
 )
 
 // Service -- тип сервиса
 type Service struct {
-	ctx      IKernelCtx
-	servHttp IKernelServerHttp
+	kCtx    IKernelCtx
+	modHttp *mod_http.ModHttp
 }
 
 // NewService -- возвращает новый сервис
-func NewService() (*Service, error) {
-	ctx := kern.GetKernelCtx()
-	ctx.Set("monolitName", "SviArch", "NewService()")
-	servHttp := kern.GetKernelServerHttp()
+func NewService() *Service {
+	kCtx := kern.GetKernelCtx()
+	kCtx.Set("monolitName", "SviArch", "NewService()")
 	sf := &Service{
-		ctx:      kern.GetKernelCtx(),
-		servHttp: servHttp,
+		kCtx:    kern.GetKernelCtx(),
+		modHttp: mod_http.NewModHttp(),
 	}
-	return sf, nil
+	return sf
 }
 
 // Run -- запуск сервиса
-func (sf *Service) Run() error {
-	sf.servHttp.Run()
-	sf.ctx.Wg().Wait()
-	return nil
+func (sf *Service) Run() ktypes.Result[bool] {
+	sHttp := sf.kCtx.Get("kServHttp").Val().(ktypes.IKernelServerHttp)
+	go sHttp.Run()
+	sf.kCtx.Wg().Wait()
+	return ktypes.NewOk(true)
 }

+ 1 - 1
local.env

@@ -1 +1 @@
-LOCAL_HTTP_URL=http://localhost:28080/
+LOCAL_HTTP_URL=http://localhost:18000/

+ 2 - 2
pkg/elems/actor/actor.go

@@ -4,8 +4,8 @@ package actor
 import (
 	"fmt"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/label"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/use_group_link"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/label"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/use_group_link"
 )
 
 // Actor -- сущность актора

+ 1 - 1
pkg/elems/canvas/canvas.go

@@ -4,7 +4,7 @@ package canvas
 import (
 	svg "github.com/ajstarks/svgo"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/coord"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/coord"
 )
 
 // Canvas -- оюъект холста

+ 1 - 1
pkg/elems/coord/coord.go

@@ -2,7 +2,7 @@
 package coord
 
 import (
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 )
 
 // Coord -- координаты точки

+ 2 - 2
pkg/elems/elem_base/elem_base.go

@@ -5,8 +5,8 @@ import (
 	"encoding/json"
 	"fmt"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/label"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/label"
 )
 
 // ElemBase -- базовый объект

+ 4 - 4
pkg/elems/label/label.go

@@ -2,10 +2,10 @@
 package label
 
 import (
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/coord"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/offset"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/coord"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/offset"
 )
 
 // Label -- текстовая метка для отображения

+ 1 - 1
pkg/elems/offset/offset.go

@@ -2,7 +2,7 @@
 package offset
 
 import (
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 )
 
 // Offset -- смещение точки

+ 1 - 1
pkg/elems/size/size.go

@@ -2,7 +2,7 @@
 package size
 
 import (
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
 )
 
 // Size -- размер области

+ 5 - 5
pkg/elems/use_case/use_case.go

@@ -4,11 +4,11 @@ package use_case
 import (
 	"fmt"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/cons"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/elem_base"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/size"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/cons"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/elem_base"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/size"
 )
 
 // UseCase -- вариант использования

+ 4 - 4
pkg/elems/use_group/use_group.go

@@ -4,10 +4,10 @@ package use_group
 import (
 	"fmt"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/elem_base"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/size"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/elem_base"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/size"
 )
 
 // UseGroup -- группа вариантов использования

+ 3 - 3
pkg/elems/use_group_link/use_group_link.go

@@ -4,9 +4,9 @@ package use_group_link
 import (
 	"fmt"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/elem_base"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/elem_base"
 )
 
 // UseGroupLink -- группа связей в вариантах использования

+ 5 - 5
pkg/elems/use_link/use_link.go

@@ -4,11 +4,11 @@ package use_link
 import (
 	"fmt"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/cons"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/coord"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/elem_base"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/cons"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/coord"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/elem_base"
 )
 
 // UseLink -- связь между объектами

+ 3 - 3
pkg/views/view_actor/view_actor.go

@@ -7,9 +7,9 @@ import (
 
 	svg "github.com/ajstarks/svgo"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/actor"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/actor"
 )
 
 // ViewActor -- SVG-фигура актора

+ 3 - 3
pkg/views/view_link/view_link.go

@@ -6,9 +6,9 @@ import (
 
 	svg "github.com/ajstarks/svgo"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/use_link"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/use_link"
 )
 
 // Link -- отображение связи между объектами

+ 3 - 3
pkg/views/view_use_case/view_use_case.go

@@ -6,9 +6,9 @@ import (
 
 	svg "github.com/ajstarks/svgo"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/use_case"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/use_case"
 )
 
 // ViewUseCase -- вариант использования

+ 3 - 3
pkg/views/view_use_group/view_use_group.go

@@ -6,9 +6,9 @@ import (
 
 	svg "github.com/ajstarks/svgo"
 
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/alias"
-	"gitp78su.ipnodns.ru/svi/test_arch/lev0/types"
-	"gitp78su.ipnodns.ru/svi/test_arch/pkg/elems/use_group"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/alias"
+	"gitp78su.ipnodns.ru/svi/goarch/lev0/types"
+	"gitp78su.ipnodns.ru/svi/goarch/pkg/elems/use_group"
 )
 
 // ViewUseGroup -- отображение группы вариантов использования

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
static/js/htmx.min.js


+ 9 - 4
vendor/github.com/andybalholm/brotli/README.md

@@ -2,13 +2,18 @@ This package is a brotli compressor and decompressor implemented in Go.
 It was translated from the reference implementation (https://github.com/google/brotli)
 with the `c2go` tool at https://github.com/andybalholm/c2go.
 
+I am using it in production with https://github.com/andybalholm/redwood.
+
+API documentation is found at https://pkg.go.dev/github.com/andybalholm/brotli?tab=doc.
+
+## Roadmap
+
 I have been working on new compression algorithms (not translated from C)
 in the matchfinder package.
 You can use them with the NewWriterV2 function.
 Currently they give better results than the old implementation
 (at least for compressing my test file, Newton’s *Opticks*) 
-on levels 2 to 6.
-
-I am using it in production with https://github.com/andybalholm/redwood.
+on levels 0 to 9.
 
-API documentation is found at https://pkg.go.dev/github.com/andybalholm/brotli?tab=doc.
+The new APIs are currently considered experimental,
+and are not covered by any SemVer compatibility guarantees.

+ 87 - 191
vendor/github.com/andybalholm/brotli/brotli_bit_stream.go

@@ -1,7 +1,7 @@
 package brotli
 
 import (
-	"math"
+	"slices"
 	"sync"
 )
 
@@ -438,12 +438,6 @@ func buildAndStoreHuffmanTree(histogram []uint32, histogram_length uint, alphabe
 	}
 }
 
-func sortHuffmanTree1(v0 huffmanTree, v1 huffmanTree) bool {
-	return v0.total_count_ < v1.total_count_
-}
-
-var huffmanTreePool sync.Pool
-
 func buildAndStoreHuffmanTreeFast(histogram []uint32, histogram_total uint, max_bits uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {
 	var count uint = 0
 	var symbols = [4]uint{0}
@@ -470,98 +464,7 @@ func buildAndStoreHuffmanTreeFast(histogram []uint32, histogram_total uint, max_
 		return
 	}
 
-	for i := 0; i < int(length); i++ {
-		depth[i] = 0
-	}
-	{
-		var max_tree_size uint = 2*length + 1
-		tree, _ := huffmanTreePool.Get().(*[]huffmanTree)
-		if tree == nil || cap(*tree) < int(max_tree_size) {
-			tmp := make([]huffmanTree, max_tree_size)
-			tree = &tmp
-		} else {
-			*tree = (*tree)[:max_tree_size]
-		}
-		var count_limit uint32
-		for count_limit = 1; ; count_limit *= 2 {
-			var node int = 0
-			var l uint
-			for l = length; l != 0; {
-				l--
-				if histogram[l] != 0 {
-					if histogram[l] >= count_limit {
-						initHuffmanTree(&(*tree)[node:][0], histogram[l], -1, int16(l))
-					} else {
-						initHuffmanTree(&(*tree)[node:][0], count_limit, -1, int16(l))
-					}
-
-					node++
-				}
-			}
-			{
-				var n int = node
-				/* Points to the next leaf node. */ /* Points to the next non-leaf node. */
-				var sentinel huffmanTree
-				var i int = 0
-				var j int = n + 1
-				var k int
-
-				sortHuffmanTreeItems(*tree, uint(n), huffmanTreeComparator(sortHuffmanTree1))
-
-				/* The nodes are:
-				   [0, n): the sorted leaf nodes that we start with.
-				   [n]: we add a sentinel here.
-				   [n + 1, 2n): new parent nodes are added here, starting from
-				                (n+1). These are naturally in ascending order.
-				   [2n]: we add a sentinel at the end as well.
-				   There will be (2n+1) elements at the end. */
-				initHuffmanTree(&sentinel, math.MaxUint32, -1, -1)
-
-				(*tree)[node] = sentinel
-				node++
-				(*tree)[node] = sentinel
-				node++
-
-				for k = n - 1; k > 0; k-- {
-					var left int
-					var right int
-					if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
-						left = i
-						i++
-					} else {
-						left = j
-						j++
-					}
-
-					if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
-						right = i
-						i++
-					} else {
-						right = j
-						j++
-					}
-
-					/* The sentinel node becomes the parent node. */
-					(*tree)[node-1].total_count_ = (*tree)[left].total_count_ + (*tree)[right].total_count_
-
-					(*tree)[node-1].index_left_ = int16(left)
-					(*tree)[node-1].index_right_or_value_ = int16(right)
-
-					/* Add back the last sentinel node. */
-					(*tree)[node] = sentinel
-					node++
-				}
-
-				if setDepth(2*n-1, *tree, depth, 14) {
-					/* We need to pack the Huffman tree in 14 bits. If this was not
-					   successful, add fake entities to the lowest values and retry. */
-					break
-				}
-			}
-		}
-
-		huffmanTreePool.Put(tree)
-	}
+	chooseBitDepths(histogram[:length], depth[:length], 14)
 
 	convertBitDepthsToSymbols(depth, length, bits)
 	if count <= 4 {
@@ -647,6 +550,90 @@ func buildAndStoreHuffmanTreeFast(histogram []uint32, histogram_total uint, max_
 	}
 }
 
+type symbolAndCount struct {
+	symbol uint32
+	count  uint32
+}
+
+func chooseBitDepths(histogram []uint32, depth []byte, maxBits int) {
+	totalCodeSpace := 1 << maxBits
+	symbols := make([]symbolAndCount, 0, 704 /* static capacity so that it will be stack allocated */)
+	var totalCount uint32 = 0
+	for i, n := range histogram {
+		if n != 0 {
+			symbols = append(symbols, symbolAndCount{
+				symbol: uint32(i),
+				count:  n,
+			})
+			totalCount += n
+		}
+	}
+	slices.SortFunc(symbols, func(a, b symbolAndCount) int {
+		return int(b.count) - int(a.count)
+	})
+
+	// boundaries contains indexes into symbols such that (for example)
+	// boundaries[8] is the index of the first 8-bit symbol.
+	boundaries := make([]int, maxBits+1, 20 /* static capacity for stack allocation */)
+
+	codeSpaceUsed := 0
+
+	// Assign initial boundaries conservatively, making sure no symbol uses more
+	// than its share of code space.
+	totalRatio := float64(totalCount) / float64(totalCodeSpace)
+	currentDepth := 1
+	for i, symbol := range symbols {
+		for currentDepth < maxBits && float64(symbol.count)/float64(int(1)<<(maxBits-currentDepth)) < totalRatio {
+			currentDepth++
+			boundaries[currentDepth] = i
+		}
+		codeSpaceUsed += 1 << (maxBits - currentDepth)
+	}
+	for i := currentDepth + 1; i <= maxBits; i++ {
+		boundaries[i] = len(symbols)
+	}
+
+	// Move the boundaries till the code space is filled.
+	for codeSpaceUsed < totalCodeSpace {
+		available := totalCodeSpace - codeSpaceUsed
+		// Find the most efficient boundary to move, based on the ratio of how
+		// many times the symbol was used to how much code space will be consumed.
+		bestRatio := 0.0
+		bestBoundary := 0
+		for i := 2; i <= maxBits; i++ {
+			cost := 1 << (maxBits - i) // code space that would be used by moving this boundary
+			if cost > available {
+				continue
+			}
+			if boundaries[i] == len(symbols) {
+				continue
+			}
+			if i < maxBits && boundaries[i] == boundaries[i+1] {
+				continue
+			}
+			ratio := float64(symbols[boundaries[i]].count) / float64(cost)
+			if ratio > bestRatio {
+				bestRatio = ratio
+				bestBoundary = i
+			}
+		}
+		boundaries[bestBoundary]++
+		codeSpaceUsed += 1 << (maxBits - bestBoundary)
+	}
+
+	for i := range depth {
+		depth[i] = 0
+	}
+	for i := 1; i < maxBits; i++ {
+		for j := boundaries[i]; j < boundaries[i+1]; j++ {
+			depth[symbols[j].symbol] = byte(i)
+		}
+	}
+	for j := boundaries[maxBits]; j < len(symbols); j++ {
+		depth[symbols[j].symbol] = byte(maxBits)
+	}
+}
+
 func buildAndStoreHuffmanTreeFastBW(histogram []uint32, histogram_total uint, max_bits uint, depth []byte, bits []uint16, bw *bitWriter) {
 	var count uint = 0
 	var symbols = [4]uint{0}
@@ -673,98 +660,7 @@ func buildAndStoreHuffmanTreeFastBW(histogram []uint32, histogram_total uint, ma
 		return
 	}
 
-	for i := 0; i < int(length); i++ {
-		depth[i] = 0
-	}
-	{
-		var max_tree_size uint = 2*length + 1
-		tree, _ := huffmanTreePool.Get().(*[]huffmanTree)
-		if tree == nil || cap(*tree) < int(max_tree_size) {
-			tmp := make([]huffmanTree, max_tree_size)
-			tree = &tmp
-		} else {
-			*tree = (*tree)[:max_tree_size]
-		}
-		var count_limit uint32
-		for count_limit = 1; ; count_limit *= 2 {
-			var node int = 0
-			var l uint
-			for l = length; l != 0; {
-				l--
-				if histogram[l] != 0 {
-					if histogram[l] >= count_limit {
-						initHuffmanTree(&(*tree)[node:][0], histogram[l], -1, int16(l))
-					} else {
-						initHuffmanTree(&(*tree)[node:][0], count_limit, -1, int16(l))
-					}
-
-					node++
-				}
-			}
-			{
-				var n int = node
-				/* Points to the next leaf node. */ /* Points to the next non-leaf node. */
-				var sentinel huffmanTree
-				var i int = 0
-				var j int = n + 1
-				var k int
-
-				sortHuffmanTreeItems(*tree, uint(n), huffmanTreeComparator(sortHuffmanTree1))
-
-				/* The nodes are:
-				   [0, n): the sorted leaf nodes that we start with.
-				   [n]: we add a sentinel here.
-				   [n + 1, 2n): new parent nodes are added here, starting from
-				                (n+1). These are naturally in ascending order.
-				   [2n]: we add a sentinel at the end as well.
-				   There will be (2n+1) elements at the end. */
-				initHuffmanTree(&sentinel, math.MaxUint32, -1, -1)
-
-				(*tree)[node] = sentinel
-				node++
-				(*tree)[node] = sentinel
-				node++
-
-				for k = n - 1; k > 0; k-- {
-					var left int
-					var right int
-					if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
-						left = i
-						i++
-					} else {
-						left = j
-						j++
-					}
-
-					if (*tree)[i].total_count_ <= (*tree)[j].total_count_ {
-						right = i
-						i++
-					} else {
-						right = j
-						j++
-					}
-
-					/* The sentinel node becomes the parent node. */
-					(*tree)[node-1].total_count_ = (*tree)[left].total_count_ + (*tree)[right].total_count_
-
-					(*tree)[node-1].index_left_ = int16(left)
-					(*tree)[node-1].index_right_or_value_ = int16(right)
-
-					/* Add back the last sentinel node. */
-					(*tree)[node] = sentinel
-					node++
-				}
-
-				if setDepth(2*n-1, *tree, depth, 14) {
-					/* We need to pack the Huffman tree in 14 bits. If this was not
-					   successful, add fake entities to the lowest values and retry. */
-					break
-				}
-			}
-		}
-
-		huffmanTreePool.Put(tree)
-	}
+	chooseBitDepths(histogram[:length], depth[:length], 14)
 
 	convertBitDepthsToSymbols(depth, length, bits)
 	if count <= 4 {

+ 2 - 2
vendor/github.com/andybalholm/brotli/encoder.go

@@ -60,7 +60,7 @@ func (e *Encoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, la
 			// If the stream ends with unmatched bytes, we need a dummy copy length.
 			copyCode = 2
 		}
-		command := combineLengthCodes(insertCode, copyCode, false)
+		command := combineLengthCodes(insertCode, copyCode, i > 0 && m.Distance == matches[i-1].Distance)
 		commandHisto[command]++
 		commandCount++
 
@@ -127,7 +127,7 @@ func (e *Encoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, la
 			// If the stream ends with unmatched bytes, we need a dummy copy length.
 			copyCode = 2
 		}
-		command := combineLengthCodes(insertCode, copyCode, false)
+		command := combineLengthCodes(insertCode, copyCode, i > 0 && m.Distance == matches[i-1].Distance)
 		e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
 		if kInsExtra[insertCode] > 0 {
 			e.bw.writeBits(uint(kInsExtra[insertCode]), uint64(m.Unmatched)-uint64(kInsBase[insertCode]))

+ 197 - 0
vendor/github.com/andybalholm/brotli/encoder_fast.go

@@ -0,0 +1,197 @@
+package brotli
+
+import (
+	"math"
+
+	"github.com/andybalholm/brotli/matchfinder"
+)
+
+func gaussianProbability(x, mean, stdDev float64) float64 {
+	return math.Exp(-(x-mean)*(x-mean)/(2*stdDev*stdDev)) / math.Sqrt(2*math.Pi*stdDev*stdDev)
+}
+
+// A FastEncoder implements the matchfinder.Encoder interface, writing in Brotli
+// format. It uses a simplified encoding (like level 0 in the reference
+// implementation) to save time.
+type FastEncoder struct {
+	wroteHeader   bool
+	bw            bitWriter
+	commandHisto  [704]uint32
+	distanceHisto [64]uint32
+}
+
+func (e *FastEncoder) Reset() {
+	e.wroteHeader = false
+	e.bw = bitWriter{}
+}
+
+func (e *FastEncoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {
+	e.bw.dst = dst
+	if !e.wroteHeader {
+		e.bw.writeBits(4, 15)
+		e.wroteHeader = true
+
+		// Fill the histograms with default statistics.
+
+		// For the command codes we're using for insert lengths (insert + 2-byte copy),
+		// fill the histogram with a Zipf-squared distribution.
+		for i := range 24 {
+			e.commandHisto[combineLengthCodes(uint16(i), 0, false)] = uint32(2000 / (i + 1) / (i + 1))
+		}
+
+		// For the command codes we're using for copy lengths (0 insert + copy
+		// (length - 2), with repeat distance),
+		// fill the histogram with Zipf distribution starting at code 1 (match length 5),
+		// but a smaller frequency for code 0.
+		e.commandHisto[combineLengthCodes(0, 0, true)] = 50
+		for i := 1; i < 24; i++ {
+			e.commandHisto[combineLengthCodes(0, uint16(i), i < 16)] = uint32(800 / i)
+		}
+
+		// Fill in the combined codes for short insert and copy lengths.
+		for insertCode := range 6 {
+			copyCode := 2
+			e.commandHisto[128+insertCode<<3+copyCode] = uint32(100 / (insertCode + 1) / (insertCode + 1) / copyCode)
+			for copyCode := 3; copyCode < 8; copyCode++ {
+				e.commandHisto[128+insertCode<<3+copyCode] = uint32(343 / (insertCode + 1) / (insertCode + 1) / copyCode)
+			}
+		}
+
+		// Fill e.distanceHisto with a normal distribution.
+		e.distanceHisto[0] = 100
+		for i := 16; i < 64; i++ {
+			e.distanceHisto[i] = max(uint32(gaussianProbability(float64(i), 32, 8)*10000), 1)
+		}
+	}
+
+	if len(src) == 0 {
+		if lastBlock {
+			e.bw.writeBits(2, 3) // islast + isempty
+			e.bw.jumpToByteBoundary()
+			return e.bw.dst
+		}
+		return dst
+	}
+
+	var literalHisto [256]uint32
+	for _, c := range src {
+		literalHisto[c]++
+	}
+
+	storeMetaBlockHeaderBW(uint(len(src)), false, &e.bw)
+	e.bw.writeBits(13, 0)
+
+	var literalDepths [256]byte
+	var literalBits [256]uint16
+	buildAndStoreHuffmanTreeFastBW(literalHisto[:], uint(len(src)), 8, literalDepths[:], literalBits[:], &e.bw)
+
+	var commandDepths [704]byte
+	var commandBits [704]uint16
+	commandCount := 0
+	for _, n := range e.commandHisto {
+		commandCount += int(n)
+	}
+	buildAndStoreHuffmanTreeFastBW(e.commandHisto[:], uint(commandCount), 10, commandDepths[:], commandBits[:], &e.bw)
+
+	var distanceDepths [64]byte
+	var distanceBits [64]uint16
+	distanceCount := 0
+	for _, n := range e.distanceHisto {
+		distanceCount += int(n)
+	}
+	buildAndStoreHuffmanTreeFastBW(e.distanceHisto[:], uint(distanceCount), 6, distanceDepths[:], distanceBits[:], &e.bw)
+
+	// Reset the statistics, starting with a count of 1 for each symbol we might use.
+	for i := range 24 {
+		e.commandHisto[combineLengthCodes(uint16(i), 0, false)] = 1
+	}
+	for i := range 24 {
+		e.commandHisto[combineLengthCodes(0, uint16(i), i < 16)] = 1
+	}
+	for insertCode := range 6 {
+		for copyCode := 2; copyCode < 8; copyCode++ {
+			e.commandHisto[128+insertCode<<3+copyCode] = 1
+		}
+	}
+	e.distanceHisto[0] = 1
+	for i := 16; i < 64; i++ {
+		e.distanceHisto[i] = 1
+	}
+
+	pos := 0
+	for i, m := range matches {
+		lengthFinished := false
+		// Write a command with the appropriate insert length, and a copy length of 2.
+		if m.Unmatched < 6 {
+			var command int
+			if m.Length < 10 && m.Length != 0 {
+				// We can use a combined insert/copy code with no extra bits.
+				command = m.Unmatched<<3 + m.Length - 2 + 128
+				lengthFinished = true
+			} else {
+				command = m.Unmatched<<3 + 128
+			}
+			e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+			e.commandHisto[command]++
+		} else {
+			insertCode := getInsertLengthCode(uint(m.Unmatched))
+			command := combineLengthCodes(insertCode, 0, false)
+			e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+			e.bw.writeBits(uint(kInsExtra[insertCode]), uint64(m.Unmatched)-uint64(kInsBase[insertCode]))
+			e.commandHisto[command]++
+		}
+
+		// Write the literals, if any.
+		if m.Unmatched > 0 {
+			for _, c := range src[pos : pos+m.Unmatched] {
+				e.bw.writeBits(uint(literalDepths[c]), uint64(literalBits[c]))
+			}
+		}
+
+		if m.Length != 0 {
+			// Write the distance code.
+			var distCode distanceCode
+			if i == 0 || m.Distance != matches[i-1].Distance {
+				distCode = getDistanceCode(m.Distance)
+			}
+			e.bw.writeBits(uint(distanceDepths[distCode.code]), uint64(distanceBits[distCode.code]))
+			if distCode.nExtra > 0 {
+				e.bw.writeBits(distCode.nExtra, distCode.extraBits)
+			}
+			e.distanceHisto[distCode.code]++
+
+			// Write a command for the remainder of the match (after the first two bytes
+			// from before), using the previous distance.
+			switch {
+			case lengthFinished:
+				// We don't need to finish the length.
+			case m.Length < 12:
+				command := m.Length - 4
+				e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+				e.commandHisto[command]++
+			case m.Length < 72:
+				copyCode := getCopyLengthCode(uint(m.Length - 2))
+				command := combineLengthCodes(0, copyCode, true)
+				e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+				e.bw.writeBits(uint(kCopyExtra[copyCode]), uint64(m.Length-2)-uint64(kCopyBase[copyCode]))
+				e.commandHisto[command]++
+			default:
+				copyCode := getCopyLengthCode(uint(m.Length - 2))
+				command := combineLengthCodes(0, copyCode, false)
+				e.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))
+				e.bw.writeBits(uint(kCopyExtra[copyCode]), uint64(m.Length-2)-uint64(kCopyBase[copyCode]))
+				e.bw.writeBits(uint(distanceDepths[0]), uint64(distanceBits[0]))
+				e.commandHisto[command]++
+				e.distanceHisto[0]++
+			}
+		}
+
+		pos += m.Unmatched + m.Length
+	}
+
+	if lastBlock {
+		e.bw.writeBits(2, 3) // islast + isempty
+		e.bw.jumpToByteBoundary()
+	}
+	return e.bw.dst
+}

+ 27 - 0
vendor/github.com/andybalholm/brotli/flate/LICENSE

@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 2 - 0
vendor/github.com/andybalholm/brotli/flate/README.md

@@ -0,0 +1,2 @@
+This package is a flate/gzip compressor that reuses the matchfinder package that I’ve been developing for brotli.
+It is copied and adapted from the standard library compress/flate package.

+ 65 - 0
vendor/github.com/andybalholm/brotli/flate/gzip.go

@@ -0,0 +1,65 @@
+package flate
+
+import (
+	"hash/crc32"
+	"time"
+
+	"github.com/andybalholm/brotli/matchfinder"
+)
+
+func NewGZIPEncoder() matchfinder.Encoder {
+	return &gzipEncoder{
+		f: NewEncoder(),
+	}
+}
+
+type gzipEncoder struct {
+	f           matchfinder.Encoder
+	length      uint32
+	crc         uint32
+	wroteHeader bool
+}
+
+func (g *gzipEncoder) Reset() {
+	g.f.Reset()
+	g.length = 0
+	g.crc = 0
+	g.wroteHeader = false
+}
+
+func appendUint32(dst []byte, n uint32) []byte {
+	return append(dst,
+		byte(n),
+		byte(n>>8),
+		byte(n>>16),
+		byte(n>>24),
+	)
+}
+
+func (g *gzipEncoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {
+	if !g.wroteHeader {
+		dst = append(dst,
+			0x1f, 0x8b, // magic number
+			8, // CM = flate
+			0, // FLG
+		)
+		dst = appendUint32(dst, uint32(time.Now().Unix()))
+		dst = append(dst,
+			0,   // XFL
+			255, // OS (unspecified)
+		)
+		g.wroteHeader = true
+	}
+
+	dst = g.f.Encode(dst, src, matches, lastBlock)
+
+	g.length += uint32(len(src))
+	g.crc = crc32.Update(g.crc, crc32.IEEETable, src)
+
+	if lastBlock {
+		dst = appendUint32(dst, g.crc)
+		dst = appendUint32(dst, g.length)
+	}
+
+	return dst
+}

+ 517 - 0
vendor/github.com/andybalholm/brotli/flate/huffman_bit_writer.go

@@ -0,0 +1,517 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+	"github.com/andybalholm/brotli/matchfinder"
+)
+
+const (
+	// The largest offset code.
+	offsetCodeCount = 30
+
+	// The special code used to mark the end of a block.
+	endBlockMarker = 256
+
+	// The first length code.
+	lengthCodesStart = 257
+
+	// The number of codegen codes.
+	codegenCodeCount = 19
+	badCode          = 255
+
+	maxNumLit         = 286
+	maxStoreBlockSize = 65535
+	baseMatchLength   = 3 // The smallest match length per the RFC section 3.2.5
+	baseMatchOffset   = 1 // The smallest match offset
+)
+
+// The number of extra bits needed by length code X - LENGTH_CODES_START.
+var lengthExtraBits = []int8{
+	/* 257 */ 0, 0, 0,
+	/* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
+	/* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
+	/* 280 */ 4, 5, 5, 5, 5, 0,
+}
+
+// The length indicated by length code X - LENGTH_CODES_START.
+var lengthBase = []int{
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 10,
+	12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+	64, 80, 96, 112, 128, 160, 192, 224, 255,
+}
+
+// offset code word extra bits.
+var offsetExtraBits = []int8{
+	0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
+	4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+	9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
+}
+
+var offsetBase = []int{
+	0x000000, 0x000001, 0x000002, 0x000003, 0x000004,
+	0x000006, 0x000008, 0x00000c, 0x000010, 0x000018,
+	0x000020, 0x000030, 0x000040, 0x000060, 0x000080,
+	0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300,
+	0x000400, 0x000600, 0x000800, 0x000c00, 0x001000,
+	0x001800, 0x002000, 0x003000, 0x004000, 0x006000,
+}
+
+// The odd order in which the codegen code sizes are written.
+var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+type huffmanBitWriter struct {
+	dst []byte
+
+	// Data waiting to be written is the low nbits of bits.
+	bits            uint64
+	nbits           uint
+	codegenFreq     [codegenCodeCount]int32
+	literalFreq     []int32
+	offsetFreq      []int32
+	codegen         []uint8
+	literalEncoding *huffmanEncoder
+	offsetEncoding  *huffmanEncoder
+	codegenEncoding *huffmanEncoder
+}
+
+func NewEncoder() matchfinder.Encoder {
+	return &huffmanBitWriter{
+		literalFreq:     make([]int32, maxNumLit),
+		offsetFreq:      make([]int32, offsetCodeCount),
+		codegen:         make([]uint8, maxNumLit+offsetCodeCount+1),
+		literalEncoding: newHuffmanEncoder(maxNumLit),
+		codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+		offsetEncoding:  newHuffmanEncoder(offsetCodeCount),
+	}
+}
+
+func (w *huffmanBitWriter) Reset() {
+	w.bits, w.nbits = 0, 0
+}
+
+func (w *huffmanBitWriter) flush() {
+	dst := w.dst
+	for w.nbits != 0 {
+		dst = append(dst, byte(w.bits))
+		w.bits >>= 8
+		if w.nbits > 8 { // Avoid underflow
+			w.nbits -= 8
+		} else {
+			w.nbits = 0
+		}
+	}
+	w.bits = 0
+	w.dst = dst
+}
+
+func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
+	w.bits |= uint64(b) << w.nbits
+	w.nbits += nb
+	if w.nbits >= 48 {
+		bits := w.bits
+		w.bits >>= 48
+		w.nbits -= 48
+		w.dst = append(w.dst,
+			byte(bits),
+			byte(bits>>8),
+			byte(bits>>16),
+			byte(bits>>24),
+			byte(bits>>32),
+			byte(bits>>40),
+		)
+	}
+}
+
+func (w *huffmanBitWriter) writeBytes(bytes []byte) {
+	if w.nbits&7 != 0 {
+		panic("writeBytes with unfinished bits")
+	}
+	for w.nbits != 0 {
+		w.dst = append(w.dst, byte(w.bits))
+		w.bits >>= 8
+		w.nbits -= 8
+	}
+	w.dst = append(w.dst, bytes...)
+}
+
+// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
+// the literal and offset lengths arrays (which are concatenated into a single
+// array).  This method generates that run-length encoding.
+//
+// The result is written into the codegen array, and the frequencies
+// of each code is written into the codegenFreq array.
+// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
+// information. Code badCode is an end marker
+//
+//	numLiterals      The number of literals in literalEncoding
+//	numOffsets       The number of offsets in offsetEncoding
+//	litenc, offenc   The literal and offset encoder to use
+func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litEnc, offEnc *huffmanEncoder) {
+	for i := range w.codegenFreq {
+		w.codegenFreq[i] = 0
+	}
+	// Note that we are using codegen both as a temporary variable for holding
+	// a copy of the frequencies, and as the place where we put the result.
+	// This is fine because the output is always shorter than the input used
+	// so far.
+	codegen := w.codegen // cache
+	// Copy the concatenated code sizes to codegen. Put a marker at the end.
+	cgnl := codegen[:numLiterals]
+	for i := range cgnl {
+		cgnl[i] = uint8(litEnc.codes[i].len)
+	}
+
+	cgnl = codegen[numLiterals : numLiterals+numOffsets]
+	for i := range cgnl {
+		cgnl[i] = uint8(offEnc.codes[i].len)
+	}
+	codegen[numLiterals+numOffsets] = badCode
+
+	size := codegen[0]
+	count := 1
+	outIndex := 0
+	for inIndex := 1; size != badCode; inIndex++ {
+		// INVARIANT: We have seen "count" copies of size that have not yet
+		// had output generated for them.
+		nextSize := codegen[inIndex]
+		if nextSize == size {
+			count++
+			continue
+		}
+		// We need to generate codegen indicating "count" of size.
+		if size != 0 {
+			codegen[outIndex] = size
+			outIndex++
+			w.codegenFreq[size]++
+			count--
+			for count >= 3 {
+				n := 6
+				if n > count {
+					n = count
+				}
+				codegen[outIndex] = 16
+				outIndex++
+				codegen[outIndex] = uint8(n - 3)
+				outIndex++
+				w.codegenFreq[16]++
+				count -= n
+			}
+		} else {
+			for count >= 11 {
+				n := 138
+				if n > count {
+					n = count
+				}
+				codegen[outIndex] = 18
+				outIndex++
+				codegen[outIndex] = uint8(n - 11)
+				outIndex++
+				w.codegenFreq[18]++
+				count -= n
+			}
+			if count >= 3 {
+				// count >= 3 && count <= 10
+				codegen[outIndex] = 17
+				outIndex++
+				codegen[outIndex] = uint8(count - 3)
+				outIndex++
+				w.codegenFreq[17]++
+				count = 0
+			}
+		}
+		count--
+		for ; count >= 0; count-- {
+			codegen[outIndex] = size
+			outIndex++
+			w.codegenFreq[size]++
+		}
+		// Set up invariant for next time through the loop.
+		size = nextSize
+		count = 1
+	}
+	// Marker indicating the end of the codegen.
+	codegen[outIndex] = badCode
+}
+
+// dynamicSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) {
+	numCodegens = len(w.codegenFreq)
+	for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+		numCodegens--
+	}
+	header := 3 + 5 + 5 + 4 + (3 * numCodegens) +
+		w.codegenEncoding.bitLength(w.codegenFreq[:]) +
+		int(w.codegenFreq[16])*2 +
+		int(w.codegenFreq[17])*3 +
+		int(w.codegenFreq[18])*7
+	size = header +
+		litEnc.bitLength(w.literalFreq) +
+		offEnc.bitLength(w.offsetFreq) +
+		extraBits
+
+	return size, numCodegens
+}
+
+// fixedSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) fixedSize(extraBits int) int {
+	return 3 +
+		fixedLiteralEncoding.bitLength(w.literalFreq) +
+		fixedOffsetEncoding.bitLength(w.offsetFreq) +
+		extraBits
+}
+
+// storedSize calculates the stored size, including header.
+// The function returns the size in bits and whether the block
+// fits inside a single block.
+func (w *huffmanBitWriter) storedSize(in []byte) (int, bool) {
+	if in == nil {
+		return 0, false
+	}
+	if len(in) <= maxStoreBlockSize {
+		return (len(in) + 5) * 8, true
+	}
+	return 0, false
+}
+
+func (w *huffmanBitWriter) writeCode(c hcode) {
+	w.bits |= uint64(c.code) << w.nbits
+	w.nbits += uint(c.len)
+	if w.nbits >= 48 {
+		bits := w.bits
+		w.bits >>= 48
+		w.nbits -= 48
+		w.dst = append(w.dst,
+			byte(bits),
+			byte(bits>>8),
+			byte(bits>>16),
+			byte(bits>>24),
+			byte(bits>>32),
+			byte(bits>>40),
+		)
+	}
+}
+
+// Write the header of a dynamic Huffman block to the output stream.
+//
+//	numLiterals  The number of literals specified in codegen
+//	numOffsets   The number of offsets specified in codegen
+//	numCodegens  The number of codegens used in codegen
+func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) {
+	var firstBits int32 = 4
+	if isEof {
+		firstBits = 5
+	}
+	w.writeBits(firstBits, 3)
+	w.writeBits(int32(numLiterals-257), 5)
+	w.writeBits(int32(numOffsets-1), 5)
+	w.writeBits(int32(numCodegens-4), 4)
+
+	for i := 0; i < numCodegens; i++ {
+		value := uint(w.codegenEncoding.codes[codegenOrder[i]].len)
+		w.writeBits(int32(value), 3)
+	}
+
+	i := 0
+	for {
+		var codeWord int = int(w.codegen[i])
+		i++
+		if codeWord == badCode {
+			break
+		}
+		w.writeCode(w.codegenEncoding.codes[uint32(codeWord)])
+
+		switch codeWord {
+		case 16:
+			w.writeBits(int32(w.codegen[i]), 2)
+			i++
+		case 17:
+			w.writeBits(int32(w.codegen[i]), 3)
+			i++
+		case 18:
+			w.writeBits(int32(w.codegen[i]), 7)
+			i++
+		}
+	}
+}
+
+func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) {
+	var flag int32
+	if isEof {
+		flag = 1
+	}
+	w.writeBits(flag, 3)
+	w.flush()
+	w.writeBits(int32(length), 16)
+	w.writeBits(int32(^uint16(length)), 16)
+}
+
+func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
+	// Indicate that we are a fixed Huffman block
+	var value int32 = 2
+	if isEof {
+		value = 3
+	}
+	w.writeBits(value, 3)
+}
+
+// writeBlock will write a block of tokens with the smallest encoding.
+func (w *huffmanBitWriter) writeBlock(matches []matchfinder.Match, eof bool, input []byte) {
+	numLiterals, numOffsets := w.makeStatistics(matches, input)
+
+	var extraBits int
+	storedSize, storable := w.storedSize(input)
+	if storable {
+		// We only bother calculating the costs of the extra bits required by
+		// the length of offset fields (which will be the same for both fixed
+		// and dynamic encoding), if we need to compare those two encodings
+		// against stored encoding.
+		for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
+			// First eight length codes have extra size = 0.
+			extraBits += int(w.literalFreq[lengthCode]) * int(lengthExtraBits[lengthCode-lengthCodesStart])
+		}
+		for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
+			// First four offset codes have extra size = 0.
+			extraBits += int(w.offsetFreq[offsetCode]) * int(offsetExtraBits[offsetCode])
+		}
+	}
+
+	// Figure out smallest code.
+	// Fixed Huffman baseline.
+	var literalEncoding = fixedLiteralEncoding
+	var offsetEncoding = fixedOffsetEncoding
+	var size = w.fixedSize(extraBits)
+
+	// Dynamic Huffman?
+	var numCodegens int
+
+	// Generate codegen and codegenFrequencies, which indicates how to encode
+	// the literalEncoding and the offsetEncoding.
+	w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
+	w.codegenEncoding.generate(w.codegenFreq[:], 7)
+	dynamicSize, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits)
+
+	if dynamicSize < size {
+		size = dynamicSize
+		literalEncoding = w.literalEncoding
+		offsetEncoding = w.offsetEncoding
+	}
+
+	// Stored bytes?
+	if storable && storedSize < size {
+		w.writeStoredHeader(len(input), eof)
+		w.writeBytes(input)
+		return
+	}
+
+	// Huffman.
+	if literalEncoding == fixedLiteralEncoding {
+		w.writeFixedHeader(eof)
+	} else {
+		w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+	}
+
+	// Write the tokens.
+	w.writeTokens(matches, input, literalEncoding.codes, offsetEncoding.codes)
+	w.writeCode(literalEncoding.codes[endBlockMarker])
+}
+
+// makeStatistics indexes a slice of tokens, and updates
+// literalFreq and offsetFreq, and generates literalEncoding
+// and offsetEncoding.
+// The number of literal and offset tokens is returned.
+func (w *huffmanBitWriter) makeStatistics(matches []matchfinder.Match, input []byte) (numLiterals, numOffsets int) {
+	for i := range w.literalFreq {
+		w.literalFreq[i] = 0
+	}
+	for i := range w.offsetFreq {
+		w.offsetFreq[i] = 0
+	}
+
+	pos := 0
+	for _, m := range matches {
+		for _, c := range input[pos : pos+m.Unmatched] {
+			w.literalFreq[c]++
+		}
+		pos += m.Unmatched
+
+		if m.Length == 0 {
+			continue
+		}
+		w.literalFreq[lengthCodesStart+lengthCode(m.Length)]++
+		w.offsetFreq[offsetCode(m.Distance)]++
+		pos += m.Length
+	}
+	w.literalFreq[endBlockMarker]++
+
+	// get the number of literals
+	numLiterals = len(w.literalFreq)
+	for w.literalFreq[numLiterals-1] == 0 {
+		numLiterals--
+	}
+	// get the number of offsets
+	numOffsets = len(w.offsetFreq)
+	for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 {
+		numOffsets--
+	}
+	if numOffsets == 0 {
+		// We haven't found a single match. If we want to go with the dynamic encoding,
+		// we should count at least one offset to be sure that the offset huffman tree could be encoded.
+		w.offsetFreq[0] = 1
+		numOffsets = 1
+	}
+	w.literalEncoding.generate(w.literalFreq, 15)
+	w.offsetEncoding.generate(w.offsetFreq, 15)
+	return
+}
+
+// writeTokens writes a slice of tokens to the output.
+// codes for literal and offset encoding must be supplied.
+func (w *huffmanBitWriter) writeTokens(matches []matchfinder.Match, input []byte, leCodes, oeCodes []hcode) {
+	pos := 0
+	for _, m := range matches {
+		for _, c := range input[pos : pos+m.Unmatched] {
+			w.writeCode(leCodes[c])
+		}
+		pos += m.Unmatched
+
+		// Write the length
+		length := m.Length
+		if length == 0 {
+			continue
+		}
+		lengthCode := lengthCode(length)
+		w.writeCode(leCodes[lengthCode+lengthCodesStart])
+		extraLengthBits := uint(lengthExtraBits[lengthCode])
+		if extraLengthBits > 0 {
+			extraLength := int32(length - baseMatchLength - lengthBase[lengthCode])
+			w.writeBits(extraLength, extraLengthBits)
+		}
+
+		// Write the offset
+		offset := m.Distance
+		offsetCode := offsetCode(offset)
+		w.writeCode(oeCodes[offsetCode])
+		extraOffsetBits := uint(offsetExtraBits[offsetCode])
+		if extraOffsetBits > 0 {
+			extraOffset := int32(offset - baseMatchOffset - offsetBase[offsetCode])
+			w.writeBits(extraOffset, extraOffsetBits)
+		}
+		pos += m.Length
+	}
+}
+
+func (w *huffmanBitWriter) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {
+	w.dst = dst
+
+	w.writeBlock(matches, lastBlock, src)
+	if lastBlock {
+		w.flush()
+	}
+
+	dst = w.dst
+	w.dst = nil
+	return dst
+}

+ 346 - 0
vendor/github.com/andybalholm/brotli/flate/huffman_code.go

@@ -0,0 +1,346 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+	"math"
+	"math/bits"
+	"sort"
+)
+
+// hcode is a huffman code with a bit code and bit length.
+type hcode struct {
+	code, len uint16
+}
+
+type huffmanEncoder struct {
+	codes     []hcode
+	freqcache []literalNode
+	bitCount  [17]int32
+	lns       byLiteral // stored to avoid repeated allocation in generate
+	lfs       byFreq    // stored to avoid repeated allocation in generate
+}
+
+type literalNode struct {
+	literal uint16
+	freq    int32
+}
+
+// A levelInfo describes the state of the constructed tree for a given depth.
+type levelInfo struct {
+	// Our level.  for better printing
+	level int32
+
+	// The frequency of the last node at this level
+	lastFreq int32
+
+	// The frequency of the next character to add to this level
+	nextCharFreq int32
+
+	// The frequency of the next pair (from level below) to add to this level.
+	// Only valid if the "needed" value of the next lower level is 0.
+	nextPairFreq int32
+
+	// The number of chains remaining to generate for this level before moving
+	// up to the next level
+	needed int32
+}
+
+// set sets the code and length of an hcode.
+func (h *hcode) set(code uint16, length uint16) {
+	h.len = length
+	h.code = code
+}
+
+func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }
+
+func newHuffmanEncoder(size int) *huffmanEncoder {
+	return &huffmanEncoder{codes: make([]hcode, size)}
+}
+
+// Generates a HuffmanCode corresponding to the fixed literal table
+func generateFixedLiteralEncoding() *huffmanEncoder {
+	h := newHuffmanEncoder(maxNumLit)
+	codes := h.codes
+	var ch uint16
+	for ch = 0; ch < maxNumLit; ch++ {
+		var bits uint16
+		var size uint16
+		switch {
+		case ch < 144:
+			// size 8, 000110000  .. 10111111
+			bits = ch + 48
+			size = 8
+		case ch < 256:
+			// size 9, 110010000 .. 111111111
+			bits = ch + 400 - 144
+			size = 9
+		case ch < 280:
+			// size 7, 0000000 .. 0010111
+			bits = ch - 256
+			size = 7
+		default:
+			// size 8, 11000000 .. 11000111
+			bits = ch + 192 - 280
+			size = 8
+		}
+		codes[ch] = hcode{code: reverseBits(bits, byte(size)), len: size}
+	}
+	return h
+}
+
+func generateFixedOffsetEncoding() *huffmanEncoder {
+	h := newHuffmanEncoder(30)
+	codes := h.codes
+	for ch := range codes {
+		codes[ch] = hcode{code: reverseBits(uint16(ch), 5), len: 5}
+	}
+	return h
+}
+
+var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
+var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()
+
+func (h *huffmanEncoder) bitLength(freq []int32) int {
+	var total int
+	for i, f := range freq {
+		if f != 0 {
+			total += int(f) * int(h.codes[i].len)
+		}
+	}
+	return total
+}
+
+const maxBitsLimit = 16
+
+// Return the number of literals assigned to each bit size in the Huffman encoding
+//
+// This method is only called when list.length >= 3
+// The cases of 0, 1, and 2 literals are handled by special case code.
+//
+// list  An array of the literals with non-zero frequencies
+//             and their associated frequencies. The array is in order of increasing
+//             frequency, and has as its last element a special element with frequency
+//             MaxInt32
+// maxBits     The maximum number of bits that should be used to encode any literal.
+//             Must be less than 16.
+// return      An integer array in which array[i] indicates the number of literals
+//             that should be encoded in i bits.
+func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
+	if maxBits >= maxBitsLimit {
+		panic("flate: maxBits too large")
+	}
+	n := int32(len(list))
+	list = list[0 : n+1]
+	list[n] = maxNode()
+
+	// The tree can't have greater depth than n - 1, no matter what. This
+	// saves a little bit of work in some small cases
+	if maxBits > n-1 {
+		maxBits = n - 1
+	}
+
+	// Create information about each of the levels.
+	// A bogus "Level 0" whose sole purpose is so that
+	// level1.prev.needed==0.  This makes level1.nextPairFreq
+	// be a legitimate value that never gets chosen.
+	var levels [maxBitsLimit]levelInfo
+	// leafCounts[i] counts the number of literals at the left
+	// of ancestors of the rightmost node at level i.
+	// leafCounts[i][j] is the number of literals at the left
+	// of the level j ancestor.
+	var leafCounts [maxBitsLimit][maxBitsLimit]int32
+
+	for level := int32(1); level <= maxBits; level++ {
+		// For every level, the first two items are the first two characters.
+		// We initialize the levels as if we had already figured this out.
+		levels[level] = levelInfo{
+			level:        level,
+			lastFreq:     list[1].freq,
+			nextCharFreq: list[2].freq,
+			nextPairFreq: list[0].freq + list[1].freq,
+		}
+		leafCounts[level][level] = 2
+		if level == 1 {
+			levels[level].nextPairFreq = math.MaxInt32
+		}
+	}
+
+	// We need a total of 2*n - 2 items at top level and have already generated 2.
+	levels[maxBits].needed = 2*n - 4
+
+	level := maxBits
+	for {
+		l := &levels[level]
+		if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
+			// We've run out of both leafs and pairs.
+			// End all calculations for this level.
+			// To make sure we never come back to this level or any lower level,
+			// set nextPairFreq impossibly large.
+			l.needed = 0
+			levels[level+1].nextPairFreq = math.MaxInt32
+			level++
+			continue
+		}
+
+		prevFreq := l.lastFreq
+		if l.nextCharFreq < l.nextPairFreq {
+			// The next item on this row is a leaf node.
+			n := leafCounts[level][level] + 1
+			l.lastFreq = l.nextCharFreq
+			// Lower leafCounts are the same of the previous node.
+			leafCounts[level][level] = n
+			l.nextCharFreq = list[n].freq
+		} else {
+			// The next item on this row is a pair from the previous row.
+			// nextPairFreq isn't valid until we generate two
+			// more values in the level below
+			l.lastFreq = l.nextPairFreq
+			// Take leaf counts from the lower level, except counts[level] remains the same.
+			copy(leafCounts[level][:level], leafCounts[level-1][:level])
+			levels[l.level-1].needed = 2
+		}
+
+		if l.needed--; l.needed == 0 {
+			// We've done everything we need to do for this level.
+			// Continue calculating one level up. Fill in nextPairFreq
+			// of that level with the sum of the two nodes we've just calculated on
+			// this level.
+			if l.level == maxBits {
+				// All done!
+				break
+			}
+			levels[l.level+1].nextPairFreq = prevFreq + l.lastFreq
+			level++
+		} else {
+			// If we stole from below, move down temporarily to replenish it.
+			for levels[level-1].needed > 0 {
+				level--
+			}
+		}
+	}
+
+	// Somethings is wrong if at the end, the top level is null or hasn't used
+	// all of the leaves.
+	if leafCounts[maxBits][maxBits] != n {
+		panic("leafCounts[maxBits][maxBits] != n")
+	}
+
+	bitCount := h.bitCount[:maxBits+1]
+	bits := 1
+	counts := &leafCounts[maxBits]
+	for level := maxBits; level > 0; level-- {
+		// chain.leafCount gives the number of literals requiring at least "bits"
+		// bits to encode.
+		bitCount[bits] = counts[level] - counts[level-1]
+		bits++
+	}
+	return bitCount
+}
+
+// Look at the leaves and assign them a bit count and an encoding as specified
+// in RFC 1951 3.2.2
+func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) {
+	code := uint16(0)
+	for n, bits := range bitCount {
+		code <<= 1
+		if n == 0 || bits == 0 {
+			continue
+		}
+		// The literals list[len(list)-bits] .. list[len(list)-bits]
+		// are encoded using "bits" bits, and get the values
+		// code, code + 1, ....  The code values are
+		// assigned in literal order (not frequency order).
+		chunk := list[len(list)-int(bits):]
+
+		h.lns.sort(chunk)
+		for _, node := range chunk {
+			h.codes[node.literal] = hcode{code: reverseBits(code, uint8(n)), len: uint16(n)}
+			code++
+		}
+		list = list[0 : len(list)-int(bits)]
+	}
+}
+
+// Update this Huffman Code object to be the minimum code for the specified frequency count.
+//
+// freq  An array of frequencies, in which frequency[i] gives the frequency of literal i.
+// maxBits  The maximum number of bits to use for any literal.
+func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
+	if h.freqcache == nil {
+		// Allocate a reusable buffer with the longest possible frequency table.
+		// Possible lengths are codegenCodeCount, offsetCodeCount and maxNumLit.
+		// The largest of these is maxNumLit, so we allocate for that case.
+		h.freqcache = make([]literalNode, maxNumLit+1)
+	}
+	list := h.freqcache[:len(freq)+1]
+	// Number of non-zero literals
+	count := 0
+	// Set list to be the set of all non-zero literals and their frequencies
+	for i, f := range freq {
+		if f != 0 {
+			list[count] = literalNode{uint16(i), f}
+			count++
+		} else {
+			list[count] = literalNode{}
+			h.codes[i].len = 0
+		}
+	}
+	list[len(freq)] = literalNode{}
+
+	list = list[:count]
+	if count <= 2 {
+		// Handle the small cases here, because they are awkward for the general case code. With
+		// two or fewer literals, everything has bit length 1.
+		for i, node := range list {
+			// "list" is in order of increasing literal value.
+			h.codes[node.literal].set(uint16(i), 1)
+		}
+		return
+	}
+	h.lfs.sort(list)
+
+	// Get the number of literals for each bit count
+	bitCount := h.bitCounts(list, maxBits)
+	// And do the assignment
+	h.assignEncodingAndSize(bitCount, list)
+}
+
+type byLiteral []literalNode
+
+func (s *byLiteral) sort(a []literalNode) {
+	*s = byLiteral(a)
+	sort.Sort(s)
+}
+
+func (s byLiteral) Len() int { return len(s) }
+
+func (s byLiteral) Less(i, j int) bool {
+	return s[i].literal < s[j].literal
+}
+
+func (s byLiteral) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+type byFreq []literalNode
+
+func (s *byFreq) sort(a []literalNode) {
+	*s = byFreq(a)
+	sort.Sort(s)
+}
+
+func (s byFreq) Len() int { return len(s) }
+
+func (s byFreq) Less(i, j int) bool {
+	if s[i].freq == s[j].freq {
+		return s[i].literal < s[j].literal
+	}
+	return s[i].freq < s[j].freq
+}
+
+func (s byFreq) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+func reverseBits(number uint16, bitLength byte) uint16 {
+	return bits.Reverse16(number << (16 - bitLength))
+}

+ 80 - 0
vendor/github.com/andybalholm/brotli/flate/token.go

@@ -0,0 +1,80 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import "log"
+
+// The length code for length X (MIN_MATCH_LENGTH <= X <= MAX_MATCH_LENGTH)
+// is lengthCodes[length - MIN_MATCH_LENGTH]
+var lengthCodes = [...]uint32{
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 8,
+	9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+	13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+	15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+	17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
+	18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+	19, 19, 19, 19, 20, 20, 20, 20, 20, 20,
+	20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+	21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+	21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+	22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+	22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+	23, 23, 23, 23, 23, 23, 23, 23, 24, 24,
+	24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+	25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+	26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+	26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+	26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
+	27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+	27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+	27, 27, 27, 27, 27, 28,
+}
+
+var offsetCodes = [...]uint32{
+	0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+	8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+	10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+	12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+	12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+	13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+	13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+	14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+}
+
+func lengthCode(len int) uint32 {
+	if len > 258 {
+		panic("match too long")
+	}
+	return lengthCodes[len-baseMatchLength]
+}
+
+// Returns the offset code corresponding to a specific offset
+func offsetCode(off int) uint32 {
+	if off > 32768 {
+		log.Println(off)
+		panic("match distance too high")
+	}
+	off -= baseMatchOffset
+	if off < len(offsetCodes) {
+		return offsetCodes[off]
+	}
+	if off>>7 < len(offsetCodes) {
+		return offsetCodes[off>>7] + 14
+	}
+	return offsetCodes[off>>14] + 28
+}

+ 66 - 0
vendor/github.com/andybalholm/brotli/flate/writer.go

@@ -0,0 +1,66 @@
+package flate
+
+import (
+	"io"
+
+	"github.com/andybalholm/brotli/matchfinder"
+)
+
+// NewWriter returns a new matchfinder.Writer that compresses data at the given level,
+// in flate encoding. Levels 1–9 are available; levels outside this range will
+// be replaced with the closest level available.
+func NewWriter(w io.Writer, level int) *matchfinder.Writer {
+	return newWriter(w, level, NewEncoder())
+}
+
+// NewGZIPWriter returns a new matchfinder.Writer that compresses data at the given
+// level, in gzip encoding. Levels 1–9 are available; levels outside this range
+// will be replaced by the closest level available.
+func NewGZIPWriter(w io.Writer, level int) *matchfinder.Writer {
+	return newWriter(w, level, NewGZIPEncoder())
+}
+
+func newWriter(w io.Writer, level int, e matchfinder.Encoder) *matchfinder.Writer {
+	var mf matchfinder.MatchFinder
+	if level < 2 {
+		mf = &matchfinder.ZFast{MaxDistance: 1 << 15}
+	} else if level == 2 {
+		mf = &matchfinder.ZDFast{MaxDistance: 1 << 15}
+	} else if level == 3 {
+		mf = &matchfinder.ZM{MaxDistance: 1 << 15}
+	} else if level == 4 {
+		mf = &matchfinder.Trio{MaxDistance: 1 << 15}
+	} else if level < 8 {
+		chainLen := 32
+		switch level {
+		case 5:
+			chainLen = 8
+		case 6:
+			chainLen = 16
+		}
+		mf = &matchfinder.M4{
+			MaxDistance:     1 << 15,
+			ChainLength:     chainLen,
+			HashLen:         5,
+			DistanceBitCost: 66,
+		}
+	} else {
+		chainLen := 32
+		hashLen := 5
+		if level == 8 {
+			chainLen = 4
+		}
+		mf = &matchfinder.Pathfinder{
+			MaxDistance: 1 << 15,
+			ChainLength: chainLen,
+			HashLen:     hashLen,
+		}
+	}
+
+	return &matchfinder.Writer{
+		Dest:        w,
+		MatchFinder: mf,
+		Encoder:     e,
+		BlockSize:   1 << 16,
+	}
+}

+ 8 - 3
vendor/github.com/andybalholm/brotli/http.go

@@ -1,10 +1,11 @@
 package brotli
 
 import (
-	"compress/gzip"
 	"io"
 	"net/http"
 	"strings"
+
+	"github.com/andybalholm/brotli/flate"
 )
 
 // HTTPCompressor chooses a compression method (brotli, gzip, or none) based on
@@ -12,6 +13,10 @@ import (
 // WriteCloser that implements that compression. The Close method must be called
 // before the current HTTP handler returns.
 func HTTPCompressor(w http.ResponseWriter, r *http.Request) io.WriteCloser {
+	return HTTPCompressorWithLevel(w, r, 4)
+}
+
+func HTTPCompressorWithLevel(w http.ResponseWriter, r *http.Request, level int) io.WriteCloser {
 	if w.Header().Get("Vary") == "" {
 		w.Header().Set("Vary", "Accept-Encoding")
 	}
@@ -20,10 +25,10 @@ func HTTPCompressor(w http.ResponseWriter, r *http.Request) io.WriteCloser {
 	switch encoding {
 	case "br":
 		w.Header().Set("Content-Encoding", "br")
-		return NewWriterV2(w, DefaultCompression)
+		return NewWriterV2(w, level)
 	case "gzip":
 		w.Header().Set("Content-Encoding", "gzip")
-		return gzip.NewWriter(w)
+		return flate.NewGZIPWriter(w, level)
 	}
 	return nopCloser{w}
 }

+ 212 - 0
vendor/github.com/andybalholm/brotli/matchfinder/bargain1.go

@@ -0,0 +1,212 @@
+package matchfinder
+
+import (
+	"encoding/binary"
+	"math"
+	"math/bits"
+	"slices"
+)
+
+const (
+	bargain1TableBits = 18
+	bargain1TableSize = 1 << bargain1TableBits
+)
+
+// Bargain1 is a MatchFinder that attempts to find the encoding with the lowest
+// "bit cost", using 1 hash length (6).
+type Bargain1 struct {
+	MaxDistance int
+
+	// Skip is whether to look for matches at every other byte instead of every
+	// byte (to increase speed but decrease compression).
+	Skip bool
+
+	history []byte
+	table6  [bargain1TableSize]tableEntry
+
+	// holding onto buffers to reduce allocations:
+
+	arrivals []arrival
+	matches  []Match
+}
+
+func (z *Bargain1) Reset() {
+	z.table6 = [bargain1TableSize]tableEntry{}
+	z.history = z.history[:0]
+}
+
+func (z *Bargain1) FindMatches(dst []Match, src []byte) []Match {
+	if z.MaxDistance == 0 {
+		z.MaxDistance = 1 << 16
+	}
+
+	var histogram [256]uint32
+	for _, b := range src {
+		histogram[b]++
+	}
+	var byteCost [256]float32
+	for b, n := range histogram {
+		cost := max(math.Log2(float64(len(src))/float64(n)), 1)
+		byteCost[b] = float32(cost)
+	}
+
+	// Each element in arrivals corresponds to the position just after
+	// the corresponding byte in src.
+	arrivals := z.arrivals
+	if len(arrivals) < len(src) {
+		arrivals = make([]arrival, len(src))
+		z.arrivals = arrivals
+	} else {
+		arrivals = arrivals[:len(src)]
+		for i := range arrivals {
+			arrivals[i] = arrival{}
+		}
+	}
+
+	if len(z.history) > z.MaxDistance*2 {
+		delta := len(z.history) - z.MaxDistance
+		copy(z.history, z.history[delta:])
+		z.history = z.history[:z.MaxDistance]
+
+		for i := range z.table6 {
+			v := z.table6[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table6[i] = tableEntry{}
+			} else {
+				z.table6[i].offset = v
+			}
+		}
+	}
+
+	historyLen := len(z.history)
+	z.history = append(z.history, src...)
+	src = z.history
+
+	addMatch := func(m absoluteMatch, unmatched int, repeat bool) {
+		var startCost float32
+		if m.Start > historyLen {
+			startCost = arrivals[m.Start-historyLen-1].cost
+		}
+		insertCost := float32(bits.Len(uint(unmatched)))
+		var distanceCost float32
+		if !repeat {
+			distanceCost = float32(bits.Len(uint(m.Start - m.Match)))
+		}
+		cost := startCost + baseMatchCost + insertCost + distanceCost
+		for j := m.End; j >= m.Start+3; j-- {
+			a := &arrivals[j-historyLen-1]
+			if a.cost > 0 && a.cost <= cost {
+				break
+			}
+			*a = arrival{
+				length:   uint32(j - m.Start),
+				distance: uint32(m.Start - m.Match),
+				cost:     cost,
+			}
+		}
+	}
+
+	var nextOverlapSearch int
+
+	for i := historyLen; i < len(src); i++ {
+		var arrivedHere arrival
+		if i > historyLen {
+			arrivedHere = arrivals[i-historyLen-1]
+		}
+
+		unmatched := 0
+		if arrivedHere.distance == 0 {
+			unmatched = int(arrivedHere.length)
+		}
+		prevDistance := 0
+		if unmatched != 0 && i-unmatched > historyLen {
+			prevDistance = int(arrivals[i-historyLen-1-unmatched].distance)
+		}
+
+		literalCost := byteCost[src[i]]
+		nextArrival := &arrivals[i-historyLen]
+		if nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {
+			*nextArrival = arrival{
+				cost:   arrivedHere.cost + literalCost,
+				length: uint32(unmatched + 1),
+			}
+		}
+
+		if i > len(src)-8 {
+			// There's no room to check hashes.
+			continue
+		}
+
+		cv := binary.LittleEndian.Uint64(src[i:])
+		nextHash6 := z.hash6(cv)
+		candidate6 := z.table6[nextHash6]
+
+		entry := tableEntry{offset: int32(i), val: uint32(cv)}
+		z.table6[nextHash6] = entry
+
+		// Look for a repeat match, unless there is no previous distance, or a match at
+		// that distance has already been found.
+		if prevDistance != 0 && prevDistance != int(arrivals[i-historyLen-1+4].distance) {
+			repIndex := i - prevDistance
+			if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv) {
+				// We have a repeat of the previous match distance.
+				m := extendMatch2(src, i, repIndex, i)
+				addMatch(m, unmatched, true)
+			}
+		}
+
+		if z.Skip && i%2 != 0 {
+			continue
+		}
+
+		nextByteIsUnmatched := arrivals[i-historyLen-1+1].distance == 0
+
+		if unmatched > 0 || i >= nextOverlapSearch || nextByteIsUnmatched {
+			if int(candidate6.offset) < i && i-int(candidate6.offset) < z.MaxDistance && uint32(cv) == candidate6.val &&
+				binary.LittleEndian.Uint32(src[candidate6.offset:]) == uint32(cv) {
+				m := extendMatch2(src, i, int(candidate6.offset), historyLen)
+				delta := i - m.Start
+				if delta == 0 {
+					addMatch(m, unmatched, false)
+				} else {
+					// The match was extended backwards. Add it with and without the extra.
+					addMatch(m, max(unmatched-delta, 0), false)
+					m.Start += delta
+					m.Match += delta
+					addMatch(m, unmatched, false)
+				}
+				nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-4)
+			}
+		}
+	}
+
+	// We've found the shortest path; now walk it backward and store the matches.
+	matches := z.matches[:0]
+	i := len(arrivals) - 1
+	for i >= 0 {
+		a := arrivals[i]
+		if a.distance > 0 {
+			matches = append(matches, Match{
+				Length:   int(a.length),
+				Distance: int(a.distance),
+			})
+			i -= int(a.length)
+		} else {
+			if len(matches) == 0 {
+				matches = append(matches, Match{})
+			}
+			matches[len(matches)-1].Unmatched = int(a.length)
+			i -= int(a.length)
+		}
+	}
+	z.matches = matches
+
+	slices.Reverse(matches)
+
+	return append(dst, matches...)
+}
+
+func (z *Bargain1) hash6(u uint64) uint32 {
+	return uint32(((u << 16) * 227718039650203) >> (64 - bargain1TableBits))
+}

+ 248 - 0
vendor/github.com/andybalholm/brotli/matchfinder/bargain2.go

@@ -0,0 +1,248 @@
+package matchfinder
+
+import (
+	"encoding/binary"
+	"math"
+	"math/bits"
+	"slices"
+)
+
+const (
+	bargain2TableBits = 18
+	bargain2TableSize = 1 << bargain2TableBits
+)
+
+// Bargain2 is a MatchFinder that attempts to find the encoding with the lowest
+// "bit cost", using 2 hash lengths (5 and 8).
+type Bargain2 struct {
+	MaxDistance int
+
+	// Skip is whether to look for matches at every other byte instead of every
+	// byte (to increase speed but decrease compression).
+	Skip bool
+
+	history []byte
+	table5  [bargain2TableSize]tableEntry
+	table8  [bargain2TableSize]tableEntry
+
+	// holding onto buffers to reduce allocations:
+
+	arrivals []arrival
+	matches  []Match
+}
+
+func (z *Bargain2) Reset() {
+	z.table5 = [bargain2TableSize]tableEntry{}
+	z.table8 = [bargain2TableSize]tableEntry{}
+	z.history = z.history[:0]
+}
+
+func (z *Bargain2) FindMatches(dst []Match, src []byte) []Match {
+	if z.MaxDistance == 0 {
+		z.MaxDistance = 1 << 16
+	}
+
+	var histogram [256]uint32
+	for _, b := range src {
+		histogram[b]++
+	}
+	var byteCost [256]float32
+	for b, n := range histogram {
+		cost := max(math.Log2(float64(len(src))/float64(n)), 1)
+		byteCost[b] = float32(cost)
+	}
+
+	// Each element in arrivals corresponds to the position just after
+	// the corresponding byte in src.
+	arrivals := z.arrivals
+	if len(arrivals) < len(src) {
+		arrivals = make([]arrival, len(src))
+		z.arrivals = arrivals
+	} else {
+		arrivals = arrivals[:len(src)]
+		for i := range arrivals {
+			arrivals[i] = arrival{}
+		}
+	}
+
+	if len(z.history) > z.MaxDistance*2 {
+		delta := len(z.history) - z.MaxDistance
+		copy(z.history, z.history[delta:])
+		z.history = z.history[:z.MaxDistance]
+
+		for i := range z.table5 {
+			v := z.table5[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table5[i] = tableEntry{}
+			} else {
+				z.table5[i].offset = v
+			}
+		}
+		for i := range z.table8 {
+			v := z.table8[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table8[i] = tableEntry{}
+			} else {
+				z.table8[i].offset = v
+			}
+		}
+	}
+
+	historyLen := len(z.history)
+	z.history = append(z.history, src...)
+	src = z.history
+
+	addMatch := func(m absoluteMatch, unmatched int, repeat bool) {
+		var startCost float32
+		if m.Start > historyLen {
+			startCost = arrivals[m.Start-historyLen-1].cost
+		}
+		insertCost := float32(bits.Len(uint(unmatched)))
+		var distanceCost float32
+		if !repeat {
+			distanceCost = float32(bits.Len(uint(m.Start - m.Match)))
+		}
+		cost := startCost + baseMatchCost + insertCost + distanceCost
+		for j := m.End; j >= m.Start+3; j-- {
+			a := &arrivals[j-historyLen-1]
+			if a.cost > 0 && a.cost <= cost {
+				break
+			}
+			*a = arrival{
+				length:   uint32(j - m.Start),
+				distance: uint32(m.Start - m.Match),
+				cost:     cost,
+			}
+		}
+	}
+
+	var nextOverlapSearch int
+
+	for i := historyLen; i < len(src); i++ {
+		var arrivedHere arrival
+		if i > historyLen {
+			arrivedHere = arrivals[i-historyLen-1]
+		}
+
+		unmatched := 0
+		if arrivedHere.distance == 0 {
+			unmatched = int(arrivedHere.length)
+		}
+		prevDistance := 0
+		if unmatched != 0 && i-unmatched > historyLen {
+			prevDistance = int(arrivals[i-historyLen-1-unmatched].distance)
+		}
+
+		literalCost := byteCost[src[i]]
+		nextArrival := &arrivals[i-historyLen]
+		if nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {
+			*nextArrival = arrival{
+				cost:   arrivedHere.cost + literalCost,
+				length: uint32(unmatched + 1),
+			}
+		}
+
+		if i > len(src)-8 {
+			// There's no room to check hashes.
+			continue
+		}
+
+		cv := binary.LittleEndian.Uint64(src[i:])
+		nextHash5 := z.hash5(cv)
+		nextHash8 := z.hash8(cv)
+		candidate5 := z.table5[nextHash5]
+		candidate8 := z.table8[nextHash8]
+
+		entry := tableEntry{offset: int32(i), val: uint32(cv)}
+		z.table5[nextHash5] = entry
+		z.table8[nextHash8] = entry
+
+		// Look for a repeat match, unless there is no previous distance, or a match at
+		// that distance has already been found.
+		if prevDistance != 0 && prevDistance != int(arrivals[i-historyLen-1+4].distance) {
+			repIndex := i - prevDistance
+			if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv) {
+				// We have a repeat of the previous match distance.
+				m := extendMatch2(src, i, repIndex, i)
+				addMatch(m, unmatched, true)
+			}
+		}
+
+		if z.Skip {
+			if i%2 != 0 {
+				continue
+			}
+		}
+
+		nextByteIsUnmatched := arrivals[i-historyLen-1+1].distance == 0
+
+		if unmatched > 0 || i >= nextOverlapSearch || nextByteIsUnmatched {
+			if int(candidate5.offset) < i && i-int(candidate5.offset) < z.MaxDistance && uint32(cv) == candidate5.val &&
+				binary.LittleEndian.Uint32(src[candidate5.offset:]) == uint32(cv) {
+				m := extendMatch2(src, i, int(candidate5.offset), historyLen)
+				delta := i - m.Start
+				if delta == 0 {
+					addMatch(m, unmatched, false)
+				} else {
+					// The match was extended backwards. Add it with and without the extra.
+					addMatch(m, max(unmatched-delta, 0), false)
+					m.Start += delta
+					m.Match += delta
+					addMatch(m, unmatched, false)
+				}
+				nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+			}
+
+			if int(candidate8.offset) < i && i-int(candidate8.offset) < z.MaxDistance && uint32(cv) == candidate8.val &&
+				binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+				m := extendMatch2(src, i, int(candidate8.offset), historyLen)
+				delta := i - m.Start
+				if delta == 0 {
+					addMatch(m, unmatched, false)
+				} else {
+					// The match was extended backwards. Add it with and without the extra.
+					addMatch(m, max(unmatched-delta, 0), false)
+					m.Start += delta
+					m.Match += delta
+					addMatch(m, unmatched, false)
+				}
+				nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+			}
+		}
+	}
+
+	// We've found the shortest path; now walk it backward and store the matches.
+	matches := z.matches[:0]
+	i := len(arrivals) - 1
+	for i >= 0 {
+		a := arrivals[i]
+		if a.distance > 0 {
+			matches = append(matches, Match{
+				Length:   int(a.length),
+				Distance: int(a.distance),
+			})
+			i -= int(a.length)
+		} else {
+			if len(matches) == 0 {
+				matches = append(matches, Match{})
+			}
+			matches[len(matches)-1].Unmatched = int(a.length)
+			i -= int(a.length)
+		}
+	}
+	z.matches = matches
+
+	slices.Reverse(matches)
+
+	return append(dst, matches...)
+}
+
+func (z *Bargain2) hash5(u uint64) uint32 {
+	return uint32(((u << 24) * 889523592379) >> (64 - bargain2TableBits))
+}
+
+func (z *Bargain2) hash8(u uint64) uint32 {
+	return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - bargain2TableBits))
+}

+ 278 - 0
vendor/github.com/andybalholm/brotli/matchfinder/bargain3.go

@@ -0,0 +1,278 @@
+package matchfinder
+
+import (
+	"encoding/binary"
+	"math"
+	"math/bits"
+	"slices"
+)
+
+// Bargain3 is a MatchFinder that attempts to find the encoding with the lowest
+// "bit cost", using 3 hash lengths (5, 8, and 12).
+type Bargain3 struct {
+	MaxDistance int
+
+	// Skip is whether to look for matches at every other byte instead of every
+	// byte (to increase speed but decrease compression).
+	Skip bool
+
+	history []byte
+	table5  [1 << 17]tableEntry
+	table8  [1 << 18]tableEntry
+	table12 [1 << 19]tableEntry
+
+	// holding onto buffers to reduce allocations:
+
+	arrivals []arrival
+	matches  []Match
+}
+
+func (z *Bargain3) Reset() {
+	z.table5 = [len(z.table5)]tableEntry{}
+	z.table8 = [len(z.table8)]tableEntry{}
+	z.table12 = [len(z.table12)]tableEntry{}
+	z.history = z.history[:0]
+}
+
+func (z *Bargain3) FindMatches(dst []Match, src []byte) []Match {
+	if z.MaxDistance == 0 {
+		z.MaxDistance = 1 << 16
+	}
+
+	var histogram [256]uint32
+	for _, b := range src {
+		histogram[b]++
+	}
+	var byteCost [256]float32
+	for b, n := range histogram {
+		cost := max(math.Log2(float64(len(src))/float64(n)), 1)
+		byteCost[b] = float32(cost)
+	}
+
+	// Each element in arrivals corresponds to the position just after
+	// the corresponding byte in src.
+	arrivals := z.arrivals
+	if len(arrivals) < len(src) {
+		arrivals = make([]arrival, len(src))
+		z.arrivals = arrivals
+	} else {
+		arrivals = arrivals[:len(src)]
+		for i := range arrivals {
+			arrivals[i] = arrival{}
+		}
+	}
+
+	if len(z.history) > z.MaxDistance*2 {
+		delta := len(z.history) - z.MaxDistance
+		copy(z.history, z.history[delta:])
+		z.history = z.history[:z.MaxDistance]
+
+		for i := range z.table5 {
+			v := z.table5[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table5[i] = tableEntry{}
+			} else {
+				z.table5[i].offset = v
+			}
+		}
+		for i := range z.table8 {
+			v := z.table8[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table8[i] = tableEntry{}
+			} else {
+				z.table8[i].offset = v
+			}
+		}
+		for i := range z.table12 {
+			v := z.table12[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table12[i] = tableEntry{}
+			} else {
+				z.table12[i].offset = v
+			}
+		}
+	}
+
+	historyLen := len(z.history)
+	z.history = append(z.history, src...)
+	src = z.history
+
+	addMatch := func(m absoluteMatch, unmatched int, repeat bool) {
+		var startCost float32
+		if m.Start > historyLen {
+			startCost = arrivals[m.Start-historyLen-1].cost
+		}
+		insertCost := float32(bits.Len(uint(unmatched)))
+		var distanceCost float32
+		if !repeat {
+			distanceCost = float32(bits.Len(uint(m.Start - m.Match)))
+		}
+		cost := startCost + baseMatchCost + insertCost + distanceCost
+		for j := m.End; j >= m.Start+3; j-- {
+			a := &arrivals[j-historyLen-1]
+			if a.cost > 0 && a.cost <= cost {
+				break
+			}
+			*a = arrival{
+				length:   uint32(j - m.Start),
+				distance: uint32(m.Start - m.Match),
+				cost:     cost,
+			}
+		}
+	}
+
+	var nextOverlapSearch int
+
+	for i := historyLen; i < len(src); i++ {
+		var arrivedHere arrival
+		if i > historyLen {
+			arrivedHere = arrivals[i-historyLen-1]
+		}
+
+		unmatched := 0
+		if arrivedHere.distance == 0 {
+			unmatched = int(arrivedHere.length)
+		}
+		prevDistance := 0
+		if unmatched != 0 && i-unmatched > historyLen {
+			prevDistance = int(arrivals[i-historyLen-1-unmatched].distance)
+		}
+
+		literalCost := byteCost[src[i]]
+		nextArrival := &arrivals[i-historyLen]
+		if nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {
+			*nextArrival = arrival{
+				cost:   arrivedHere.cost + literalCost,
+				length: uint32(unmatched + 1),
+			}
+		}
+
+		if i > len(src)-12 {
+			// There's no room to check hashes.
+			continue
+		}
+
+		cv := binary.LittleEndian.Uint64(src[i:])
+		extra := binary.LittleEndian.Uint32(src[i+8:])
+		nextHash5 := z.hash5(cv)
+		nextHash8 := z.hash8(cv)
+		nextHash12 := z.hash12(cv, extra)
+		candidate5 := z.table5[nextHash5]
+		candidate8 := z.table8[nextHash8]
+		candidate12 := z.table12[nextHash12]
+
+		entry := tableEntry{offset: int32(i), val: uint32(cv)}
+		z.table5[nextHash5] = entry
+		z.table8[nextHash8] = entry
+		z.table12[nextHash12] = entry
+
+		// Look for a repeat match, unless there is no previous distance, or a match at
+		// that distance has already been found.
+		if prevDistance != 0 && prevDistance != int(arrivals[i-historyLen-1+4].distance) {
+			repIndex := i - prevDistance
+			if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv) {
+				// We have a repeat of the previous match distance.
+				m := extendMatch2(src, i, repIndex, i)
+				addMatch(m, unmatched, true)
+			}
+		}
+
+		if z.Skip {
+			if i%2 != 0 {
+				continue
+			}
+		}
+
+		nextByteIsUnmatched := arrivals[i-historyLen-1+1].distance == 0
+
+		if unmatched > 0 || i >= nextOverlapSearch || nextByteIsUnmatched {
+			if int(candidate5.offset) < i && i-int(candidate5.offset) < z.MaxDistance && uint32(cv) == candidate5.val &&
+				binary.LittleEndian.Uint32(src[candidate5.offset:]) == uint32(cv) {
+				m := extendMatch2(src, i, int(candidate5.offset), historyLen)
+				delta := i - m.Start
+				if delta == 0 {
+					addMatch(m, unmatched, false)
+				} else {
+					// The match was extended backwards. Add it with and without the extra.
+					addMatch(m, max(unmatched-delta, 0), false)
+					m.Start += delta
+					m.Match += delta
+					addMatch(m, unmatched, false)
+				}
+				nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+			}
+
+			if int(candidate8.offset) < i && i-int(candidate8.offset) < z.MaxDistance && uint32(cv) == candidate8.val &&
+				binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+				m := extendMatch2(src, i, int(candidate8.offset), historyLen)
+				delta := i - m.Start
+				if delta == 0 {
+					addMatch(m, unmatched, false)
+				} else {
+					// The match was extended backwards. Add it with and without the extra.
+					addMatch(m, max(unmatched-delta, 0), false)
+					m.Start += delta
+					m.Match += delta
+					addMatch(m, unmatched, false)
+				}
+				nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+			}
+
+			if int(candidate12.offset) < i && i-int(candidate12.offset) < z.MaxDistance && uint32(cv) == candidate12.val &&
+				binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+				m := extendMatch2(src, i, int(candidate12.offset), historyLen)
+				delta := i - m.Start
+				if delta == 0 {
+					addMatch(m, unmatched, false)
+				} else {
+					// The match was extended backwards. Add it with and without the extra.
+					addMatch(m, max(unmatched-delta, 0), false)
+					m.Start += delta
+					m.Match += delta
+					addMatch(m, unmatched, false)
+				}
+				nextOverlapSearch = max(nextOverlapSearch, m.Start+1, m.End-6)
+			}
+		}
+	}
+
+	// We've found the shortest path; now walk it backward and store the matches.
+	matches := z.matches[:0]
+	i := len(arrivals) - 1
+	for i >= 0 {
+		a := arrivals[i]
+		if a.distance > 0 {
+			matches = append(matches, Match{
+				Length:   int(a.length),
+				Distance: int(a.distance),
+			})
+			i -= int(a.length)
+		} else {
+			if len(matches) == 0 {
+				matches = append(matches, Match{})
+			}
+			matches[len(matches)-1].Unmatched = int(a.length)
+			i -= int(a.length)
+		}
+	}
+	z.matches = matches
+
+	slices.Reverse(matches)
+
+	return append(dst, matches...)
+}
+
+func (z *Bargain3) hash5(u uint64) uint32 {
+	return uint32(((u << 24) * 889523592379) >> (64 - 17))
+}
+
+func (z *Bargain3) hash8(u uint64) uint32 {
+	return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - 18))
+}
+
+func (z *Bargain3) hash12(u uint64, e uint32) uint32 {
+	return uint32((u*0xcf1bbcdcb7a56463 + uint64(e)*(2654435761<<32)) >> (64 - 19))
+}

+ 12 - 6
vendor/github.com/andybalholm/brotli/matchfinder/m0.go

@@ -22,7 +22,7 @@ func (M0) Reset() {}
 const (
 	m0HashLen = 5
 
-	m0TableBits = 14
+	m0TableBits = 16
 	m0TableSize = 1 << m0TableBits
 	m0Shift     = 32 - m0TableBits
 	// m0TableMask is redundant, but helps the compiler eliminate bounds
@@ -145,18 +145,24 @@ func (m M0) FindMatches(dst []Match, src []byte) []Match {
 		if m.Lazy {
 			// If lazy matching is enabled, we update the hash table for
 			// every byte in the match.
-			for i := origBase + 2; i < s-1; i++ {
+			for i := origBase + 2; i < s-3; i++ {
 				x := binary.LittleEndian.Uint64(src[i:])
 				table[m.hash(x)&m0TableMask] = uint16(i)
 			}
+		} else {
+			// We update the hash table only at base+1
+			x := binary.LittleEndian.Uint64(src[base+1:])
+			table[m.hash(x)&m0TableMask] = uint16(base + 1)
 		}
 
 		// We could immediately start working at s now, but to improve
-		// compression we first update the hash table at s-1 and at s.
-		x := binary.LittleEndian.Uint64(src[s-1:])
-		prevHash := m.hash(x >> 0)
+		// compression we first update the hash table.
+		x := binary.LittleEndian.Uint64(src[s-3:])
+		table[m.hash(x)&m0TableMask] = uint16(s - 3)
+		table[m.hash(x>>8)&m0TableMask] = uint16(s - 2)
+		prevHash := m.hash(x >> 16)
 		table[prevHash&m0TableMask] = uint16(s - 1)
-		nextHash = m.hash(x >> 8)
+		nextHash = m.hash(x >> 24)
 	}
 
 emitRemainder:

+ 1 - 0
vendor/github.com/andybalholm/brotli/matchfinder/m4.go

@@ -85,6 +85,7 @@ func (q *M4) FindMatches(dst []Match, src []byte) []Match {
 		copy(q.history, q.history[delta:])
 		q.history = q.history[:q.MaxDistance]
 		if q.ChainLength > 0 {
+			copy(q.chain, q.chain[delta:])
 			q.chain = q.chain[:q.MaxDistance]
 		}
 

+ 326 - 0
vendor/github.com/andybalholm/brotli/matchfinder/trio.go

@@ -0,0 +1,326 @@
+package matchfinder
+
+import "encoding/binary"
+
+// Trio is a MatchFinder that uses 3 different hash lengths, and
+// overlap parsing.
+type Trio struct {
+	MaxDistance int
+	history     []byte
+	table5      [1 << 16]tableEntry
+	table8      [1 << 17]tableEntry
+	table12     [1 << 18]tableEntry
+}
+
+func (z *Trio) Reset() {
+	z.table5 = [len(z.table5)]tableEntry{}
+	z.table8 = [len(z.table8)]tableEntry{}
+	z.table12 = [len(z.table12)]tableEntry{}
+	z.history = z.history[:0]
+}
+
+func (z *Trio) FindMatches(dst []Match, src []byte) []Match {
+	if z.MaxDistance == 0 {
+		z.MaxDistance = 1 << 16
+	}
+
+	if len(z.history) > z.MaxDistance*2 {
+		delta := len(z.history) - z.MaxDistance
+		copy(z.history, z.history[delta:])
+		z.history = z.history[:z.MaxDistance]
+
+		for i := range z.table5 {
+			v := z.table5[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table5[i] = tableEntry{}
+			} else {
+				z.table5[i].offset = v
+			}
+		}
+		for i := range z.table8 {
+			v := z.table8[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table8[i] = tableEntry{}
+			} else {
+				z.table8[i].offset = v
+			}
+		}
+		for i := range z.table12 {
+			v := z.table12[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table12[i] = tableEntry{}
+			} else {
+				z.table12[i].offset = v
+			}
+		}
+	}
+
+	if len(src) < 20 {
+		return append(dst, Match{
+			Unmatched: len(src),
+		})
+	}
+
+	e := matchEmitter{
+		Dst:      dst,
+		NextEmit: len(z.history),
+	}
+	z.history = append(z.history, src...)
+	src = z.history
+
+	// matches stores the matches that have been found but not emitted,
+	// in reverse order. (matches[0] is the most recent one.)
+	var matches [3]absoluteMatch
+
+	sLimit := int32(len(src)) - 14
+
+mainLoop:
+	for {
+		// Search for a match, starting after the last match emitted.
+		s := int32(e.NextEmit)
+		if s > sLimit {
+			break mainLoop
+		}
+
+		// t will contain the match offset when we find one.
+		var t int32
+		var hashLengthFound int
+
+		cv := binary.LittleEndian.Uint64(src[s:])
+		extra := binary.LittleEndian.Uint32(src[s+8:])
+
+		for {
+			nextHash12 := z.hash12(cv, extra)
+			nextHash8 := z.hash8(cv)
+			nextHash5 := z.hash5(cv)
+			candidate12 := z.table12[nextHash12]
+			candidate8 := z.table8[nextHash8]
+			candidate5 := z.table5[nextHash5]
+
+			entry := tableEntry{offset: s, val: uint32(cv)}
+			z.table12[nextHash12] = entry
+			z.table8[nextHash8] = entry
+			z.table5[nextHash5] = entry
+
+			// Look for a repeat match one byte after the current position.
+			if len(e.Dst) > 0 {
+				prevDistance := int32(e.Dst[len(e.Dst)-1].Distance)
+				if prevDistance != 0 {
+					repIndex := s - prevDistance + 1
+					if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>8) {
+						// There is a repeated match at s+2.
+						s++
+						t = repIndex
+						break
+					}
+				}
+			}
+
+			if candidate12.offset < s && s-candidate12.offset < int32(z.MaxDistance) && uint32(cv) == candidate12.val &&
+				binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+				// There is a 12-byte match at s.
+				t = candidate12.offset
+				hashLengthFound = 12
+				break
+			}
+			if candidate8.offset < s && s-candidate8.offset < int32(z.MaxDistance) && uint32(cv) == candidate8.val &&
+				binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+				t = candidate8.offset
+				hashLengthFound = 8
+				break
+			}
+			if candidate5.offset < s && s-candidate5.offset < int32(z.MaxDistance) && uint32(cv) == candidate5.val &&
+				binary.LittleEndian.Uint32(src[candidate5.offset:]) == uint32(cv) {
+				t = candidate5.offset
+				hashLengthFound = 5
+				break
+			}
+
+			s += 1 + ((s - int32(e.NextEmit)) >> 7)
+			if s > sLimit {
+				break mainLoop
+			}
+			cv = binary.LittleEndian.Uint64(src[s:])
+			extra = binary.LittleEndian.Uint32(src[s+8:])
+		}
+
+		if hashLengthFound != 0 && hashLengthFound < 12 {
+			// Look for a "lazy" match with a longer hash at s+1.
+			cv := binary.LittleEndian.Uint64(src[s+1:])
+			extra := binary.LittleEndian.Uint32(src[s+9:])
+			nextHash12 := z.hash12(cv, extra)
+			nextHash8 := z.hash8(cv)
+			candidate12 := z.table12[nextHash12]
+			candidate8 := z.table8[nextHash8]
+			coffset12 := s - candidate12.offset + 1
+			coffset8 := s - candidate8.offset + 1
+			entry := tableEntry{offset: s + 1, val: uint32(cv)}
+			z.table12[nextHash12] = entry
+			z.table8[nextHash8] = entry
+			if candidate12.offset < s+1 && coffset12 < int32(z.MaxDistance) && uint32(cv) == candidate12.val &&
+				binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+				t = candidate12.offset
+				s++
+			} else if hashLengthFound < 8 && candidate8.offset < s+1 && coffset8 < int32(z.MaxDistance) && uint32(cv) == candidate8.val &&
+				binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+				t = candidate8.offset
+				s++
+			}
+		}
+
+		currentMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+		matches[0] = currentMatch
+
+		index0 := s + 1
+
+		// We have a match in matches[0].
+		// Now look for overlapping matches.
+
+		for {
+			if matches[0].End > int(sLimit) {
+				break
+			}
+			s = int32(max(matches[0].Start+2, matches[0].End-10))
+
+			// Store some entries that haven't been indexed yet.
+			for index0 < s-1 {
+				cv0 := binary.LittleEndian.Uint64(src[index0:])
+				extra0 := binary.LittleEndian.Uint32(src[index0+8:])
+				te0 := tableEntry{offset: index0, val: uint32(cv0)}
+				z.table5[z.hash5(cv0)] = te0
+				z.table8[z.hash8(cv0)] = te0
+				z.table12[z.hash12(cv0, extra0)] = te0
+				index0++
+			}
+
+			cv = binary.LittleEndian.Uint64(src[s:])
+			extra = binary.LittleEndian.Uint32(src[s+8:])
+
+			nextHash12 := z.hash12(cv, extra)
+			nextHash8 := z.hash8(cv)
+			nextHash5 := z.hash5(cv)
+			candidate12 := z.table12[nextHash12]
+			candidate8 := z.table8[nextHash8]
+
+			entry := tableEntry{offset: s, val: uint32(cv)}
+			z.table12[nextHash12] = entry
+			z.table8[nextHash8] = entry
+			z.table5[nextHash5] = entry
+
+			t = -1
+			if candidate12.offset < s && s-candidate12.offset < int32(z.MaxDistance) && uint32(cv) == candidate12.val &&
+				binary.LittleEndian.Uint32(src[candidate12.offset:]) == uint32(cv) {
+				// There is a 12-byte match at s.
+				t = candidate12.offset
+			} else if candidate8.offset < s && s-candidate8.offset < int32(z.MaxDistance) && uint32(cv) == candidate8.val &&
+				binary.LittleEndian.Uint32(src[candidate8.offset:]) == uint32(cv) {
+				// There is a long match at s.
+				t = candidate8.offset
+			}
+
+			index0 = s + 1
+
+			if t == -1 {
+				// No overlapping match was found.
+				break
+			}
+
+			newMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+
+			if newMatch.End-newMatch.Start <= matches[0].End-matches[0].Start {
+				// The new match isn't longer than the old one, so we break out of the loop
+				// of looking for overlapping matches.
+				break
+			}
+
+			matches = [3]absoluteMatch{
+				newMatch,
+				matches[0],
+				matches[1],
+			}
+
+			if matches[2] == (absoluteMatch{}) {
+				continue
+			}
+
+			// We have three matches, so it's time to emit one and/or eliminate one.
+			switch {
+			case matches[0].Start < matches[2].End:
+				// The first and third matches overlap; discard the one in between.
+				matches = [3]absoluteMatch{
+					matches[0],
+					matches[2],
+					{},
+				}
+
+			case matches[0].Start < matches[2].End+4:
+				// The first and third matches don't overlap, but there's no room for
+				// another match between them. Emit the first match and discard the second.
+				e.emit(matches[2])
+				matches = [3]absoluteMatch{
+					matches[0],
+					{},
+					{},
+				}
+
+			default:
+				// Emit the first match, shortening it if necessary to avoid overlap with the second.
+				if matches[2].End > matches[1].Start {
+					matches[2].End = matches[1].Start
+				}
+				if matches[2].End-matches[2].Start >= 4 {
+					e.emit(matches[2])
+				}
+				matches[2] = absoluteMatch{}
+			}
+		}
+
+		// Store some entries up to the end of the last match.
+		for index0 < int32(matches[0].End) && index0 < sLimit {
+			cv0 := binary.LittleEndian.Uint64(src[index0:])
+			extra0 := binary.LittleEndian.Uint32(src[index0+8:])
+			te0 := tableEntry{offset: index0, val: uint32(cv0)}
+			z.table5[z.hash5(cv0)] = te0
+			z.table8[z.hash8(cv0)] = te0
+			z.table12[z.hash12(cv0, extra0)] = te0
+			index0++
+		}
+
+		// We're done looking for overlapping matches; emit the ones we have.
+
+		if matches[1] != (absoluteMatch{}) {
+			if matches[1].End > matches[0].Start {
+				matches[1].End = matches[0].Start
+			}
+			if matches[1].End-matches[1].Start >= 4 {
+				e.emit(matches[1])
+			}
+		}
+		e.emit(matches[0])
+		matches = [3]absoluteMatch{}
+	}
+
+	dst = e.Dst
+	if e.NextEmit < len(src) {
+		dst = append(dst, Match{
+			Unmatched: len(src) - e.NextEmit,
+		})
+	}
+
+	return dst
+}
+
+func (z *Trio) hash5(u uint64) uint32 {
+	return uint32(((u << 24) * 889523592379) >> (64 - 16))
+}
+
+func (z *Trio) hash8(u uint64) uint32 {
+	return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - 17))
+}
+
+func (z *Trio) hash12(u uint64, e uint32) uint32 {
+	return uint32((u*0xcf1bbcdcb7a56463 + uint64(e)*(2654435761<<32)) >> (64 - 18))
+}

+ 258 - 0
vendor/github.com/andybalholm/brotli/matchfinder/zdfast.go

@@ -0,0 +1,258 @@
+package matchfinder
+
+import (
+	"encoding/binary"
+	"math"
+)
+
+const (
+	zdfastLongTableBits = 17
+	zdfastLongTableSize = 1 << zdfastLongTableBits
+)
+
+// ZDFast is a MatchFinder based on the "Default" setting in
+// github.com/klauspost/compress/zstd.
+type ZDFast struct {
+	MaxDistance int
+
+	history []byte
+	// current is the offset at the start of history
+	current   int32
+	table     [zfastTableSize]tableEntry
+	longTable [zdfastLongTableSize]tableEntry
+}
+
+func (z *ZDFast) Reset() {
+	z.current = 0
+	z.table = [zfastTableSize]tableEntry{}
+	z.longTable = [zdfastLongTableSize]tableEntry{}
+	z.history = z.history[:0]
+}
+
+func (z *ZDFast) FindMatches(dst []Match, src []byte) []Match {
+	if z.MaxDistance == 0 {
+		z.MaxDistance = 1 << 16
+	}
+
+	// Protect against overflow of current.
+	if int(z.current) >= int(math.MaxInt32)-2*z.MaxDistance-len(z.history) {
+		minOffset := z.current + int32(len(z.history)) - int32(z.MaxDistance)
+		for i := range z.table {
+			v := z.table[i].offset
+			if v < minOffset {
+				v = 0
+			} else {
+				v = v - z.current + int32(z.MaxDistance)
+			}
+			z.table[i].offset = v
+		}
+		for i := range z.longTable {
+			v := z.longTable[i].offset
+			if v < minOffset {
+				v = 0
+			} else {
+				v = v - z.current + int32(z.MaxDistance)
+			}
+			z.longTable[i].offset = v
+		}
+		z.current = int32(z.MaxDistance)
+	}
+
+	if len(z.history)+len(src) > cap(z.history) {
+		// history doesn't have enough capacity to hold the new block.
+		if cap(z.history) == 0 {
+			historySize := max(2*z.MaxDistance, 1<<20, len(src))
+			z.history = make([]byte, 0, historySize)
+		} else {
+			// Move down
+			offset := len(z.history) - z.MaxDistance
+			copy(z.history[:z.MaxDistance], z.history[offset:])
+			z.current += int32(offset)
+			z.history = z.history[:z.MaxDistance]
+		}
+	}
+	s := int32(len(z.history))
+	z.history = append(z.history, src...)
+
+	if len(src) < 16 {
+		return append(dst, Match{
+			Unmatched: len(src),
+		})
+	}
+
+	src = z.history
+	sLimit := int32(len(src)) - 10
+
+	const stepSize = 1
+
+	nextEmit := s
+	cv := binary.LittleEndian.Uint64(src[s:])
+	var offset1, offset2 int32
+
+mainLoop:
+	for {
+		// t will contain the match offset when we find one.
+		// When exiting the search loop, we have already checked 4 bytes.
+		var t int32
+
+		for {
+			nextHashL := z.hashLong(cv)
+			nextHashS := z.hashShort(cv)
+			candidateL := z.longTable[nextHashL]
+			candidateS := z.table[nextHashS]
+
+			repIndex := s - offset1 + 1
+
+			entry := tableEntry{offset: s + z.current, val: uint32(cv)}
+			z.longTable[nextHashL] = entry
+			z.table[nextHashS] = entry
+
+			if offset1 != 0 && repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>8) {
+				// There is a repeated match at s+1.
+				end := extendMatch(src, int(repIndex+4), int(s+5))
+				start := s + 1
+				for repIndex > 0 && start > nextEmit && src[repIndex-1] == src[start-1] {
+					repIndex--
+					start--
+				}
+
+				dst = append(dst, Match{
+					Unmatched: int(start - nextEmit),
+					Length:    end - int(start),
+					Distance:  int(start - repIndex),
+				})
+				s = int32(end)
+				nextEmit = s
+				if s >= sLimit {
+					break mainLoop
+				}
+				cv = binary.LittleEndian.Uint64(src[s:])
+				continue
+			}
+
+			coffsetL := s - (candidateL.offset - z.current)
+			coffsetS := s - (candidateS.offset - z.current)
+			if coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val {
+				t = candidateL.offset - z.current
+				if binary.LittleEndian.Uint32(src[t:]) == uint32(cv) {
+					// found a long match (likely at least 8 bytes)
+					break
+				}
+			}
+			if coffsetS < int32(z.MaxDistance) && uint32(cv) == candidateS.val {
+				t = candidateS.offset - z.current
+				if binary.LittleEndian.Uint32(src[t:]) != uint32(cv) {
+					goto noMatch
+				}
+				// Found a regular match.
+				// See if we can find a long match at s+1
+				cv := binary.LittleEndian.Uint64(src[s+1:])
+				nextHashL = z.hashLong(cv)
+				candidateL = z.longTable[nextHashL]
+				coffsetL = s - (candidateL.offset - z.current) + 1
+				z.longTable[nextHashL] = tableEntry{offset: s + 1 + z.current, val: uint32(cv)}
+				if coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val {
+					t = candidateL.offset - z.current
+					if binary.LittleEndian.Uint32(src[t:]) == uint32(cv) {
+						// We found a long match at s+1, so we'll use that instead
+						// of the regular match at s.
+						s++
+						break
+					}
+				}
+
+				t = candidateS.offset - z.current
+				break
+			}
+		noMatch:
+
+			s += stepSize + ((s - nextEmit) >> 7)
+			if s > sLimit {
+				break mainLoop
+			}
+			cv = binary.LittleEndian.Uint64(src[s:])
+		}
+
+		// A 4-byte match has been found. We'll later see if more than
+		// 4 bytes.
+		offset2 = offset1
+		offset1 = s - t
+
+		end := extendMatch(src, int(t+4), int(s+4))
+		for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+			s--
+			t--
+		}
+
+		dst = append(dst, Match{
+			Unmatched: int(s - nextEmit),
+			Length:    end - int(s),
+			Distance:  int(s - t),
+		})
+		prevS := s
+		s = int32(end)
+		nextEmit = s
+		if s >= sLimit {
+			break mainLoop
+		}
+
+		// Store some table entries near the start and end of the match.
+		index0 := prevS + 1
+		index1 := s - 2
+		cv0 := binary.LittleEndian.Uint64(src[index0:])
+		cv1 := binary.LittleEndian.Uint64(src[index1:])
+		te0 := tableEntry{offset: index0 + z.current, val: uint32(cv0)}
+		te1 := tableEntry{offset: index1 + z.current, val: uint32(cv1)}
+		z.longTable[z.hashLong(cv0)] = te0
+		z.longTable[z.hashLong(cv1)] = te1
+		cv0 >>= 8
+		cv1 >>= 8
+		te0.offset++
+		te1.offset++
+		te0.val = uint32(cv0)
+		te1.val = uint32(cv1)
+		z.table[z.hashShort(cv0)] = te0
+		z.table[z.hashShort(cv1)] = te1
+
+		cv = binary.LittleEndian.Uint64(src[s:])
+
+		// Check offset 2
+		if o2 := s - offset2; offset2 != 0 && binary.LittleEndian.Uint32(src[o2:]) == uint32(cv) {
+			end := extendMatch(src, int(o2+4), int(s+4))
+
+			// Store the hashes, since we have them.
+			nextHashS := z.hashShort(cv)
+			nextHashL := z.hashLong(cv)
+			entry := tableEntry{offset: s + z.current, val: uint32(cv)}
+			z.table[nextHashS] = entry
+			z.longTable[nextHashL] = entry
+			dst = append(dst, Match{
+				Length:   end - int(s),
+				Distance: int(offset2),
+			})
+			s = int32(end)
+			nextEmit = s
+			offset1, offset2 = offset2, offset1
+			if s >= sLimit {
+				break mainLoop
+			}
+			cv = binary.LittleEndian.Uint64(src[s:])
+		}
+	}
+
+	if int(nextEmit) < len(src) {
+		dst = append(dst, Match{
+			Unmatched: len(src) - int(nextEmit),
+		})
+	}
+
+	return dst
+}
+
+func (z *ZDFast) hashShort(u uint64) uint32 {
+	return uint32(((u << 24) * 889523592379) >> (64 - zfastTableBits))
+}
+
+func (z *ZDFast) hashLong(u uint64) uint32 {
+	return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - zdfastLongTableBits))
+}

+ 206 - 0
vendor/github.com/andybalholm/brotli/matchfinder/zfast.go

@@ -0,0 +1,206 @@
+package matchfinder
+
+import (
+	"encoding/binary"
+	"math"
+)
+
+type tableEntry struct {
+	val    uint32
+	offset int32
+}
+
+const (
+	zfastTableBits = 15
+	zfastTableSize = 1 << zfastTableBits
+	zfastHashLen   = 6
+
+	prime6Bytes = 227718039650203
+)
+
+// ZFast is a MatchFinder based on the "Fastest" setting in
+// github.com/klauspost/compress/zstd.
+type ZFast struct {
+	MaxDistance int
+
+	history []byte
+	// current is the offset at the start of history
+	current int32
+	table   [zfastTableSize]tableEntry
+}
+
+func (z *ZFast) Reset() {
+	z.current = 0
+	z.table = [zfastTableSize]tableEntry{}
+	z.history = z.history[:0]
+}
+
+func (z *ZFast) FindMatches(dst []Match, src []byte) []Match {
+	if z.MaxDistance == 0 {
+		z.MaxDistance = 1 << 16
+	}
+
+	// Protect against overflow of current.
+	if int(z.current) >= int(math.MaxInt32)-2*z.MaxDistance-len(z.history) {
+		minOffset := z.current + int32(len(z.history)) - int32(z.MaxDistance)
+		for i := range z.table {
+			v := z.table[i].offset
+			if v < minOffset {
+				v = 0
+			} else {
+				v = v - z.current + int32(z.MaxDistance)
+			}
+			z.table[i].offset = v
+		}
+		z.current = int32(z.MaxDistance)
+	}
+
+	if len(z.history)+len(src) > cap(z.history) {
+		// history doesn't have enough capacity to hold the new block.
+		if cap(z.history) == 0 {
+			historySize := max(2*z.MaxDistance, 1<<20, len(src))
+			z.history = make([]byte, 0, historySize)
+		} else {
+			// Move down
+			offset := len(z.history) - z.MaxDistance
+			copy(z.history[:z.MaxDistance], z.history[offset:])
+			z.current += int32(offset)
+			z.history = z.history[:z.MaxDistance]
+		}
+	}
+	s := int32(len(z.history))
+	z.history = append(z.history, src...)
+
+	if len(src) < 10 {
+		return append(dst, Match{
+			Unmatched: len(src),
+		})
+	}
+
+	src = z.history
+	sLimit := int32(len(src)) - 8
+
+	const stepSize = 2
+
+	nextEmit := s
+	cv := binary.LittleEndian.Uint64(src[s:])
+	var offset1, offset2 int32
+
+mainLoop:
+	for {
+		// t will contain the match offset when we find one.
+		// When exiting the search loop, we have already checked 4 bytes.
+		var t int32
+
+		for {
+			nextHash := z.hash(cv)
+			nextHash2 := z.hash(cv >> 8)
+			candidate := z.table[nextHash]
+			candidate2 := z.table[nextHash2]
+			repIndex := s - offset1 + 2
+
+			z.table[nextHash] = tableEntry{offset: s + z.current, val: uint32(cv)}
+			z.table[nextHash2] = tableEntry{offset: s + z.current + 1, val: uint32(cv >> 8)}
+
+			if offset1 != 0 && repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>16) {
+				// There is a repeated match at s+2.
+				end := extendMatch(src, int(repIndex+4), int(s+6))
+				start := s + 2
+				for repIndex > 0 && start > nextEmit && src[repIndex-1] == src[start-1] {
+					repIndex--
+					start--
+				}
+				dst = append(dst, Match{
+					Unmatched: int(start - nextEmit),
+					Length:    end - int(start),
+					Distance:  int(start - repIndex),
+				})
+				s = int32(end)
+				nextEmit = s
+				if s >= sLimit {
+					break mainLoop
+				}
+				cv = binary.LittleEndian.Uint64(src[s:])
+				continue
+			}
+
+			coffset0 := s - (candidate.offset - z.current)
+			coffset1 := s - (candidate2.offset - z.current) + 1
+			if coffset0 < int32(z.MaxDistance) && uint32(cv) == candidate.val {
+				t = candidate.offset - z.current
+				if binary.LittleEndian.Uint32(src[t:]) == uint32(cv) {
+					// found a regular match
+					break
+				}
+			}
+			if coffset1 < int32(z.MaxDistance) && uint32(cv>>8) == candidate2.val {
+				t = candidate2.offset - z.current
+				if binary.LittleEndian.Uint32(src[t:]) == uint32(cv>>8) {
+					s++
+					break
+				}
+			}
+
+			s += stepSize + ((s - nextEmit) >> 5)
+			if s > sLimit {
+				break mainLoop
+			}
+			cv = binary.LittleEndian.Uint64(src[s:])
+		}
+
+		// A 4-byte match has been found. We'll later see if more than
+		// 4 bytes.
+		offset2 = offset1
+		offset1 = s - t
+
+		end := extendMatch(src, int(t+4), int(s+4))
+		for t > 0 && s > nextEmit && src[t-1] == src[s-1] {
+			s--
+			t--
+		}
+
+		dst = append(dst, Match{
+			Unmatched: int(s - nextEmit),
+			Length:    end - int(s),
+			Distance:  int(s - t),
+		})
+		s = int32(end)
+		nextEmit = s
+		if s >= sLimit {
+			break mainLoop
+		}
+		cv = binary.LittleEndian.Uint64(src[s:])
+
+		// Check offset 2
+		if o2 := s - offset2; offset2 != 0 && binary.LittleEndian.Uint32(src[o2:]) == uint32(cv) {
+			end := extendMatch(src, int(o2+4), int(s+4))
+
+			// Store the hash, since we have it.
+			nextHash := z.hash(cv)
+			z.table[nextHash] = tableEntry{offset: s + z.current, val: uint32(cv)}
+			dst = append(dst, Match{
+				Length:   end - int(s),
+				Distance: int(offset2),
+			})
+			s = int32(end)
+			nextEmit = s
+			offset1, offset2 = offset2, offset1
+			if s >= sLimit {
+				break mainLoop
+			}
+			cv = binary.LittleEndian.Uint64(src[s:])
+		}
+	}
+
+	if int(nextEmit) < len(src) {
+		dst = append(dst, Match{
+			Unmatched: len(src) - int(nextEmit),
+		})
+	}
+
+	return dst
+}
+
+func (z *ZFast) hash(u uint64) uint32 {
+	return uint32(((u << 16) * prime6Bytes) >> (64 - zfastTableBits))
+}

+ 301 - 0
vendor/github.com/andybalholm/brotli/matchfinder/zm.go

@@ -0,0 +1,301 @@
+package matchfinder
+
+import "encoding/binary"
+
+const (
+	zmTableBits     = 15
+	zmTableSize     = 1 << zmTableBits
+	zmLongTableBits = 17
+	zmLongTableSize = 1 << zmLongTableBits
+)
+
+// ZM is a MatchFinder that combines the cache tables of ZDFast with the
+// overlap-based parsing of M4.
+type ZM struct {
+	MaxDistance int
+	history     []byte
+	table       [zmTableSize]tableEntry
+	longTable   [zmLongTableSize]tableEntry
+}
+
+func (z *ZM) Reset() {
+	z.table = [zmTableSize]tableEntry{}
+	z.longTable = [zmLongTableSize]tableEntry{}
+	z.history = z.history[:0]
+}
+
+func (z *ZM) FindMatches(dst []Match, src []byte) []Match {
+	if z.MaxDistance == 0 {
+		z.MaxDistance = 1 << 16
+	}
+
+	if len(z.history) > z.MaxDistance*2 {
+		delta := len(z.history) - z.MaxDistance
+		copy(z.history, z.history[delta:])
+		z.history = z.history[:z.MaxDistance]
+
+		for i := range z.table {
+			v := z.table[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.table[i] = tableEntry{}
+			} else {
+				z.table[i].offset = v
+			}
+		}
+		for i := range z.longTable {
+			v := z.longTable[i].offset
+			v -= int32(delta)
+			if v < 0 {
+				z.longTable[i] = tableEntry{}
+			} else {
+				z.longTable[i].offset = v
+			}
+		}
+	}
+
+	if len(src) < 16 {
+		return append(dst, Match{
+			Unmatched: len(src),
+		})
+	}
+
+	e := matchEmitter{
+		Dst:      dst,
+		NextEmit: len(z.history),
+	}
+	z.history = append(z.history, src...)
+	src = z.history
+
+	// matches stores the matches that have been found but not emitted,
+	// in reverse order. (matches[0] is the most recent one.)
+	var matches [3]absoluteMatch
+
+	sLimit := int32(len(src)) - 10
+
+mainLoop:
+	for {
+		// Search for a match, starting after the last match emitted.
+		s := int32(e.NextEmit)
+		if s > sLimit {
+			break mainLoop
+		}
+
+		// t will contain the match offset when we find one.
+		var t int32
+
+		cv := binary.LittleEndian.Uint64(src[s:])
+
+		for {
+			nextHashL := z.hashLong(cv)
+			nextHashS := z.hashShort(cv)
+			candidateL := z.longTable[nextHashL]
+			candidateS := z.table[nextHashS]
+
+			entry := tableEntry{offset: s, val: uint32(cv)}
+			z.longTable[nextHashL] = entry
+			z.table[nextHashS] = entry
+
+			// Look for a repeat match one byte after the current position.
+			if len(e.Dst) > 0 {
+				prevDistance := int32(e.Dst[len(e.Dst)-1].Distance)
+				if prevDistance != 0 {
+					repIndex := s - prevDistance + 1
+					if repIndex >= 0 && binary.LittleEndian.Uint32(src[repIndex:]) == uint32(cv>>8) {
+						// There is a repeated match at s+2.
+						s++
+						t = repIndex
+						break
+					}
+				}
+			}
+
+			if candidateL.offset < s && s-candidateL.offset < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+				binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+				// There is a long match at s.
+				t = candidateL.offset
+				break
+			}
+			if candidateS.offset < s && s-candidateS.offset < int32(z.MaxDistance) && uint32(cv) == candidateS.val &&
+				binary.LittleEndian.Uint32(src[candidateS.offset:]) == uint32(cv) {
+				// There is a regular match at s.
+				// See if we can find a long match at s+1.
+				cv := binary.LittleEndian.Uint64(src[s+1:])
+				nextHashL = z.hashLong(cv)
+				candidateL = z.longTable[nextHashL]
+				coffsetL := s - candidateL.offset + 1
+				z.longTable[nextHashL] = tableEntry{offset: s + 1, val: uint32(cv)}
+				if candidateL.offset < s+1 && coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+					binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+					// We found a long match at s+1, so we'll use that instead
+					// of the regular match at s.
+					t = candidateL.offset
+					s++
+					break
+				}
+
+				t = candidateS.offset
+				break
+			}
+
+			s += 1 + ((s - int32(e.NextEmit)) >> 7)
+			if s > sLimit {
+				break mainLoop
+			}
+			cv = binary.LittleEndian.Uint64(src[s:])
+		}
+
+		currentMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+		matches[0] = currentMatch
+
+		// Store some table entries after s.
+		index0 := s + 1
+		cv0 := binary.LittleEndian.Uint64(src[index0:])
+		te0 := tableEntry{offset: index0, val: uint32(cv0)}
+		z.longTable[z.hashLong(cv0)] = te0
+		cv0 >>= 8
+		te0.offset++
+		te0.val = uint32(cv0)
+		z.table[z.hashShort(cv0)] = te0
+
+		// We have a match in matches[0].
+		// Now look for overlapping matches.
+
+		for {
+			if matches[0].End > int(sLimit) {
+				break
+			}
+			s = int32(max(matches[0].Start+2, matches[0].End-6))
+			cv = binary.LittleEndian.Uint64(src[s:])
+
+			nextHashL := z.hashLong(cv)
+			nextHashS := z.hashShort(cv)
+			candidateL := z.longTable[nextHashL]
+			candidateS := z.table[nextHashS]
+
+			entry := tableEntry{offset: s, val: uint32(cv)}
+			z.longTable[nextHashL] = entry
+			z.table[nextHashS] = entry
+
+			t = -1
+			if candidateL.offset < s && s-candidateL.offset < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+				binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+				// There is a long match at s.
+				t = candidateL.offset
+			} else if candidateS.offset < s && s-candidateS.offset < int32(z.MaxDistance) && uint32(cv) == candidateS.val &&
+				binary.LittleEndian.Uint32(src[candidateS.offset:]) == uint32(cv) {
+				// There is a regular match at s.
+				t = candidateS.offset
+				// See if we can find a long match at s+1.
+				cv := binary.LittleEndian.Uint64(src[s+1:])
+				nextHashL = z.hashLong(cv)
+				candidateL = z.longTable[nextHashL]
+				coffsetL := s - candidateL.offset + 1
+				z.longTable[nextHashL] = tableEntry{offset: s + 1, val: uint32(cv)}
+				if candidateL.offset < s+1 && coffsetL < int32(z.MaxDistance) && uint32(cv) == candidateL.val &&
+					binary.LittleEndian.Uint32(src[candidateL.offset:]) == uint32(cv) {
+					// We found a long match at s+1, so we'll use that instead
+					// of the regular match at s.
+					t = candidateL.offset
+					s++
+				}
+			}
+
+			if t == -1 {
+				// No overlapping match was found.
+				break
+			}
+
+			newMatch := extendMatch2(src, int(s), int(t), e.NextEmit)
+
+			if newMatch.End-newMatch.Start <= matches[0].End-matches[0].Start {
+				// The new match isn't longer than the old one, so we break out of the loop
+				// of looking for overlapping matches.
+				break
+			}
+
+			matches = [3]absoluteMatch{
+				newMatch,
+				matches[0],
+				matches[1],
+			}
+
+			if matches[2] == (absoluteMatch{}) {
+				continue
+			}
+
+			// We have three matches, so it's time to emit one and/or eliminate one.
+			switch {
+			case matches[0].Start < matches[2].End:
+				// The first and third matches overlap; discard the one in between.
+				matches = [3]absoluteMatch{
+					matches[0],
+					matches[2],
+					{},
+				}
+
+			case matches[0].Start < matches[2].End+4:
+				// The first and third matches don't overlap, but there's no room for
+				// another match between them. Emit the first match and discard the second.
+				e.emit(matches[2])
+				matches = [3]absoluteMatch{
+					matches[0],
+					{},
+					{},
+				}
+
+			default:
+				// Emit the first match, shortening it if necessary to avoid overlap with the second.
+				if matches[2].End > matches[1].Start {
+					matches[2].End = matches[1].Start
+				}
+				if matches[2].End-matches[2].Start >= 4 {
+					e.emit(matches[2])
+				}
+				matches[2] = absoluteMatch{}
+			}
+		}
+
+		// Store some table entries at the end of the last match.
+		index1 := int32(matches[0].End - 2)
+		if index1 < sLimit {
+			cv1 := binary.LittleEndian.Uint64(src[index1:])
+			te1 := tableEntry{offset: index1, val: uint32(cv1)}
+			z.longTable[z.hashLong(cv1)] = te1
+			cv1 >>= 8
+			te1.offset++
+			te1.val = uint32(cv1)
+			z.table[z.hashShort(cv1)] = te1
+		}
+
+		// We're done looking for overlapping matches; emit the ones we have.
+
+		if matches[1] != (absoluteMatch{}) {
+			if matches[1].End > matches[0].Start {
+				matches[1].End = matches[0].Start
+			}
+			if matches[1].End-matches[1].Start >= 4 {
+				e.emit(matches[1])
+			}
+		}
+		e.emit(matches[0])
+		matches = [3]absoluteMatch{}
+	}
+
+	dst = e.Dst
+	if e.NextEmit < len(src) {
+		dst = append(dst, Match{
+			Unmatched: len(src) - e.NextEmit,
+		})
+	}
+
+	return dst
+}
+
+func (z *ZM) hashShort(u uint64) uint32 {
+	return uint32(((u << 24) * 889523592379) >> (64 - zmTableBits))
+}
+
+func (z *ZM) hashLong(u uint64) uint32 {
+	return uint32((u * 0xcf1bbcdcb7a56463) >> (64 - zmLongTableBits))
+}

+ 1 - 1
vendor/github.com/andybalholm/brotli/metablock_command.go

@@ -44,7 +44,7 @@ func initBlockSplitterCommand(self *blockSplitterCommand, alphabet_size uint, mi
 	brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
 	self.split_.num_blocks = max_num_blocks
 	*histograms_size = max_num_types
-	if histograms == nil || cap(*histograms) < int(*histograms_size) {
+	if cap(*histograms) < int(*histograms_size) {
 		*histograms = make([]histogramCommand, (*histograms_size))
 	} else {
 		*histograms = (*histograms)[:*histograms_size]

+ 1 - 1
vendor/github.com/andybalholm/brotli/metablock_distance.go

@@ -44,7 +44,7 @@ func initBlockSplitterDistance(self *blockSplitterDistance, alphabet_size uint,
 	brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
 	self.split_.num_blocks = max_num_blocks
 	*histograms_size = max_num_types
-	if histograms == nil || cap(*histograms) < int(*histograms_size) {
+	if cap(*histograms) < int(*histograms_size) {
 		*histograms = make([]histogramDistance, *histograms_size)
 	} else {
 		*histograms = (*histograms)[:*histograms_size]

+ 1 - 1
vendor/github.com/andybalholm/brotli/metablock_literal.go

@@ -44,7 +44,7 @@ func initBlockSplitterLiteral(self *blockSplitterLiteral, alphabet_size uint, mi
 	brotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)
 	self.split_.num_blocks = max_num_blocks
 	*histograms_size = max_num_types
-	if histograms == nil || cap(*histograms) < int(*histograms_size) {
+	if cap(*histograms) < int(*histograms_size) {
 		*histograms = make([]histogramLiteral, *histograms_size)
 	} else {
 		*histograms = (*histograms)[:*histograms_size]

+ 27 - 39
vendor/github.com/andybalholm/brotli/writer.go

@@ -124,51 +124,39 @@ func (nopCloser) Close() error { return nil }
 // based on the matchfinder package. It currently supports up to level 9;
 // if a higher level is specified, level 9 will be used.
 func NewWriterV2(dst io.Writer, level int) *matchfinder.Writer {
+	if level < 0 {
+		level = 0
+	} else if level > 9 {
+		level = 9
+	}
 	var mf matchfinder.MatchFinder
-	if level < 2 {
-		mf = matchfinder.M0{Lazy: level == 1}
-	} else if level < 8 {
-		hashLen := 6
-		if level >= 6 {
-			hashLen = 5
-		}
-		chainLen := 16
-		switch level {
-		case 2:
-			chainLen = 0
-		case 3:
-			chainLen = 1
-		case 4:
-			chainLen = 2
-		case 5:
-			chainLen = 4
-		case 6:
-			chainLen = 8
-		}
-		mf = &matchfinder.M4{
-			MaxDistance:     1 << 20,
-			ChainLength:     chainLen,
-			HashLen:         hashLen,
-			DistanceBitCost: 66,
-		}
-	} else {
-		chainLen := 32
-		hashLen := 5
-		if level == 8 {
-			chainLen = 4
-			hashLen = 6
-		}
-		mf = &matchfinder.Pathfinder{
-			MaxDistance: 1 << 20,
-			ChainLength: chainLen,
-			HashLen:     hashLen,
-		}
+	switch level {
+	case 0, 1:
+		mf = &matchfinder.ZFast{MaxDistance: 1 << 20}
+	case 2:
+		mf = &matchfinder.ZDFast{MaxDistance: 1 << 20}
+	case 3:
+		mf = &matchfinder.ZM{MaxDistance: 1 << 20}
+	case 4:
+		mf = &matchfinder.Trio{MaxDistance: 1 << 20}
+	case 5, 6:
+		mf = &matchfinder.Bargain1{MaxDistance: 1 << 20}
+	case 7:
+		mf = &matchfinder.Bargain2{MaxDistance: 1 << 20, Skip: true}
+	case 8:
+		mf = &matchfinder.Bargain2{MaxDistance: 1 << 20}
+	case 9:
+		mf = &matchfinder.Bargain3{MaxDistance: 1 << 20}
 	}
 
-	return &matchfinder.Writer{
+	w := &matchfinder.Writer{
 		Dest:        dst,
 		MatchFinder: mf,
 		Encoder:     &Encoder{},
 		BlockSize:   1 << 16,
 	}
+	if level < 1 {
+		w.Encoder = &FastEncoder{}
+	}
+	return w
 }

+ 0 - 2
vendor/github.com/clipperhouse/stringish/.gitignore

@@ -1,2 +0,0 @@
-.DS_Store
-*.test

+ 0 - 21
vendor/github.com/clipperhouse/stringish/LICENSE

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2025 Matt Sherman
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 0 - 64
vendor/github.com/clipperhouse/stringish/README.md

@@ -1,64 +0,0 @@
-# stringish
-
-A small Go module that provides a generic type constraint for “string-like”
-data, and a utf8 package that works with both strings and byte slices
-without conversions.
-
-```go
-type Interface interface {
-	~[]byte | ~string
-}
-```
-
-[![Go Reference](https://pkg.go.dev/badge/github.com/clipperhouse/stringish/utf8.svg)](https://pkg.go.dev/github.com/clipperhouse/stringish/utf8)
-[![Test Status](https://github.com/clipperhouse/stringish/actions/workflows/gotest.yml/badge.svg)](https://github.com/clipperhouse/stringish/actions/workflows/gotest.yml)
-
-## Install
-
-```
-go get github.com/clipperhouse/stringish
-```
-
-## Examples
-
-```go
-import (
-    "github.com/clipperhouse/stringish"
-    "github.com/clipperhouse/stringish/utf8"
-)
-
-s := "Hello, 世界"
-r, size := utf8.DecodeRune(s)   // not DecodeRuneInString 🎉
-
-b := []byte("Hello, 世界")
-r, size = utf8.DecodeRune(b)    // same API!
-
-func MyFoo[T stringish.Interface](s T) T {
-    // pass a string or a []byte
-    // iterate, slice, transform, whatever
-}
-```
-
-## Motivation
-
-Sometimes we want APIs to accept `string` or `[]byte` without having to convert
-between those types. That conversion usually allocates!
-
-By implementing with `stringish.Interface`, we can have a single API, and
-single implementation for both types: one `Foo` instead of `Foo` and
-`FooString`.
-
-We have converted the
-[`unicode/utf8` package](https://github.com/clipperhouse/stringish/blob/main/utf8/utf8.go)
-as an example -- note the absence of`*InString` funcs. We might look at `x/text`
-next.
-
-## Used by
-
-- clipperhouse/uax29: [stringish trie](https://github.com/clipperhouse/uax29/blob/master/graphemes/trie.go#L27), [stringish iterator](https://github.com/clipperhouse/uax29/blob/master/internal/iterators/iterator.go#L9), [stringish SplitFunc](https://github.com/clipperhouse/uax29/blob/master/graphemes/splitfunc.go#L21)
-
-- [clipperhouse/displaywidth](https://github.com/clipperhouse/displaywidth)
-
-## Prior discussion
-
-- [Consideration of similar by the Go team](https://github.com/golang/go/issues/48643)

+ 0 - 5
vendor/github.com/clipperhouse/stringish/interface.go

@@ -1,5 +0,0 @@
-package stringish
-
-type Interface interface {
-	~[]byte | ~string
-}

+ 50 - 24
vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md

@@ -1,4 +1,4 @@
-An implementation of grapheme cluster boundaries from [Unicode text segmentation](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) (UAX 29), for Unicode version 15.0.0.
+An implementation of grapheme cluster boundaries from [Unicode text segmentation](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) (UAX 29), for Unicode 17.
 
 [![Documentation](https://pkg.go.dev/badge/github.com/clipperhouse/uax29/v2/graphemes.svg)](https://pkg.go.dev/github.com/clipperhouse/uax29/v2/graphemes)
 ![Tests](https://github.com/clipperhouse/uax29/actions/workflows/gotest.yml/badge.svg)
@@ -7,18 +7,17 @@ An implementation of grapheme cluster boundaries from [Unicode text segmentation
 ## Quick start
 
 ```
-go get "github.com/clipperhouse/uax29/v2/graphemes"
+go get github.com/clipperhouse/uax29/v2/graphemes
 ```
 
 ```go
 import "github.com/clipperhouse/uax29/v2/graphemes"
 
 text := "Hello, 世界. Nice dog! 👍🐶"
+g := graphemes.FromString(text)
 
-tokens := graphemes.FromString(text)
-
-for tokens.Next() {                     // Next() returns true until end of data
-	fmt.Println(tokens.Value())         // Do something with the current grapheme
+for g.Next() {                     // Next() returns true until end of data
+	fmt.Println(g.Value())         // Do something with the current grapheme
 }
 ```
 
@@ -26,7 +25,7 @@ _A grapheme is a “single visible character”, which might be a simple as a si
 
 ## Conformance
 
-We use the Unicode [test suite](https://unicode.org/reports/tr41/tr41-26.html#Tests29).
+We use the Unicode [test suite](https://unicode.org/reports/tr41/tr41-36.html#Tests29).
 
 ![Tests](https://github.com/clipperhouse/uax29/actions/workflows/gotest.yml/badge.svg)
 ![Fuzz](https://github.com/clipperhouse/uax29/actions/workflows/gofuzz.yml/badge.svg)
@@ -37,11 +36,10 @@ We use the Unicode [test suite](https://unicode.org/reports/tr41/tr41-26.html#Te
 
 ```go
 text := "Hello, 世界. Nice dog! 👍🐶"
+g := graphemes.FromString(text)
 
-tokens := graphemes.FromString(text)
-
-for tokens.Next() {                     // Next() returns true until end of data
-	fmt.Println(tokens.Value())         // Do something with the current grapheme
+for g.Next() {                     // Next() returns true until end of data
+	fmt.Println(g.Value())         // Do something with the current grapheme
 }
 ```
 
@@ -50,15 +48,15 @@ for tokens.Next() {                     // Next() returns true until end of data
 `FromReader` embeds a [`bufio.Scanner`](https://pkg.go.dev/bufio#Scanner), so just use those methods.
 
 ```go
-r := getYourReader()                        // from a file or network maybe
-tokens := graphemes.FromReader(r)
+r := getYourReader()                    // from a file or network maybe
+g := graphemes.FromReader(r)
 
-for tokens.Scan() {                         // Scan() returns true until error or EOF
-	fmt.Println(tokens.Text())              // Do something with the current grapheme
+for g.Scan() {                         // Scan() returns true until error or EOF
+	fmt.Println(g.Text())              // Do something with the current grapheme
 }
 
-if tokens.Err() != nil {                    // Check the error
-	log.Fatal(tokens.Err())
+if g.Err() != nil {                    // Check the error
+	log.Fatal(g.Err())
 }
 ```
 
@@ -67,24 +65,52 @@ if tokens.Err() != nil {                    // Check the error
 ```go
 b := []byte("Hello, 世界. Nice dog! 👍🐶")
 
-tokens := graphemes.FromBytes(b)
+g := graphemes.FromBytes(b)
 
-for tokens.Next() {                     // Next() returns true until end of data
-	fmt.Println(tokens.Value())         // Do something with the current grapheme
+for g.Next() {                     // Next() returns true until end of data
+	fmt.Println(g.Value())         // Do something with the current grapheme
 }
 ```
 
-### Benchmarks
+### ANSI escape sequences
+
+By the UAX 29 specification, ANSI escape sequences are not grapheme clusters. To treat 7-bit ANSI escape sequences as a single cluster, set `AnsiEscapeSequences` to true.
+
+```go
+text := "Hello, \x1b[31mworld\x1b[0m!"
+g := graphemes.FromString(text)
+g.AnsiEscapeSequences = true
+
+for g.Next() {
+	fmt.Println(g.Value())
+}
+```
 
-On a Mac M2 laptop, we see around 200MB/s, or around 100 million graphemes per second, and no allocations.
+To also parse 8-bit C1 controls (non-UTF-8 bytes), set `AnsiEscapeSequences8Bit` to true.
+
+```go
+g.AnsiEscapeSequences = true     // 7-bit forms (ESC ...)
+g.AnsiEscapeSequences8Bit = true // 8-bit C1 forms (0x80-0x9F), not valid UTF-8
+```
+
+For ESC-initiated (7-bit) control strings, only 7-bit terminators are recognized.
+For C1-initiated (8-bit) control strings, only C1 ST (`0x9C`) is recognized as ST.
+
+We implement [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/) control codes in both 7-bit and 8-bit representations. 8-bit control codes are not UTF-8 encoded and are not valid UTF-8, caveat emptor.
+
+### Benchmarks
 
 ```
 goos: darwin
 goarch: arm64
 pkg: github.com/clipperhouse/uax29/graphemes/comparative
 cpu: Apple M2
-BenchmarkGraphemes/clipperhouse/uax29-8    	    173805 ns/op	 201.16 MB/s      0 B/op	   0 allocs/op
-BenchmarkGraphemes/rivo/uniseg-8           	   2045128 ns/op	  17.10 MB/s      0 B/op	   0 allocs/op
+
+BenchmarkGraphemesMixed/clipperhouse/uax29-8  	    142635 ns/op	 245.12 MB/s    0 B/op	   0 allocs/op
+BenchmarkGraphemesMixed/rivo/uniseg-8         	   2018284 ns/op	  17.32 MB/s    0 B/op	   0 allocs/op
+
+BenchmarkGraphemesASCII/clipperhouse/uax29-8  	      8846 ns/op	 508.73 MB/s    0 B/op	   0 allocs/op
+BenchmarkGraphemesASCII/rivo/uniseg-8         	    366760 ns/op	  12.27 MB/s    0 B/op	   0 allocs/op
 ```
 
 ### Invalid inputs

+ 138 - 0
vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go

@@ -0,0 +1,138 @@
+package graphemes
+
+// ansiEscapeLength returns the byte length of a valid 7-bit ANSI escape
+// sequence at the start of data, or 0 if none.
+//
+// Recognized forms (ECMA-48 / ISO 6429):
+//   - CSI: ESC [ then parameter bytes (0x30-0x3F), intermediate (0x20-0x2F), final (0x40-0x7E)
+//   - OSC: ESC ] then payload until BEL (0x07), 7-bit ST (ESC \), CAN (0x18), or SUB (0x1A)
+//   - DCS, SOS, PM, APC: ESC P/X/^/_ then payload until 7-bit ST (ESC \), CAN, or SUB
+//   - Two-byte: ESC + Fe/Fs (0x40-0x7E excluding above), or Fp (0x30-0x3F), or nF (0x20-0x2F then final)
+func ansiEscapeLength[T ~string | ~[]byte](data T) int {
+	n := len(data)
+	if n < 2 || data[0] != esc {
+		return 0
+	}
+
+	b1 := data[1]
+	switch b1 {
+	case '[': // CSI
+		body := csiBodyLength(data[2:])
+		if body == 0 {
+			return 0
+		}
+		return 2 + body
+	case ']': // OSC - allows BEL or 7-bit ST terminator
+		body := oscLength(data[2:])
+		if body < 0 {
+			return 0
+		}
+		return 2 + body
+	case 'P', 'X', '^', '_': // DCS, SOS, PM, APC
+		body := stSequenceLength(data[2:])
+		if body < 0 {
+			return 0
+		}
+		return 2 + body
+	}
+
+	if b1 >= 0x40 && b1 <= 0x7E {
+		// Fe/Fs two-byte; [ ] P X ^ _ handled above
+		return 2
+	}
+	if b1 >= 0x30 && b1 <= 0x3F {
+		// Fp (private) two-byte
+		return 2
+	}
+	if b1 >= 0x20 && b1 <= 0x2F {
+		// nF: intermediates then one final (0x30-0x7E)
+		i := 2
+		for i < n && data[i] >= 0x20 && data[i] <= 0x2F {
+			i++
+		}
+		if i < n && data[i] >= 0x30 && data[i] <= 0x7E {
+			return i + 1
+		}
+		return 0
+	}
+
+	return 0
+}
+
+// csiBodyLength returns the length of the CSI body (param/intermediate/final bytes).
+// data is the slice after "ESC [".
+// Per ECMA-48, the CSI body has the form:
+//
+//	parameters (0x30–0x3F)*, intermediates (0x20–0x2F)*, final (0x40–0x7E)
+//
+// Once an intermediate byte is seen, subsequent parameter bytes are invalid.
+func csiBodyLength[T ~string | ~[]byte](data T) int {
+	seenIntermediate := false
+	for i := 0; i < len(data); i++ {
+		b := data[i]
+		if b >= 0x30 && b <= 0x3F {
+			if seenIntermediate {
+				return 0
+			}
+			continue
+		}
+		if b >= 0x20 && b <= 0x2F {
+			seenIntermediate = true
+			continue
+		}
+		if b >= 0x40 && b <= 0x7E {
+			return i + 1
+		}
+		return 0
+	}
+	return 0
+}
+
+// oscLength returns the length of the OSC body.
+// data is the slice after "ESC ]".
+//
+// Returns:
+//   - n >= 0: consumed body length (includes BEL/ST terminator when present)
+//   - -1: not terminated in the provided data
+//
+// OSC accepts BEL (0x07) or 7-bit ST (ESC \) as terminators by widespread convention.
+// Per ECMA-48, CAN (0x18) and SUB (0x1A) cancel the control string; in that
+// case they are not part of the OSC sequence length.
+func oscLength[T ~string | ~[]byte](data T) int {
+	for i := 0; i < len(data); i++ {
+		b := data[i]
+		if b == bel {
+			return i + 1
+		}
+		if b == can || b == sub {
+			return i
+		}
+		if b == esc && i+1 < len(data) && data[i+1] == '\\' {
+			return i + 2
+		}
+	}
+	return -1
+}
+
+// stSequenceLength returns the length of a control-string body.
+// data is the slice after "ESC x".
+//
+// Returns:
+//   - n >= 0: consumed body length (includes ST terminator when present)
+//   - -1: not terminated in the provided data
+//
+// Used for DCS, SOS, PM, and APC, which per ECMA-48 terminate with ST.
+// ST here is the 7-bit form (ESC \).
+// CAN (0x18) and SUB (0x1A) cancel the control string; in that case they are
+// not part of the sequence length.
+func stSequenceLength[T ~string | ~[]byte](data T) int {
+	for i := 0; i < len(data); i++ {
+		if data[i] == can || data[i] == sub {
+			return i
+		}
+		if data[i] == esc && i+1 < len(data) && data[i+1] == '\\' {
+			return i + 2
+		}
+	}
+	return -1
+}

+ 79 - 0
vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go

@@ -0,0 +1,79 @@
+package graphemes
+
+// ansiEscapeLength8Bit returns the byte length of a valid 8-bit C1 ANSI
+// sequence at the start of data, or 0 if none.
+//
+// Recognized forms (ECMA-48 / ISO 6429):
+//   - C1 CSI (0x9B) body as parameter/intermediate/final bytes
+//   - C1 OSC (0x9D) body terminated by BEL, C1 ST, CAN, or SUB
+//   - C1 DCS/SOS/PM/APC (0x90/0x98/0x9E/0x9F) body terminated by C1 ST, CAN, or SUB
+//   - Standalone C1 controls (0x80..0x9F not listed above): single byte
+func ansiEscapeLength8Bit[T ~string | ~[]byte](data T) int {
+	if len(data) == 0 {
+		return 0
+	}
+
+	switch data[0] {
+	case 0x9B: // C1 CSI
+		body := csiBodyLength(data[1:])
+		if body == 0 {
+			return 0
+		}
+		return 1 + body
+	case 0x9D: // C1 OSC
+		body := oscLengthC1(data[1:])
+		if body < 0 {
+			return 0
+		}
+		return 1 + body
+	case 0x90, 0x98, 0x9E, 0x9F: // C1 DCS, SOS, PM, APC
+		body := stSequenceLengthC1(data[1:])
+		if body < 0 {
+			return 0
+		}
+		return 1 + body
+	default:
+		if data[0] >= 0x80 && data[0] <= 0x9F {
+			return 1
+		}
+	}
+
+	return 0
+}
+
+// oscLengthC1 returns the length of a C1 OSC body.
+// data is the slice after the C1 OSC initiator (0x9D).
+//
+// Returns:
+//   - n >= 0: consumed body length (includes BEL/ST terminator when present)
+//   - -1: not terminated in the provided data
+//
+// Terminators: BEL (0x07) or C1 ST (0x9C).
+// CAN (0x18) and SUB (0x1A) cancel the control string.
+func oscLengthC1[T ~string | ~[]byte](data T) int {
+	for i := 0; i < len(data); i++ {
+		b := data[i]
+		if b == bel || b == st {
+			return i + 1
+		}
+		if b == can || b == sub {
+			return i
+		}
+	}
+	return -1
+}
+
+// stSequenceLengthC1 parses DCS/SOS/PM/APC bodies that terminate with C1 ST
+// (0x9C), or are canceled by CAN/SUB.
+func stSequenceLengthC1[T ~string | ~[]byte](data T) int {
+	for i := 0; i < len(data); i++ {
+		b := data[i]
+		if b == can || b == sub {
+			return i
+		}
+		if b == st {
+			return i + 1
+		}
+	}
+	return -1
+}

+ 129 - 16
vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go

@@ -1,12 +1,44 @@
 package graphemes
 
-import (
-	"github.com/clipperhouse/stringish"
-	"github.com/clipperhouse/uax29/v2/internal/iterators"
-)
+import "unicode/utf8"
+
+// FromString returns an iterator for the grapheme clusters in the input string.
+// Iterate while Next() is true, and access the grapheme via Value().
+func FromString(s string) *Iterator[string] {
+	return &Iterator[string]{
+		split: splitFuncString,
+		data:  s,
+	}
+}
 
-type Iterator[T stringish.Interface] struct {
-	*iterators.Iterator[T]
+// FromBytes returns an iterator for the grapheme clusters in the input bytes.
+// Iterate while Next() is true, and access the grapheme via Value().
+func FromBytes(b []byte) *Iterator[[]byte] {
+	return &Iterator[[]byte]{
+		split: splitFuncBytes,
+		data:  b,
+	}
+}
+
+// Iterator is a generic iterator for grapheme clusters in strings or byte slices,
+// with an ASCII hot path optimization.
+type Iterator[T ~string | ~[]byte] struct {
+	split func(T, bool) (int, T, error)
+	data  T
+	pos   int
+	start int
+	// AnsiEscapeSequences treats 7-bit ANSI escape sequences (ECMA-48) as
+	// single grapheme clusters when true. The default is false.
+	//
+	// 8-bit controls are not enabled by this option. See [AnsiEscapeSequences8Bit].
+	AnsiEscapeSequences bool
+	// AnsiEscapeSequences8Bit treats 8-bit C1 ANSI escape sequences (ECMA-48) as single
+	// grapheme clusters when true. The default is false.
+	//
+	// 8-bit control bytes are not UTF-8 encoded, i.e. not valid UTF-8. If you
+	// choose this option, you are choosing to interpret non-UTF-8 data, caveat
+	// emptor.
+	AnsiEscapeSequences8Bit bool
 }
 
 var (
@@ -14,18 +46,99 @@ var (
 	splitFuncBytes  = splitFunc[[]byte]
 )
 
-// FromString returns an iterator for the grapheme clusters in the input string.
-// Iterate while Next() is true, and access the grapheme via Value().
-func FromString(s string) Iterator[string] {
-	return Iterator[string]{
-		iterators.New(splitFuncString, s),
+const (
+	esc = 0x1B
+	cr  = 0x0D
+	bel = 0x07
+	can = 0x18
+	sub = 0x1A
+	st  = 0x9C
+)
+
+// Next advances the iterator to the next grapheme cluster.
+// Returns false when there are no more grapheme clusters.
+func (iter *Iterator[T]) Next() bool {
+	if iter.pos >= len(iter.data) {
+		return false
 	}
+	iter.start = iter.pos
+
+	b := iter.data[iter.pos]
+	if iter.AnsiEscapeSequences && b == esc {
+		if a := ansiEscapeLength(iter.data[iter.pos:]); a > 0 {
+			iter.pos += a
+			return true
+		}
+	}
+	if iter.AnsiEscapeSequences8Bit && b >= 0x80 && b <= 0x9F {
+		if a := ansiEscapeLength8Bit(iter.data[iter.pos:]); a > 0 {
+			iter.pos += a
+			return true
+		}
+	}
+
+	// ASCII hot path: any ASCII is one grapheme when next byte is ASCII or end.
+	if b < utf8.RuneSelf && b != cr {
+		if iter.pos+1 >= len(iter.data) || iter.data[iter.pos+1] < utf8.RuneSelf {
+			iter.pos++
+			return true
+		}
+	}
+
+	// Fall back to UAX29 grapheme parsing
+	remaining := iter.data[iter.pos:]
+	advance, _, err := iter.split(remaining, true)
+	if err != nil {
+		panic(err)
+	}
+	if advance <= 0 {
+		panic("splitFunc returned a zero or negative advance")
+	}
+	iter.pos += advance
+	if iter.pos > len(iter.data) {
+		panic("splitFunc advanced beyond end of data")
+	}
+	return true
 }
 
-// FromBytes returns an iterator for the grapheme clusters in the input bytes.
-// Iterate while Next() is true, and access the grapheme via Value().
-func FromBytes(b []byte) Iterator[[]byte] {
-	return Iterator[[]byte]{
-		iterators.New(splitFuncBytes, b),
+// Value returns the current grapheme cluster.
+func (iter *Iterator[T]) Value() T {
+	return iter.data[iter.start:iter.pos]
+}
+
+// Start returns the byte position of the current grapheme in the original data.
+func (iter *Iterator[T]) Start() int {
+	return iter.start
+}
+
+// End returns the byte position after the current grapheme in the original data.
+func (iter *Iterator[T]) End() int {
+	return iter.pos
+}
+
+// Reset resets the iterator to the beginning of the data.
+func (iter *Iterator[T]) Reset() {
+	iter.start = 0
+	iter.pos = 0
+}
+
+// SetText sets the data for the iterator to operate on, and resets all state.
+func (iter *Iterator[T]) SetText(data T) {
+	iter.data = data
+	iter.start = 0
+	iter.pos = 0
+}
+
+// First returns the first grapheme cluster without advancing the iterator.
+func (iter *Iterator[T]) First() T {
+	if len(iter.data) == 0 {
+		return iter.data
 	}
+
+	// Use a copy to leverage Next()'s ASCII optimization
+	cp := *iter
+	cp.pos = 0
+	cp.start = 0
+	cp.Next()
+	return cp.Value()
 }

+ 39 - 8
vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go

@@ -2,8 +2,6 @@ package graphemes
 
 import (
 	"bufio"
-
-	"github.com/clipperhouse/stringish"
 )
 
 // is determines if lookup intersects propert(ies)
@@ -13,12 +11,22 @@ func (lookup property) is(properties property) bool {
 
 const _Ignore = _Extend
 
+// incbState tracks state for GB9c rule (Indic conjunct clusters)
+// Pattern: Consonant (Extend|Linker)* Linker (Extend|Linker)* × Consonant
+type incbState int
+
+const (
+	incbNone      incbState = iota // initial/reset
+	incbConsonant                  // seen Consonant, awaiting Linker
+	incbLinker                     // seen Consonant and Linker (conjunct ready)
+)
+
 // SplitFunc is a bufio.SplitFunc implementation of Unicode grapheme cluster segmentation, for use with bufio.Scanner.
 //
 // See https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries.
 var SplitFunc bufio.SplitFunc = splitFunc[[]byte]
 
-func splitFunc[T stringish.Interface](data T, atEOF bool) (advance int, token T, err error) {
+func splitFunc[T ~string | ~[]byte](data T, atEOF bool) (advance int, token T, err error) {
 	var empty T
 	if len(data) == 0 {
 		return 0, empty, nil
@@ -30,6 +38,9 @@ func splitFunc[T stringish.Interface](data T, atEOF bool) (advance int, token T,
 	var lastLastExIgnore property = 0 // "last one before that"
 	var regionalIndicatorCount int
 
+	// GB9c state: tracking Indic conjunct clusters
+	var incb incbState
+
 	// Rules are usually of the form Cat1 × Cat2; "current" refers to the first property
 	// to the right of the ×, from which we look back or forward
 
@@ -76,6 +87,23 @@ func splitFunc[T stringish.Interface](data T, atEOF bool) (advance int, token T,
 			lastExIgnore = last
 		}
 
+		// Update GB9c state based on what we just advanced past
+		if last.is(_InCBConsonant | _InCBLinker | _InCBExtend) {
+			switch {
+			case last.is(_InCBConsonant):
+				if incb != incbLinker {
+					incb = incbConsonant
+				}
+			case last.is(_InCBLinker):
+				if incb >= incbConsonant {
+					incb = incbLinker
+				}
+				// case last.is(_InCBExtend): stay in current state
+			}
+		} else {
+			incb = incbNone
+		}
+
 		current, w = lookup(data[pos:])
 		if w == 0 {
 			if atEOF {
@@ -141,11 +169,14 @@ func splitFunc[T stringish.Interface](data T, atEOF bool) (advance int, token T,
 		}
 
 		// https://unicode.org/reports/tr29/#GB9c
-		// TODO(clipperhouse):
-		// It appears to be added in Unicode 15.1.0:
-		// https://unicode.org/versions/Unicode15.1.0/#Migration
-		// This package currently supports Unicode 15.0.0, so
-		// out of scope for now
+		// Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker.
+		if incb == incbLinker && current.is(_InCBConsonant) {
+			// After matching the pattern, reset state to start tracking a new pattern
+			// The current Consonant becomes the start of the new pattern
+			incb = incbConsonant
+			pos += w
+			continue
+		}
 
 		// https://unicode.org/reports/tr29/#GB11
 		if current.is(_ExtendedPictographic) && last.is(_ZWJ) && lastLastExIgnore.is(_ExtendedPictographic) {

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1235 - 930
vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go


+ 0 - 100
vendor/github.com/clipperhouse/uax29/v2/internal/iterators/iterator.go

@@ -1,100 +0,0 @@
-package iterators
-
-import "github.com/clipperhouse/stringish"
-
-type SplitFunc[T stringish.Interface] func(T, bool) (int, T, error)
-
-// Iterator is a generic iterator for words that are either []byte or string.
-// Iterate while Next() is true, and access the word via Value().
-type Iterator[T stringish.Interface] struct {
-	split SplitFunc[T]
-	data  T
-	start int
-	pos   int
-}
-
-// New creates a new Iterator for the given data and SplitFunc.
-func New[T stringish.Interface](split SplitFunc[T], data T) *Iterator[T] {
-	return &Iterator[T]{
-		split: split,
-		data:  data,
-	}
-}
-
-// SetText sets the text for the iterator to operate on, and resets all state.
-func (iter *Iterator[T]) SetText(data T) {
-	iter.data = data
-	iter.start = 0
-	iter.pos = 0
-}
-
-// Split sets the SplitFunc for the Iterator.
-func (iter *Iterator[T]) Split(split SplitFunc[T]) {
-	iter.split = split
-}
-
-// Next advances the iterator to the next token. It returns false when there
-// are no remaining tokens or an error occurred.
-func (iter *Iterator[T]) Next() bool {
-	if iter.pos == len(iter.data) {
-		return false
-	}
-	if iter.pos > len(iter.data) {
-		panic("SplitFunc advanced beyond the end of the data")
-	}
-
-	iter.start = iter.pos
-
-	advance, _, err := iter.split(iter.data[iter.pos:], true)
-	if err != nil {
-		panic(err)
-	}
-	if advance <= 0 {
-		panic("SplitFunc returned a zero or negative advance")
-	}
-
-	iter.pos += advance
-	if iter.pos > len(iter.data) {
-		panic("SplitFunc advanced beyond the end of the data")
-	}
-
-	return true
-}
-
-// Value returns the current token.
-func (iter *Iterator[T]) Value() T {
-	return iter.data[iter.start:iter.pos]
-}
-
-// Start returns the byte position of the current token in the original data.
-func (iter *Iterator[T]) Start() int {
-	return iter.start
-}
-
-// End returns the byte position after the current token in the original data.
-func (iter *Iterator[T]) End() int {
-	return iter.pos
-}
-
-// Reset resets the iterator to the beginning of the data.
-func (iter *Iterator[T]) Reset() {
-	iter.start = 0
-	iter.pos = 0
-}
-
-func (iter *Iterator[T]) First() T {
-	if len(iter.data) == 0 {
-		return iter.data
-	}
-	advance, _, err := iter.split(iter.data, true)
-	if err != nil {
-		panic(err)
-	}
-	if advance <= 0 {
-		panic("SplitFunc returned a zero or negative advance")
-	}
-	if advance > len(iter.data) {
-		panic("SplitFunc advanced beyond the end of the data")
-	}
-	return iter.data[:advance]
-}

+ 261 - 102
vendor/github.com/dgraph-io/badger/v4/CHANGELOG.md

@@ -4,10 +4,156 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 
-## [Unreleased]
+## [4.9.1] - 2026-02-04
+
+**Fixed**
+
+- fix(aix): add aix directory synchronization support (#2115)
+- fix: correct the comment on value size in skl.node (#2250)
+
+**Tests**
+
+- test: add checksum tests for package y (#2246)
+
+**Chores**
+
+- chore(ci): update arm runner label (#2248)
+
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.9.0...v4.9.1
+
+## [4.9.0] - 2025-12-15
+
+**Fixed**
+
+- fix(y): y.SafeCopy shall always return empty slice rather than nil (#2245)
+  > **WARNING** SafeCopy now returns an empty slice rather than nil. For those using our `y` utility
+  > package, this could be a breaking change. This has implications for empty slices stored in
+  > badger, specifically, upon retrieval the value stored with the key will be equal to what was set
+  > (an empty []byte). See #2067 for more details.
+- fix: test.sh error (#2225)
+- fix: typo of abandoned (#2222)
+
+**Docs**
+
+- add doc for encryption at rest (#2240)
+- move docs pages in the repo (#2232)
+
+**Chores**
+
+- chore(ci): restrict Dgraph test to core packages only (#2242)
+- chore: update README.md with correct links and badges (#2239)
+- chore: change renovate to maintain backwards compatible go version (#2236)
+- chore: configure renovate to leave go version as declared (#2235)
+- chore(deps): Update actions (major) (#2229)
+- chore(deps): Update actions/checkout action to v5 (#2221)
+- chore(deps): Update go minor and patch (#2218)
+- chore: update the trunk conf file (#2217)
+- chore(deps): Update dependency node to v22 (#2219)
+- chore(deps): Update go minor and patch (#2212)
+
+**CI**
+
+- move to GitHub Actions runners
+
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.8.0...v4.8.1
+
+## [4.8.0] - 2025-07-15
+
+**Features**
+
+- feat(stream): Update stream framework with new alternate keyToList function (#2211)
+
+**Fixed**
+
+- fix: crash loop on missing manifest tables (#2198)
+
+**Chores**
+
+- chore(deps): Update module golang.org/x/sys to v0.34.0 (#2210)
+- chore(deps): Update go minor and patch (#2208)
+- chore(deps): Update go minor and patch (#2204)
+- chore(deps): Update go minor and patch (#2202)
+- chore(deps): Update go minor and patch (#2200)
+- chore(deps): Update module golang.org/x/sys to v0.33.0 (#2195)
+- chore(deps): Update go minor and patch (#2189)
+- Compile with jemalloc v5.3.0 (#2191)
+
+**CI**
+
+- Update trunk.yml
+- move Trunk to action
+
+**Docs**
+
+- docs: add new badge (#2194)
+
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.7.0...v4.8.0
+
+## [4.7.0] - 2025-04-08
+
+**Chores**
+
+- chore(deps): remove dependency on github.com/pkg/errors (#2184)
+- chore(deps): Update go minor and patch (#2187)
+- chore(deps): Update go minor and patch (#2181)
+- chore(deps): Update module golang.org/x/sys to v0.31.0 (#2179)
+
+**Fixed**
+
+- fix broken badge (#2186)
+
+**Docs**
+
+- Update README.md
+- doc: add Blink Labs projects to the using Badger list (#2183)
+- doc: add FlowG to "Projects Using Badger" section of the README (#2180)
+
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.6.0...v4.7.0
+
+## [4.6.0] - 2025-02-26
+
+**Chores**
 
-- chore(deps): Remove dependency on github.com/pkg/errors (#2184)
 - chore(deps): Migrate from OpenCensus to OpenTelemetry (#2169)
+- chore(deps): Update go minor and patch (#2177)
+- chore(deps): Update module github.com/spf13/cobra to v1.9.0 (#2174)
+- chore: add editor config
+- update .gitignore (#2176)
+
+**Fixed**
+
+- fix: remove accidentally uploaded binary `badger-darwin-arm64` (#2175)
+
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.5.2...v4.6.0
+
+## [4.5.2] - 2025-02-14
+
+**Chores**
+
+- chore(deps): Update go minor and patch (#2168)
+- chore(deps): bump minimum Go support to 1.22 (#2171)
+- chore: migrate docs to centralized docs repo (#2166)
+- chore: align repo conventions (#2158)
+- chore(deps): bump the patch group with 2 updates (#2156)
+- chore(deps): bump github.com/google/flatbuffers from 24.12.23+incompatible to 25.1.21+incompatible
+  (#2153)
+- chore(deps): bump golangci/golangci-lint-action from 6.1.1 to 6.2.0 in the actions group (#2154)
+- Update renovate.json
+- Update trunk.yaml
+- enable Trivy
+
+**Fixed**
+
+- update docs link in error message (#2170)
+- Revert "Update badgerpb4.pb.go" (#2172)
+
+**Docs**
+
+- Update README.md
+- Added my project that uses Badger database (#2157)
+- Create SECURITY.md
+
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.5.1...v4.5.2
 
 ## [4.5.1] - 2025-01-21
 
@@ -26,48 +172,46 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - docs: Add pagination explanation to docs (#2134)
 - Fix build for GOARCH=wasm with GOOS=js or GOOS=wasip1 (#2048)
 
-**Full Changelog**: https://github.com/hypermodeinc/badger/compare/v4.5.0...v4.5.1
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.5.0...v4.5.1
 
 ## [4.5.0] - 2024-11-29
 
-- fix the cd pipeline by @mangalaman93 in https://github.com/hypermodeinc/badger/pull/2127
+- fix the cd pipeline by @mangalaman93 in https://github.com/dgraph-io/badger/pull/2127
 - chore(deps): bump the minor group with 2 updates by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2128
+  https://github.com/dgraph-io/badger/pull/2128
 - chore(deps): bump github.com/stretchr/testify from 1.9.0 to 1.10.0 in the minor group by
-  @dependabot in https://github.com/hypermodeinc/badger/pull/2130
-- upgrade protobuf library by @shivaji-kharse in https://github.com/hypermodeinc/badger/pull/2131
+  @dependabot in https://github.com/dgraph-io/badger/pull/2130
+- upgrade protobuf library by @shivaji-kharse in https://github.com/dgraph-io/badger/pull/2131
 
-**Full Changelog**: https://github.com/hypermodeinc/badger/compare/v4.4.0...v4.5.0
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.4.0...v4.5.0
 
 ## [4.4.0] - 2024-10-26
 
 - retract v4.3.0 due to #2121 and #2113, upgrade to Go v1.23, use ristretto v2 in
-  https://github.com/hypermodeinc/badger/pull/2122
-- Allow stream custom maxsize per batch in https://github.com/hypermodeinc/badger/pull/2063
+  https://github.com/dgraph-io/badger/pull/2122
+- Allow stream custom maxsize per batch in https://github.com/dgraph-io/badger/pull/2063
 - chore(deps): bump github.com/klauspost/compress from 1.17.10 to 1.17.11 in the patch group in
-  https://github.com/hypermodeinc/badger/pull/2120
-- fix: sentinel errors should not have stack traces in
-  https://github.com/hypermodeinc/badger/pull/2042
-- chore(deps): bump the minor group with 2 updates in
-  https://github.com/hypermodeinc/badger/pull/2119
+  https://github.com/dgraph-io/badger/pull/2120
+- fix: sentinel errors should not have stack traces in https://github.com/dgraph-io/badger/pull/2042
+- chore(deps): bump the minor group with 2 updates in https://github.com/dgraph-io/badger/pull/2119
 
-**Full Changelog**: https://github.com/hypermodeinc/badger/compare/v4.3.1...v4.4.0
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.3.1...v4.4.0
 
 ## [4.3.1] - 2024-10-06
 
-- chore: update docs links by @ryanfoxtyler in https://github.com/hypermodeinc/badger/pull/2097
+- chore: update docs links by @ryanfoxtyler in https://github.com/dgraph-io/badger/pull/2097
 - chore(deps): bump golang.org/x/sys from 0.24.0 to 0.25.0 in the minor group by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2100
+  https://github.com/dgraph-io/badger/pull/2100
 - chore(deps): bump golang.org/x/net from 0.28.0 to 0.29.0 in the minor group by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2106
+  https://github.com/dgraph-io/badger/pull/2106
 - fix: fix reverse iterator broken by seek by @harshil-goel in
-  https://github.com/hypermodeinc/badger/pull/2109
+  https://github.com/dgraph-io/badger/pull/2109
 - chore(deps): bump github.com/klauspost/compress from 1.17.9 to 1.17.10 in the patch group by
-  @dependabot in https://github.com/hypermodeinc/badger/pull/2114
-- chore(deps): bump github.com/hypermodeinc/ristretto from 0.1.2-0.20240116140435-c67e07994f91 to
-  1.0.0 by @dependabot in https://github.com/hypermodeinc/badger/pull/2112
+  @dependabot in https://github.com/dgraph-io/badger/pull/2114
+- chore(deps): bump github.com/dgraph-io/ristretto from 0.1.2-0.20240116140435-c67e07994f91 to 1.0.0
+  by @dependabot in https://github.com/dgraph-io/badger/pull/2112
 
-**Full Changelog**: https://github.com/hypermodeinc/badger/compare/v4.3.0...v4.3.1
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.3.0...v4.3.1
 
 ## [4.3.0] - 2024-08-29
 
@@ -77,75 +221,75 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 **Fixes**
 
 - chore(changelog): add a missed entry in CHANGELOG for v4.2.0 by @mangalaman93 in
-  https://github.com/hypermodeinc/badger/pull/1988
+  https://github.com/dgraph-io/badger/pull/1988
 - update README with project KVS using badger by @tauraamui in
-  https://github.com/hypermodeinc/badger/pull/1989
+  https://github.com/dgraph-io/badger/pull/1989
 - fix edge case for watermark when index is zero by @mangalaman93 in
-  https://github.com/hypermodeinc/badger/pull/1999
+  https://github.com/dgraph-io/badger/pull/1999
 - upgrade spf13/cobra to version v1.7.0 by @mangalaman93 in
-  https://github.com/hypermodeinc/badger/pull/2001
-- chore: update readme by @joshua-goldstein in https://github.com/hypermodeinc/badger/pull/2011
+  https://github.com/dgraph-io/badger/pull/2001
+- chore: update readme by @joshua-goldstein in https://github.com/dgraph-io/badger/pull/2011
 - perf: upgrade compress package test and benchmark. by @siddhant2001 in
-  https://github.com/hypermodeinc/badger/pull/2009
+  https://github.com/dgraph-io/badger/pull/2009
 - fix(Transactions): Fix resource consumption on empty write transaction by @Zach-Johnson in
-  https://github.com/hypermodeinc/badger/pull/2018
+  https://github.com/dgraph-io/badger/pull/2018
 - chore(deps): bump golang.org/x/net from 0.7.0 to 0.17.0 by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2017
+  https://github.com/dgraph-io/badger/pull/2017
 - perf(compactor): optimize allocations: use buffer for priorities by @deff7 in
-  https://github.com/hypermodeinc/badger/pull/2006
+  https://github.com/dgraph-io/badger/pull/2006
 - fix(Transaction): discard empty transactions on CommitWith by @Wondertan in
-  https://github.com/hypermodeinc/badger/pull/2031
+  https://github.com/dgraph-io/badger/pull/2031
 - fix(levelHandler): use lock for levelHandler sort tables instead of rlock by @xgzlucario in
-  https://github.com/hypermodeinc/badger/pull/2034
+  https://github.com/dgraph-io/badger/pull/2034
 - Docs: update README with project LLS using badger by @Boc-chi-no in
-  https://github.com/hypermodeinc/badger/pull/2032
+  https://github.com/dgraph-io/badger/pull/2032
 - chore: MaxTableSize has been renamed to BaseTableSize by @mitar in
-  https://github.com/hypermodeinc/badger/pull/2038
-- Update CODEOWNERS by @ryanfoxtyler in https://github.com/hypermodeinc/badger/pull/2043
-- Chore(): add Stale Action by @ryanfoxtyler in https://github.com/hypermodeinc/badger/pull/2070
+  https://github.com/dgraph-io/badger/pull/2038
+- Update CODEOWNERS by @ryanfoxtyler in https://github.com/dgraph-io/badger/pull/2043
+- Chore(): add Stale Action by @ryanfoxtyler in https://github.com/dgraph-io/badger/pull/2070
 - Update ristretto and refactor for use of generics by @paralin in
-  https://github.com/hypermodeinc/badger/pull/2047
-- chore: Remove obsolete comment by @mitar in https://github.com/hypermodeinc/badger/pull/2039
+  https://github.com/dgraph-io/badger/pull/2047
+- chore: Remove obsolete comment by @mitar in https://github.com/dgraph-io/badger/pull/2039
 - chore(Docs): Update jQuery 3.2.1 to 3.7.1 by @kokizzu in
-  https://github.com/hypermodeinc/badger/pull/2023
+  https://github.com/dgraph-io/badger/pull/2023
 - chore(deps): bump the go_modules group with 3 updates by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2074
-- docs(): update docs path by @ryanfoxtyler in https://github.com/hypermodeinc/badger/pull/2076
-- perf: fix operation in seek by @harshil-goel in https://github.com/hypermodeinc/badger/pull/2077
-- Add lakeFS to README.md by @N-o-Z in https://github.com/hypermodeinc/badger/pull/2078
-- chore(): add Dependabot by @ryanfoxtyler in https://github.com/hypermodeinc/badger/pull/2080
+  https://github.com/dgraph-io/badger/pull/2074
+- docs(): update docs path by @ryanfoxtyler in https://github.com/dgraph-io/badger/pull/2076
+- perf: fix operation in seek by @harshil-goel in https://github.com/dgraph-io/badger/pull/2077
+- Add lakeFS to README.md by @N-o-Z in https://github.com/dgraph-io/badger/pull/2078
+- chore(): add Dependabot by @ryanfoxtyler in https://github.com/dgraph-io/badger/pull/2080
 - chore(deps): bump golangci/golangci-lint-action from 4 to 6 by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2083
+  https://github.com/dgraph-io/badger/pull/2083
 - chore(deps): bump actions/upload-artifact from 3 to 4 by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2081
+  https://github.com/dgraph-io/badger/pull/2081
 - chore(deps): bump github/codeql-action from 2 to 3 by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2082
+  https://github.com/dgraph-io/badger/pull/2082
 - chore(deps): bump the minor group with 7 updates by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2089
-- Action Manager by @madhu72 in https://github.com/hypermodeinc/badger/pull/2050
+  https://github.com/dgraph-io/badger/pull/2089
+- Action Manager by @madhu72 in https://github.com/dgraph-io/badger/pull/2050
 - chore(deps): bump golang.org/x/sys from 0.23.0 to 0.24.0 in the minor group by @dependabot in
-  https://github.com/hypermodeinc/badger/pull/2091
+  https://github.com/dgraph-io/badger/pull/2091
 - chore(deps): bump github.com/golang/protobuf from 1.5.3 to 1.5.4 in the patch group by @dependabot
-  in https://github.com/hypermodeinc/badger/pull/2090
-- chore: fix some comments by @dufucun in https://github.com/hypermodeinc/badger/pull/2092
+  in https://github.com/dgraph-io/badger/pull/2090
+- chore: fix some comments by @dufucun in https://github.com/dgraph-io/badger/pull/2092
 - chore(deps): bump github.com/google/flatbuffers from 1.12.1 to 24.3.25+incompatible by @dependabot
-  in https://github.com/hypermodeinc/badger/pull/2084
+  in https://github.com/dgraph-io/badger/pull/2084
 
 **CI**
 
 - ci: change cron frequency to fix ghost jobs by @joshua-goldstein in
-  https://github.com/hypermodeinc/badger/pull/2010
+  https://github.com/dgraph-io/badger/pull/2010
 - fix(CI): Update to pull_request trigger by @ryanfoxtyler in
-  https://github.com/hypermodeinc/badger/pull/2056
-- ci/cd optimization by @ryanfoxtyler in https://github.com/hypermodeinc/badger/pull/2051
-- fix(cd): fixed cd pipeline by @harshil-goel in https://github.com/hypermodeinc/badger/pull/2093
-- fix(cd): change name by @harshil-goel in https://github.com/hypermodeinc/badger/pull/2094
+  https://github.com/dgraph-io/badger/pull/2056
+- ci/cd optimization by @ryanfoxtyler in https://github.com/dgraph-io/badger/pull/2051
+- fix(cd): fixed cd pipeline by @harshil-goel in https://github.com/dgraph-io/badger/pull/2093
+- fix(cd): change name by @harshil-goel in https://github.com/dgraph-io/badger/pull/2094
 - fix(cd): added more debug things to cd by @harshil-goel in
-  https://github.com/hypermodeinc/badger/pull/2095
+  https://github.com/dgraph-io/badger/pull/2095
 - fix(cd): removing some debug items by @harshil-goel in
-  https://github.com/hypermodeinc/badger/pull/2096
+  https://github.com/dgraph-io/badger/pull/2096
 
-**Full Changelog**: https://github.com/hypermodeinc/badger/compare/v4.2.0...v4.3.0
+**Full Changelog**: https://github.com/dgraph-io/badger/compare/v4.2.0...v4.3.0
 
 ## [4.2.0] - 2023-08-03
 
@@ -182,7 +326,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 
 This release adds support for incremental stream writer. We also do some cleanup in the docs and
 resolve some CI issues for community PR's. We resolve high and medium CVE's and fix
-[#1833](https://github.com/hypermodeinc/badger/issues/1833).
+[#1833](https://github.com/dgraph-io/badger/issues/1833).
 
 **Features**
 
@@ -191,7 +335,7 @@ resolve some CI issues for community PR's. We resolve high and medium CVE's and
 **Fixes**
 
 - chore: upgrade xxhash from v1.1.0 to v2.1.2 (#1910) (fixes
-  [#1833](https://github.com/hypermodeinc/badger/issues/1833))
+  [#1833](https://github.com/dgraph-io/badger/issues/1833))
 
 **Security**
 
@@ -199,13 +343,13 @@ resolve some CI issues for community PR's. We resolve high and medium CVE's and
 
 **CVEs**
 
-- [CVE-2021-31525](https://github.com/hypermodeinc/badger/security/dependabot/7)
-- [CVE-2022-41723](https://github.com/hypermodeinc/badger/security/dependabot/4)
-- [CVE-2022-27664](https://github.com/hypermodeinc/badger/security/dependabot/5)
-- [CVE-2021-33194](https://github.com/hypermodeinc/badger/security/dependabot/9)
-- [CVE-2022-41723](https://github.com/hypermodeinc/badger/security/dependabot/13)
-- [CVE-2021-33194](https://github.com/hypermodeinc/badger/security/dependabot/16)
-- [CVE-2021-38561](https://github.com/hypermodeinc/badger/security/dependabot/8)
+- [CVE-2021-31525](https://github.com/dgraph-io/badger/security/dependabot/7)
+- [CVE-2022-41723](https://github.com/dgraph-io/badger/security/dependabot/4)
+- [CVE-2022-27664](https://github.com/dgraph-io/badger/security/dependabot/5)
+- [CVE-2021-33194](https://github.com/dgraph-io/badger/security/dependabot/9)
+- [CVE-2022-41723](https://github.com/dgraph-io/badger/security/dependabot/13)
+- [CVE-2021-33194](https://github.com/dgraph-io/badger/security/dependabot/16)
+- [CVE-2021-38561](https://github.com/dgraph-io/badger/security/dependabot/8)
 
 **Chores**
 
@@ -674,7 +818,6 @@ This sections lists the changes which were reverted because of non-reproducible
 **New APIs**
 
 - badger.Options
-
   - WithInMemory (f5b6321)
   - WithZSTDCompressionLevel (3eb4e72)
 
@@ -706,7 +849,6 @@ This sections lists the changes which were reverted because of non-reproducible
 **New APIs**
 
 - badger.DB
-
   - NewWriteBatchAt (7f43769)
   - CacheMetrics (b9056f1)
 
@@ -784,7 +926,6 @@ _Note_: The hashes in parentheses correspond to the commits that impacted the gi
 **New APIs**
 
 - badger.DB
-
   - DropPrefix (291295e)
   - Flatten (7e41bba)
   - KeySplits (4751ef1)
@@ -795,30 +936,25 @@ _Note_: The hashes in parentheses correspond to the commits that impacted the gi
   - Sync (851e462)
 
 - badger.DefaultOptions() and badger.LSMOnlyOptions() (91ce687)
-
   - badger.Options.WithX methods
 
 - badger.Entry (e9447c9)
-
   - NewEntry
   - WithMeta
   - WithDiscard
   - WithTTL
 
 - badger.Item
-
   - KeySize (fd59907)
   - ValueSize (5242a99)
 
 - badger.IteratorOptions
-
   - PickTable (7d46029, 49a49e3)
   - Prefix (7d46029)
 
 - badger.Logger (fbb2778)
 
 - badger.Options
-
   - CompactL0OnClose (7e41bba)
   - Logger (3f66663)
   - LogRotatesToFlush (2237832)
@@ -890,7 +1026,7 @@ Bug Fixes:
 
 - Fix for infinite yieldItemValue recursion. #503
 - Fix recursive addition of `badgerMove` prefix.
-  https://github.com/hypermodeinc/badger/commit/2e3a32f0ccac3066fb4206b28deb39c210c5266f
+  https://github.com/dgraph-io/badger/commit/2e3a32f0ccac3066fb4206b28deb39c210c5266f
 - Use file size based window size for sampling, instead of fixing it to 10MB. #501
 
 Cleanup:
@@ -957,23 +1093,46 @@ Bug fix:
 
 - Fix an uint16 overflow when resizing key slice
 
-[Unreleased]: https://github.com/hypermodeinc/badger/compare/v2.2007.2...HEAD
-[2.2007.2]: https://github.com/hypermodeinc/badger/compare/v2.2007.1...v2.2007.2
-[2.2007.1]: https://github.com/hypermodeinc/badger/compare/v2.2007.0...v2.2007.1
-[2.2007.0]: https://github.com/hypermodeinc/badger/compare/v2.0.3...v2.2007.0
-[2.0.3]: https://github.com/hypermodeinc/badger/compare/v2.0.2...v2.0.3
-[2.0.2]: https://github.com/hypermodeinc/badger/compare/v2.0.1...v2.0.2
-[2.0.1]: https://github.com/hypermodeinc/badger/compare/v2.0.0...v2.0.1
-[2.0.0]: https://github.com/hypermodeinc/badger/compare/v1.6.0...v2.0.0
-[1.6.0]: https://github.com/hypermodeinc/badger/compare/v1.5.5...v1.6.0
-[1.5.5]: https://github.com/hypermodeinc/badger/compare/v1.5.3...v1.5.5
-[1.5.3]: https://github.com/hypermodeinc/badger/compare/v1.5.2...v1.5.3
-[1.5.2]: https://github.com/hypermodeinc/badger/compare/v1.5.1...v1.5.2
-[1.5.1]: https://github.com/hypermodeinc/badger/compare/v1.5.0...v1.5.1
-[1.5.0]: https://github.com/hypermodeinc/badger/compare/v1.4.0...v1.5.0
-[1.4.0]: https://github.com/hypermodeinc/badger/compare/v1.3.0...v1.4.0
-[1.3.0]: https://github.com/hypermodeinc/badger/compare/v1.2.0...v1.3.0
-[1.2.0]: https://github.com/hypermodeinc/badger/compare/v1.1.1...v1.2.0
-[1.1.1]: https://github.com/hypermodeinc/badger/compare/v1.1.0...v1.1.1
-[1.1.0]: https://github.com/hypermodeinc/badger/compare/v1.0.1...v1.1.0
-[1.0.1]: https://github.com/hypermodeinc/badger/compare/v1.0.0...v1.0.1
+[4.9.0]: https://github.com/dgraph-io/badger/compare/v4.8.0...v4.9.0
+[4.8.0]: https://github.com/dgraph-io/badger/compare/v4.7.0...v4.8.0
+[4.7.0]: https://github.com/dgraph-io/badger/compare/v4.6.0...v4.7.0
+[4.6.0]: https://github.com/dgraph-io/badger/compare/v4.5.2...v4.6.0
+[4.5.2]: https://github.com/dgraph-io/badger/compare/v4.5.1...v4.5.2
+[4.5.1]: https://github.com/dgraph-io/badger/compare/v4.5.0...v4.5.1
+[4.5.0]: https://github.com/dgraph-io/badger/compare/v4.4.0...v4.5.0
+[4.4.0]: https://github.com/dgraph-io/badger/compare/v4.3.1...v4.4.0
+[4.3.1]: https://github.com/dgraph-io/badger/compare/v4.3.0...v4.3.1
+[4.3.0]: https://github.com/dgraph-io/badger/compare/v4.2.0...v4.3.0
+[4.2.0]: https://github.com/dgraph-io/badger/compare/v4.1.0...v4.2.0
+[4.1.0]: https://github.com/dgraph-io/badger/compare/v4.0.1...v4.1.0
+[4.0.1]: https://github.com/dgraph-io/badger/compare/v4.0.0...v4.0.1
+[4.0.0]: https://github.com/dgraph-io/badger/compare/v3.2103.5...v4.0.0
+[3.2103.5]: https://github.com/dgraph-io/badger/compare/v3.2103.4...v3.2103.5
+[3.2103.4]: https://github.com/dgraph-io/badger/compare/v3.2103.3...v3.2103.4
+[3.2103.3]: https://github.com/dgraph-io/badger/compare/v3.2103.2...v3.2103.3
+[3.2103.2]: https://github.com/dgraph-io/badger/compare/v3.2103.1...v3.2103.2
+[3.2103.1]: https://github.com/dgraph-io/badger/compare/v3.2103.0...v3.2103.1
+[3.2103.0]: https://github.com/dgraph-io/badger/compare/v3.2011.1...v3.2103.0
+[3.2011.1]: https://github.com/dgraph-io/badger/compare/v3.2011.0...v3.2011.1
+[3.2011.0]: https://github.com/dgraph-io/badger/compare/v2.2007.4...v3.2011.0
+[2.2007.4]: https://github.com/dgraph-io/badger/compare/v2.2007.3...v2.2007.4
+[2.2007.3]: https://github.com/dgraph-io/badger/compare/v2.2007.2...v2.2007.3
+[2.2007.2]: https://github.com/dgraph-io/badger/compare/v2.2007.1...v2.2007.2
+[2.2007.1]: https://github.com/dgraph-io/badger/compare/v2.2007.0...v2.2007.1
+[2.2007.0]: https://github.com/dgraph-io/badger/compare/v2.0.3...v2.2007.0
+[2.0.3]: https://github.com/dgraph-io/badger/compare/v2.0.2...v2.0.3
+[2.0.2]: https://github.com/dgraph-io/badger/compare/v2.0.1...v2.0.2
+[2.0.1]: https://github.com/dgraph-io/badger/compare/v2.0.0...v2.0.1
+[2.0.0]: https://github.com/dgraph-io/badger/compare/v1.6.0...v2.0.0
+[1.6.0]: https://github.com/dgraph-io/badger/compare/v1.5.5...v1.6.0
+[1.5.5]: https://github.com/dgraph-io/badger/compare/v1.5.3...v1.5.5
+[1.5.3]: https://github.com/dgraph-io/badger/compare/v1.5.2...v1.5.3
+[1.5.2]: https://github.com/dgraph-io/badger/compare/v1.5.1...v1.5.2
+[1.5.1]: https://github.com/dgraph-io/badger/compare/v1.5.0...v1.5.1
+[1.5.0]: https://github.com/dgraph-io/badger/compare/v1.4.0...v1.5.0
+[1.4.0]: https://github.com/dgraph-io/badger/compare/v1.3.0...v1.4.0
+[1.3.0]: https://github.com/dgraph-io/badger/compare/v1.2.0...v1.3.0
+[1.2.0]: https://github.com/dgraph-io/badger/compare/v1.1.1...v1.2.0
+[1.1.1]: https://github.com/dgraph-io/badger/compare/v1.1.0...v1.1.1
+[1.1.0]: https://github.com/dgraph-io/badger/compare/v1.0.1...v1.1.0
+[1.0.1]: https://github.com/dgraph-io/badger/compare/v1.0.0...v1.0.1

+ 2 - 2
vendor/github.com/dgraph-io/badger/v4/CODE_OF_CONDUCT.md

@@ -51,8 +51,8 @@ an appointed representative at an online or offline event.
 ## Enforcement
 
 Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community
-leaders responsible for enforcement at hello@hypermode.com. All complaints will be reviewed and
-investigated promptly and fairly.
+leaders responsible for enforcement at dgraph-admin@istaridigital.com. All complaints will be
+reviewed and investigated promptly and fairly.
 
 All community leaders are obligated to respect the privacy and security of the reporter of any
 incident.

+ 9 - 7
vendor/github.com/dgraph-io/badger/v4/CONTRIBUTING.md

@@ -25,18 +25,20 @@ Please make sure to read and observe our [Code of Conduct](./CODE_OF_CONDUCT.md)
 ### Find a good first topic
 
 You can start by finding an existing issue with the
-[good first issue](https://github.com/hypermodeinc/badger/labels/good%20first%20issue) or
-[help wanted](https://github.com/hypermodeinc/badger/labels/help%20wanted) labels. These issues are
+[good first issue](https://github.com/dgraph-io/badger/labels/good%20first%20issue) or
+[help wanted](https://github.com/dgraph-io/badger/labels/help%20wanted) labels. These issues are
 well suited for new contributors.
 
 ## Setting up your development environment
 
-Badger uses [`Go Modules`](https://github.com/golang/go/wiki/Modules) to manage dependencies. The
-version of Go should be **1.12** or above.
+- [Install Go 1.25.0 or above](https://golang.org/doc/install).
+- Install
+  [trunk](https://docs.trunk.io/code-quality/overview/getting-started/install#install-the-launcher).
+  Our CI uses trunk to lint and check code, having it installed locally will save you time.
 
 ### Fork the project
 
-- Visit https://github.com/hypermodeinc/badger
+- Visit https://github.com/dgraph-io/badger
 - Click the `Fork` button (top right) to create a fork of the repository
 
 ### Clone the project
@@ -44,7 +46,7 @@ version of Go should be **1.12** or above.
 ```sh
 git clone https://github.com/$GITHUB_USER/badger
 cd badger
-git remote add upstream git@github.com:hypermodeinc/badger.git
+git remote add upstream git@github.com:dgraph-io/badger.git
 
 # Never push to the upstream master
 git remote set-url --push upstream no_push
@@ -98,7 +100,7 @@ description.
 ### Sign the CLA
 
 Click the **Sign in with Github to agree** button to sign the CLA.
-[An example](https://cla-assistant.io/hypermodeinc/badger?pullRequest=1377).
+[An example](https://cla-assistant.io/dgraph-io/badger?pullRequest=1377).
 
 ### Get a code review
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/Makefile

@@ -1,5 +1,5 @@
 #
-# SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+# SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
 # SPDX-License-Identifier: Apache-2.0
 #
 

+ 35 - 16
vendor/github.com/dgraph-io/badger/v4/README.md

@@ -2,16 +2,16 @@
 
 [![Go Reference](https://pkg.go.dev/badge/github.com/dgraph-io/badger/v4.svg)](https://pkg.go.dev/github.com/dgraph-io/badger/v4)
 [![Go Report Card](https://goreportcard.com/badge/github.com/dgraph-io/badger/v4)](https://goreportcard.com/report/github.com/dgraph-io/badger/v4)
-[![Sourcegraph](https://sourcegraph.com/github.com/hypermodeinc/badger/-/badge.svg)](https://sourcegraph.com/github.com/hypermodeinc/badger?badge)
-[![ci-badger-tests](https://github.com/hypermodeinc/badger/actions/workflows/ci-badger-tests.yml/badge.svg)](https://github.com/hypermodeinc/badger/actions/workflows/ci-badger-tests.yml)
-[![ci-badger-bank-tests](https://github.com/hypermodeinc/badger/actions/workflows/ci-badger-bank-tests.yml/badge.svg)](https://github.com/hypermodeinc/badger/actions/workflows/ci-badger-bank-tests.yml)
-[![ci-badger-bank-tests-nightly](https://github.com/hypermodeinc/badger/actions/workflows/ci-badger-bank-tests-nightly.yml/badge.svg)](https://github.com/hypermodeinc/badger/actions/workflows/ci-badger-bank-tests-nightly.yml)
+[![Sourcegraph](https://sourcegraph.com/github.com/dgraph-io/badger/-/badge.svg)](https://sourcegraph.com/github.com/dgraph-io/badger?badge)
+[![ci-badger-tests](https://github.com/dgraph-io/badger/actions/workflows/ci-badger-tests.yml/badge.svg)](https://github.com/dgraph-io/badger/actions/workflows/ci-badger-tests.yml)
+[![ci-badger-bank-tests](https://github.com/dgraph-io/badger/actions/workflows/ci-badger-bank-tests.yml/badge.svg)](https://github.com/dgraph-io/badger/actions/workflows/ci-badger-bank-tests.yml)
+[![ci-badger-bank-tests-nightly](https://github.com/dgraph-io/badger/actions/workflows/ci-badger-bank-tests-nightly.yml/badge.svg)](https://github.com/dgraph-io/badger/actions/workflows/ci-badger-bank-tests-nightly.yml)
 
 ![Badger mascot](images/diggy-shadow.png)
 
 BadgerDB is an embeddable, persistent and fast key-value (KV) database written in pure Go. It is the
-underlying database for [Dgraph](https://github.com/hypermodeinc/dgraph), a fast, distributed graph database. It's meant
-to be a performant alternative to non-Go-based key-value stores like RocksDB.
+underlying database for [Dgraph](https://github.com/dgraph-io/dgraph), a fast, distributed graph
+database. It's meant to be a performant alternative to non-Go-based key-value stores like RocksDB.
 
 ## Project Status
 
@@ -26,7 +26,10 @@ The list of projects using Badger can be found [here](#projects-using-badger).
 
 Please consult the [Changelog] for more detailed information on releases.
 
-[Changelog]: https://github.com/hypermodeinc/badger/blob/main/CHANGELOG.md
+Note: Badger is built with go 1.23 and we refrain from bumping this version to minimize downstream
+effects of those using Badger in applications built with older versions of Go.
+
+[Changelog]: https://github.com/dgraph-io/badger/blob/main/CHANGELOG.md
 
 ## Table of Contents
 
@@ -51,7 +54,7 @@ Please consult the [Changelog] for more detailed information on releases.
 
 ### Installing
 
-To start using Badger, install Go 1.21 or above. Badger v3 and above needs go modules. From your
+To start using Badger, install Go 1.23 or above. Badger v3 and above needs go modules. From your
 project, run the following command
 
 ```sh
@@ -74,7 +77,7 @@ This will install the badger command line utility into your $GOBIN path.
 
 ## Badger Documentation
 
-Badger Documentation is available at https://docs.hypermode.com/badger
+Badger Documentation is available at [https://badger.dgraph.io](https://badger.dgraph.io)
 
 ## Resources
 
@@ -138,7 +141,7 @@ including graphs can be found the blog posts (linked above).
 
 Below is a list of known projects that use Badger:
 
-- [Dgraph](https://github.com/hypermodeinc/dgraph) - Distributed graph database.
+- [Dgraph](https://github.com/dgraph-io/dgraph) - Distributed graph database.
 - [Jaeger](https://github.com/jaegertracing/jaeger) - Distributed tracing platform.
 - [go-ipfs](https://github.com/ipfs/go-ipfs) - Go client for the InterPlanetary File System (IPFS),
   a new hypermedia distribution protocol.
@@ -244,20 +247,36 @@ Below is a list of known projects that use Badger:
 - [MightyMap](https://github.com/thisisdevelopment/mightymap) - Mightymap: Conveys both robustness
   and high capability, fitting for a powerful concurrent map.
 - [FlowG](https://github.com/link-society/flowg) - A low-code log processing facility
-- [Bluefin](https://github.com/blinklabs-io/bluefin) - Bluefin is a TUNA Proof of Work miner for
-  the Fortuna smart contract on the Cardano blockchain
+- [Bluefin](https://github.com/blinklabs-io/bluefin) - Bluefin is a TUNA Proof of Work miner for the
+  Fortuna smart contract on the Cardano blockchain
 - [cDNSd](https://github.com/blinklabs-io/cdnsd) - A Cardano blockchain backed DNS server daemon
 - [Dingo](https://github.com/blinklabs-io/dingo) - A Cardano blockchain data node
 
 If you are using Badger in a project please send a pull request to add it to the list.
 
+### Platform Compatibility
+
+Badger uses OS-specific implementations for directory locking and `fsync` operations. On
+**POSIX-compliant systems** (Linux, macOS, BSD), these work as expected.
+
+For **non-POSIX platforms**, be aware of potential limitations:
+
+| Platform | File             | Notes                                                                |
+| -------- | ---------------- | -------------------------------------------------------------------- |
+| AIX      | `dir_aix.go`     | Directory `fsync` not supported; durability on crash may be affected |
+| Windows  | `dir_windows.go` | Uses different locking mechanism                                     |
+| Plan9    | `dir_plan9.go`   | No file locking support                                              |
+| WASM/JS  | `dir_other.go`   | No file locking support                                              |
+
+If you encounter issues on these platforms, review the corresponding `dir_*.go` source file for
+implementation details.
+
 ## Contributing
 
 If you're interested in contributing to Badger see [CONTRIBUTING](./CONTRIBUTING.md).
 
 ## Contact
 
-- Please use [Github issues](https://github.com/hypermodeinc/badger/issues) for filing bugs.
-- Please use [discuss.hypermode.com](https://discuss.hypermode.com) for questions, discussions, and feature
-  requests.
-- Follow us on Twitter [@hypermodeinc](https://twitter.com/hypermodeinc).
+- Please use [Github issues](https://github.com/dgraph-io/badger/issues) for filing bugs.
+- Please use [Discussions](https://github.com/orgs/dgraph-io/discussions) for questions,
+  discussions, and feature requests.

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/SECURITY.md

@@ -5,6 +5,6 @@ vulnerability in Badger, we encourage you to let us know right away.
 
 We will investigate all legitimate reports and do our best to quickly fix the problem. Please report
 any issues or vulnerabilities via GitHub Security Advisories instead of posting a public issue in
-GitHub. You can also send security communications to security@hypermode.com.
+GitHub. You can also send security communications to dgraph-admin@istaridigital.com.
 
 Please include the version identifier and details on how the vulnerability can be exploited.

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/backup.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/batch.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/changes.sh

@@ -1,7 +1,7 @@
 #!/bin/bash
 
 set -e
-GHORG=${GHORG:-hypermodeinc}
+GHORG=${GHORG:-dgraph-io}
 GHREPO=${GHREPO:-badger}
 cat <<EOF
 This description was generated using this script:

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/compaction.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 2 - 2
vendor/github.com/dgraph-io/badger/v4/db.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -1700,7 +1700,7 @@ func (db *DB) dropAll() (func(), error) {
 		return f, err
 	}
 	// prepareToDrop will stop all the incoming write and flushes any pending memtables.
-	// Before we drop, we'll stop the compaction because anyways all the datas are going to
+	// Before we drop, we'll stop the compaction because anyways all the data are going to
 	// be deleted.
 	db.stopCompactions()
 	resume := func() {

+ 144 - 0
vendor/github.com/dgraph-io/badger/v4/dir_aix.go

@@ -0,0 +1,144 @@
+//go:build aix
+// +build aix
+
+/*
+ * SPDX-FileCopyrightText: © 2017-2026 Istari Digital, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package badger
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"path/filepath"
+	"sync"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/dgraph-io/badger/v4/y"
+)
+
+// AIX flock locks files, not descriptors. So, multiple descriptors cannot
+// be used in the same file. The first to close removals the lock on the
+// file.
+type directoryLockGuard struct {
+	// The absolute path to our pid file.
+	path string
+	// Was this a shared lock for a read-only database?
+	readOnly bool
+}
+
+// AIX flocking is file x process, not fd x file x process like linux. We can
+// only hold one descriptor with a lock open at any given time.
+type aixFlock struct {
+	file     *os.File
+	count    int
+	readOnly bool
+}
+
+// Keep a map of locks synchronized by a mutex.
+var aixFlockMap = map[string]*aixFlock{}
+var aixFlockMapLock sync.Mutex
+
+// acquireDirectoryLock gets a lock on the directory (using flock). If
+// this is not read-only, it will also write our pid to
+// dirPath/pidFileName for convenience.
+func acquireDirectoryLock(dirPath string, pidFileName string, readOnly bool) (
+	*directoryLockGuard, error) {
+
+	// Convert to absolute path so that Release still works even if we do an unbalanced
+	// chdir in the meantime.
+	absPidFilePath, err := filepath.Abs(filepath.Join(dirPath, pidFileName))
+	if err != nil {
+		return nil, y.Wrapf(err, "cannot get absolute path for pid lock file")
+	}
+
+	aixFlockMapLock.Lock()
+	defer aixFlockMapLock.Unlock()
+
+	lg := &directoryLockGuard{absPidFilePath, readOnly}
+
+	if lock, fnd := aixFlockMap[absPidFilePath]; fnd {
+		if !readOnly || lock.readOnly != readOnly {
+			return nil, fmt.Errorf(
+				"Cannot acquire directory lock on %q.  Another process is using this Badger database.", dirPath)
+		}
+		lock.count++
+	} else {
+		// This is the first acquirer, set up a lock file and register it.
+		f, err := os.OpenFile(absPidFilePath, os.O_RDWR|os.O_CREATE, 0666)
+		if err != nil {
+			return nil, y.Wrapf(err, "cannot create/open pid file %q", absPidFilePath)
+		}
+
+		opts := unix.F_WRLCK
+		if readOnly {
+			opts = unix.F_RDLCK
+		}
+
+		flckt := unix.Flock_t{int16(opts), 0, 0, 0, 0, 0, 0}
+		err = unix.FcntlFlock(uintptr(f.Fd()), unix.F_SETLK, &flckt)
+		if err != nil {
+			f.Close()
+			return nil, y.Wrapf(err,
+				"Cannot acquire directory lock on %q.  Another process is using this Badger database.", dirPath)
+		}
+
+		if !readOnly {
+			f.Truncate(0)
+			// Write our pid to the file.
+			_, err = f.Write([]byte(fmt.Sprintf("%d\n", os.Getpid())))
+			if err != nil {
+				f.Close()
+				return nil, y.Wrapf(err,
+					"Cannot write pid file %q", absPidFilePath)
+			}
+		}
+		aixFlockMap[absPidFilePath] = &aixFlock{f, 1, readOnly}
+	}
+	return lg, nil
+}
+
+// Release deletes the pid file and releases our lock on the directory.
+func (guard *directoryLockGuard) release() error {
+	var err error
+
+	aixFlockMapLock.Lock()
+	defer aixFlockMapLock.Unlock()
+
+	if lock, fnd := aixFlockMap[guard.path]; fnd {
+		lock.count--
+		if lock.count == 0 {
+			if !lock.readOnly {
+				// Try to clear the PID if we succeed.
+				lock.file.Truncate(0)
+				os.Remove(guard.path)
+			}
+
+			if closeErr := lock.file.Close(); err == nil {
+				err = closeErr
+			}
+			delete(aixFlockMap, guard.path)
+			guard.path = ""
+		}
+	} else {
+		err = errors.New(fmt.Sprintf("unknown lock %v", guard.path))
+	}
+
+	return err
+}
+
+// openDir opens a directory for syncing.
+func openDir(path string) (*os.File, error) { return os.Open(path) }
+
+// When you create or delete a file, you have to ensure the directory entry for the file is synced
+// in order to guarantee the file is visible (if the system crashes). (See the man page for fsync,
+// or see https://github.com/coreos/etcd/issues/6368 for an example.)
+func syncDir(dir string) error {
+	var err error
+	// AIX does not support fsync on a directory.
+	// Data durability on crash may be affected.
+	return err
+}

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/dir_other.go

@@ -2,7 +2,7 @@
 // +build js wasip1
 
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/dir_plan9.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 3 - 3
vendor/github.com/dgraph-io/badger/v4/dir_unix.go

@@ -1,8 +1,8 @@
-//go:build !windows && !plan9 && !js && !wasip1
-// +build !windows,!plan9,!js,!wasip1
+//go:build !windows && !plan9 && !js && !wasip1 && !aix
+// +build !windows,!plan9,!js,!wasip1,!aix
 
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 3 - 3
vendor/github.com/dgraph-io/badger/v4/dir_windows.go

@@ -2,7 +2,7 @@
 // +build windows
 
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -74,7 +74,7 @@ func acquireDirectoryLock(dirPath string, pidFileName string, readOnly bool) (*d
 	// FILE_ATTRIBUTE_TEMPORARY is used to tell Windows to try to create the handle in memory.
 	// FILE_FLAG_DELETE_ON_CLOSE is not specified in syscall_windows.go but tells Windows to delete
 	// the file when all processes holding the handler are closed.
-	// XXX: this works but it's a bit klunky. i'd prefer to use LockFileEx but it needs unsafe pkg.
+	// XXX: this works but it's a bit clunky. i'd prefer to use LockFileEx but it needs unsafe pkg.
 	h, err := syscall.CreateFile(
 		syscall.StringToUTF16Ptr(absLockFilePath), 0, 0, nil,
 		syscall.OPEN_ALWAYS,
@@ -96,5 +96,5 @@ func (g *directoryLockGuard) release() error {
 }
 
 // Windows doesn't support syncing directories to the file system. See
-// https://github.com/hypermodeinc/badger/issues/699#issuecomment-504133587 for more details.
+// https://github.com/dgraph-io/badger/issues/699#issuecomment-504133587 for more details.
 func syncDir(dir string) error { return nil }

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/discard.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 2 - 2
vendor/github.com/dgraph-io/badger/v4/errors.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -33,7 +33,7 @@ var (
 	// ErrReadOnlyTxn is returned if an update function is called on a read-only transaction.
 	ErrReadOnlyTxn = stderrors.New("No sets or deletes are allowed in a read-only transaction")
 
-	// ErrDiscardedTxn is returned if a previously discarded transaction is re-used.
+	// ErrDiscardedTxn is returned if a previously discarded transaction is reused.
 	ErrDiscardedTxn = stderrors.New("This transaction has been discarded. Create a new one")
 
 	// ErrEmptyKey is returned if an empty key is passed on an update function.

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/fb/flatbuffer.fbs

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/histogram.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 2 - 2
vendor/github.com/dgraph-io/badger/v4/iterator.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -106,7 +106,7 @@ func (item *Item) Value(fn func(val []byte) error) error {
 // returned. Tip: It might make sense to reuse the returned slice as dst argument for the next call.
 //
 // This function is useful in long running iterate/update transactions to avoid a write deadlock.
-// See Github issue: https://github.com/hypermodeinc/badger/issues/315
+// See Github issue: https://github.com/dgraph-io/badger/issues/315
 func (item *Item) ValueCopy(dst []byte) ([]byte, error) {
 	item.wg.Wait()
 	if item.status == prefetched {

+ 3 - 3
vendor/github.com/dgraph-io/badger/v4/key_registry.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -246,7 +246,7 @@ func WriteKeyRegistry(reg *KeyRegistry, opt KeyRegistryOptions) error {
 		var err error
 		eSanity, err = y.XORBlockAllocate(eSanity, opt.EncryptionKey, iv)
 		if err != nil {
-			return y.Wrapf(err, "Error while encrpting sanity text in WriteKeyRegistry")
+			return y.Wrapf(err, "Error while encrypting sanity text in WriteKeyRegistry")
 		}
 	}
 	y.Check2(buf.Write(iv))
@@ -310,7 +310,7 @@ func (kr *KeyRegistry) LatestDataKey() (*pb.DataKey, error) {
 	// validKey return datakey if the last generated key duration less than
 	// rotation duration.
 	validKey := func() (*pb.DataKey, bool) {
-		// Time diffrence from the last generated time.
+		// Time difference from the last generated time.
 		diff := time.Since(time.Unix(kr.lastCreated, 0))
 		if diff < kr.opt.EncryptionKeyRotationDuration {
 			return kr.dataKeys[kr.nextKeyID], true

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/level_handler.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 2 - 2
vendor/github.com/dgraph-io/badger/v4/levels.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -1573,7 +1573,7 @@ func (s *levelsController) addLevel0Table(t *table.Table) error {
 	}
 
 	for !s.levels[0].tryAddLevel0Table(t) {
-		// Before we unstall, we need to make sure that level 0 is healthy.
+		// Before we uninstall, we need to make sure that level 0 is healthy.
 		timeStart := time.Now()
 		for s.levels[0].numTables() >= s.kv.opt.NumLevelZeroTablesStall {
 			time.Sleep(10 * time.Millisecond)

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/logger.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/managed_db.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 5 - 5
vendor/github.com/dgraph-io/badger/v4/manifest.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 
@@ -368,14 +368,14 @@ func ReplayManifestFile(fp *os.File, extMagic uint16, opt Options) (Manifest, in
 		return Manifest{}, 0,
 			//nolint:lll
 			fmt.Errorf("manifest has unsupported version: %d (we support %d).\n"+
-				"Please see https://docs.hypermode.com/badger/troubleshooting#i-see-manifest-has-unsupported-version-x-we-support-y-error"+
-				" on how to fix this.",
+				"Please see https://github.com/dgraph-io/badger/blob/main/docs/troubleshooting.md#i-see-manifest-has-unsupported-version-x-we-support-y-error"+
+				" on how to fix this",
 				version, badgerMagicVersion)
 	}
 	if extVersion != extMagic {
 		return Manifest{}, 0,
-			fmt.Errorf("Cannot open DB because the external magic number doesn't match. "+
-				"Expected: %d, version present in manifest: %d\n", extMagic, extVersion)
+			fmt.Errorf("cannot open DB because the external magic number doesn't match, "+
+				"expected: %d, version present in manifest: %d", extMagic, extVersion)
 	}
 
 	stat, err := fp.Stat()

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/memtable.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/merge.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

+ 1 - 1
vendor/github.com/dgraph-io/badger/v4/options.go

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: © Hypermode Inc. <hello@hypermode.com>
+ * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  * SPDX-License-Identifier: Apache-2.0
  */
 

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.