#4970 fix-4928

Merged
chenshihai merged 20 commits from fix-4928 into V20231211 5 months ago
  1. +9
    -8
      go.mod
  2. +17
    -15
      go.sum
  3. +439
    -0
      models/card_request.go
  4. +2
    -0
      models/models.go
  5. +42
    -0
      modules/structs/card_requests.go
  6. +7
    -0
      options/locale/locale_en-US.ini
  7. +7
    -0
      options/locale/locale_zh-CN.ini
  8. +268
    -0
      routers/card_request/card_request.go
  9. +9
    -4
      routers/home.go
  10. +24
    -3
      routers/routes/routes.go
  11. +146
    -0
      services/card_request/card_request.go
  12. +19
    -6
      templates/base/head_navbar.tmpl
  13. +18
    -4
      templates/base/head_navbar_fluid.tmpl
  14. +18
    -4
      templates/base/head_navbar_home.tmpl
  15. +18
    -4
      templates/base/head_navbar_pro.tmpl
  16. +8
    -0
      templates/computingpower/demand.tmpl
  17. +7
    -0
      templates/computingpower/domestic.tmpl
  18. +0
    -7
      templates/explore/domestic.tmpl
  19. +0
    -1
      vendor/golang.org/x/crypto/acme/version_go112.go
  20. +0
    -1
      vendor/golang.org/x/crypto/argon2/blamka_amd64.go
  21. +0
    -1
      vendor/golang.org/x/crypto/argon2/blamka_amd64.s
  22. +0
    -1
      vendor/golang.org/x/crypto/argon2/blamka_ref.go
  23. +0
    -1
      vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go
  24. +0
    -1
      vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
  25. +0
    -1
      vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go
  26. +0
    -1
      vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s
  27. +0
    -1
      vendor/golang.org/x/crypto/blake2b/blake2b_ref.go
  28. +0
    -1
      vendor/golang.org/x/crypto/blake2b/register.go
  29. +1
    -2
      vendor/golang.org/x/crypto/chacha20/chacha_arm64.go
  30. +1
    -2
      vendor/golang.org/x/crypto/chacha20/chacha_arm64.s
  31. +1
    -2
      vendor/golang.org/x/crypto/chacha20/chacha_noasm.go
  32. +0
    -1
      vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go
  33. +0
    -1
      vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s
  34. +0
    -1
      vendor/golang.org/x/crypto/chacha20/chacha_s390x.go
  35. +0
    -1
      vendor/golang.org/x/crypto/chacha20/chacha_s390x.s
  36. +0
    -1
      vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go
  37. +0
    -1
      vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s
  38. +0
    -1
      vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go
  39. +0
    -1
      vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go
  40. +0
    -1
      vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s
  41. +0
    -1
      vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go
  42. +0
    -71
      vendor/golang.org/x/crypto/ed25519/ed25519.go
  43. +3
    -1
      vendor/golang.org/x/crypto/hkdf/hkdf.go
  44. +0
    -1
      vendor/golang.org/x/crypto/internal/alias/alias.go
  45. +0
    -1
      vendor/golang.org/x/crypto/internal/alias/alias_purego.go
  46. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go
  47. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go
  48. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go
  49. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go
  50. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s
  51. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go
  52. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s
  53. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go
  54. +0
    -1
      vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s
  55. +0
    -1
      vendor/golang.org/x/crypto/sha3/hashes_generic.go
  56. +0
    -1
      vendor/golang.org/x/crypto/sha3/keccakf.go
  57. +0
    -1
      vendor/golang.org/x/crypto/sha3/keccakf_amd64.go
  58. +0
    -1
      vendor/golang.org/x/crypto/sha3/keccakf_amd64.s
  59. +0
    -1
      vendor/golang.org/x/crypto/sha3/register.go
  60. +9
    -5
      vendor/golang.org/x/crypto/sha3/sha3.go
  61. +6
    -5
      vendor/golang.org/x/crypto/sha3/sha3_s390x.go
  62. +0
    -1
      vendor/golang.org/x/crypto/sha3/sha3_s390x.s
  63. +14
    -15
      vendor/golang.org/x/crypto/sha3/shake.go
  64. +0
    -1
      vendor/golang.org/x/crypto/sha3/shake_generic.go
  65. +0
    -1
      vendor/golang.org/x/crypto/sha3/xor.go
  66. +0
    -2
      vendor/golang.org/x/crypto/sha3/xor_unaligned.go
  67. +10
    -5
      vendor/golang.org/x/crypto/ssh/agent/client.go
  68. +2
    -2
      vendor/golang.org/x/crypto/ssh/agent/server.go
  69. +30
    -8
      vendor/golang.org/x/crypto/ssh/certs.go
  70. +85
    -31
      vendor/golang.org/x/crypto/ssh/client_auth.go
  71. +8
    -3
      vendor/golang.org/x/crypto/ssh/common.go
  72. +1
    -0
      vendor/golang.org/x/crypto/ssh/doc.go
  73. +37
    -14
      vendor/golang.org/x/crypto/ssh/handshake.go
  74. +338
    -57
      vendor/golang.org/x/crypto/ssh/keys.go
  75. +14
    -0
      vendor/golang.org/x/crypto/ssh/messages.go
  76. +6
    -0
      vendor/golang.org/x/crypto/ssh/mux.go
  77. +31
    -5
      vendor/golang.org/x/crypto/ssh/server.go
  78. +35
    -0
      vendor/golang.org/x/crypto/ssh/tcpip.go
  79. +27
    -0
      vendor/golang.org/x/exp/LICENSE
  80. +22
    -0
      vendor/golang.org/x/exp/PATENTS
  81. +50
    -0
      vendor/golang.org/x/exp/constraints/constraints.go
  82. +44
    -0
      vendor/golang.org/x/exp/slices/cmp.go
  83. +499
    -0
      vendor/golang.org/x/exp/slices/slices.go
  84. +195
    -0
      vendor/golang.org/x/exp/slices/sort.go
  85. +479
    -0
      vendor/golang.org/x/exp/slices/zsortanyfunc.go
  86. +481
    -0
      vendor/golang.org/x/exp/slices/zsortordered.go
  87. +1
    -1
      vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go
  88. +15
    -15
      vendor/golang.org/x/mod/module/module.go
  89. +1
    -1
      vendor/golang.org/x/mod/module/pseudo.go
  90. +3
    -3
      vendor/golang.org/x/mod/semver/semver.go
  91. +0
    -1
      vendor/golang.org/x/net/context/go17.go
  92. +0
    -1
      vendor/golang.org/x/net/context/go19.go
  93. +0
    -1
      vendor/golang.org/x/net/context/pre_go17.go
  94. +0
    -1
      vendor/golang.org/x/net/context/pre_go19.go
  95. +31
    -28
      vendor/golang.org/x/net/http2/databuffer.go
  96. +0
    -30
      vendor/golang.org/x/net/http2/go111.go
  97. +0
    -27
      vendor/golang.org/x/net/http2/go115.go
  98. +0
    -17
      vendor/golang.org/x/net/http2/go118.go
  99. +0
    -21
      vendor/golang.org/x/net/http2/not_go111.go
  100. +0
    -31
      vendor/golang.org/x/net/http2/not_go115.go

+ 9
- 8
go.mod View File

@@ -96,12 +96,14 @@ require (
github.com/yuin/goldmark v1.4.13
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
github.com/yuin/goldmark-meta v1.1.0
golang.org/x/crypto v0.13.0
golang.org/x/net v0.15.0
golang.org/x/crypto v0.16.0
golang.org/x/exp v0.0.0-20231127185646-65229373498e
golang.org/x/net v0.19.0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.12.0
golang.org/x/text v0.13.0
golang.org/x/tools v0.9.3
golang.org/x/sys v0.15.0
golang.org/x/text v0.14.0
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
golang.org/x/tools v0.16.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.56.0
gopkg.in/ldap.v3 v3.0.2
@@ -255,9 +257,8 @@ require (
go.mongodb.org/mongo-driver v1.1.1 // indirect
go.opencensus.io v0.22.1 // indirect
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
google.golang.org/api v0.9.0 // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect


+ 17
- 15
go.sum View File

@@ -854,10 +854,12 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
@@ -874,8 +876,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -911,8 +913,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -933,8 +935,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -980,14 +982,14 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -996,8 +998,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1028,8 +1030,8 @@ golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWc
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=


+ 439
- 0
models/card_request.go View File

@@ -0,0 +1,439 @@
package models

import (
"errors"
"strings"

"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
)

const CARD_REQUEST_COMMIT = 1
const CARD_REQUEST_AGREE = 2
const CARD_REQEST_DISAGREE = 3

const RESOURCE_TYPE_SHARE = 1 //共享
const RESOURCE_TYPE_EXCLUSIVE = 2 //独占

const OrderByIDDesc = "card_request.id desc"
const OrderByStatus = "card_request.status asc,card_request.id desc"

type CardRequest struct {
ID int64 `xorm:"pk autoincr"`
ComputeResource string
UID int64
UserName string `xorm:"-"`
CardType string
AccCardsNum string
DiskCapacity int64
ResourceType int
BeginDate string
BeginUnix int64 `xorm:"INDEX"`
EndDate string
EndUnix int64 `xorm:"INDEX"`
Contact string
PhoneNumber string
EmailAddress string
Org string `xorm:"varchar(500)"`
Description string `xorm:"varchar(3000)"`
Status int
Review string `xorm:"varchar(3000)"`
CreatedUnix int64 `xorm:"INDEX created"`
UpdatedUnix int64 `xorm:"INDEX updated"`
DeleteUnix int64 `xorm:"deleted"`
}

type CardRequestSpecRes struct {
ID int64
ComputeResource string
UID int64
UserName string
CardType string
AccCardsNum string
DiskCapacity int64
ResourceType int
BeginDate string
BeginUnix int64
EndDate string
EndUnix int64
Contact string
PhoneNumber string
EmailAddress string
Org string
Description string
Status int
Review string
CreatedUnix int64
UpdatedUnix int64
DeleteUnix int64
Specs []RequestSpecInfo
}

func (CardRequestSpecRes) TableName() string {
return "card_request"
}

type CardRequestSpec struct {
ID int64 `xorm:"pk autoincr"`
RequestId int64 `xorm:"unique(idx_request_spec)"`
SpecId int64 `xorm:"unique(idx_request_spec)"`
CreatedTime timeutil.TimeStamp `xorm:"created"`
}

type CardRequestOptions struct {
ListOptions
UserID int64
OrderBy string
Keyword string

AiCenterCode string
QueueId int64
ComputeResource string
AccCardType string
Cluster string
ResourceType int
UseBeginTime int64
UseEndTime int64
BeginTimeUnix int64
EndTimeUnix int64
NeedSpec bool
}
type CardRequestShowList struct {
Total int64 `json:"total"`
CardRequestList []*CardRequestSpecShow `json:"cardRequestList"`
}

type CardRequestSpecShow struct {
ID int64 `json:"id"`
ComputeResource string `json:"compute_resource"`
CardType string `json:"card_type"`
AccCardsNum string `json:"acc_cards_num"`
BeginDate string `json:"begin_date"`
EndDate string `json:"end_date"`
ResourceType int `json:"resource_type"`
DiskCapacity int64 `json:"disk_capacity"`
UID int64 `json:"uid"`
UserName string `json:"user_name"`
TargetCenter []string `json:"target_center"`
Contact string `json:"contact"`
PhoneNumber string `json:"phone_number"`
EmailAddress string `json:"email_address"`
Org string `json:"org"`
Description string `json:"description"`
Status int `json:"status"`
Review string `json:"review"`
CreatedUnix int64 `json:"created_unix"`
Specs []RequestSpecInfo `json:"specs"`
}

type RequestSpecInfo struct {
ID int64
SourceSpecId string
AccCardsNum int
CpuCores int
MemGiB float32
GPUMemGiB float32
ShareMemGiB float32
UnitPrice int
Status int
UpdatedTime timeutil.TimeStamp
RequestId int64
//queue
Cluster string
AiCenterCode string
AiCenterName string
QueueCode string
QueueId int64
ComputeResource string
AccCardType string
HasInternet int
}

func (RequestSpecInfo) TableName() string {
return "resource_specification"
}

type CardRequestReview struct {
ID int64
Review string
SpecIds []int64
}

func AgreeCardRequest(r CardRequestReview) error {
sess := x.NewSession()
var err error
defer func() {
if err != nil {
sess.Rollback()
}
sess.Close()
}()

// find old scene
old := CardRequest{}
if has, _ := sess.ID(r.ID).Get(&old); !has {
return errors.New("CardRequest not exist")
}
//check specification
specs := make([]ResourceSpecification, 0)
cond := builder.In("id", r.SpecIds)
if err := sess.Where(cond).Find(&specs); err != nil {
return err
}
if len(specs) < len(r.SpecIds) {
return errors.New("specIds not correct")
}

rs := CardRequest{
Status: CARD_REQUEST_AGREE,
Review: "",
}
if _, err = sess.ID(r.ID).Cols("status", "review").Update(&rs); err != nil {
return err
}

//delete scene spec relation
if _, err = sess.Where("request_id = ? ", r.ID).Delete(&CardRequestSpec{}); err != nil {
sess.Rollback()
return err
}

if len(r.SpecIds) == 0 {
return sess.Commit()
}
//build new scene spec relation
rss := make([]CardRequestSpec, len(r.SpecIds))
for i, v := range r.SpecIds {
rss[i] = CardRequestSpec{
RequestId: r.ID,
SpecId: v,
}
}
if _, err = sess.Insert(&rss); err != nil {
sess.Rollback()
return err
}

return sess.Commit()
}

func DisagreeCardRequest(r CardRequestReview) error {
sess := x.NewSession()
var err error
defer func() {
if err != nil {
sess.Rollback()
}
sess.Close()
}()

// find old scene
old := CardRequest{}
if has, _ := sess.ID(r.ID).Get(&old); !has {
return errors.New("CardRequest not exist")
}
//update review_message
rs := CardRequest{
Status: CARD_REQEST_DISAGREE,
Review: r.Review,
}
if _, err = sess.ID(r.ID).Update(&rs); err != nil {
return err
}

//delete scene spec relation
if _, err = sess.Where("request_id = ? ", r.ID).Delete(&CardRequestSpec{}); err != nil {
sess.Rollback()
return err
}

return sess.Commit()
}

func CreateCardRequest(cardRequest *CardRequest) error {
_, err := x.Insert(cardRequest)
return err
}
func GetCardRequestById(id int64) (*CardRequest, error) {
rel := new(CardRequest)
has, err := x.
ID(id).
Get(rel)
if err != nil {
return nil, err
} else if !has {
return nil, ErrNotExist{id}
}

return rel, nil
}

func SearchCardRequest(opts *CardRequestOptions) (int64, []*CardRequestSpecRes, error) {
var cond = builder.NewCond()
if opts.Page <= 0 {
opts.Page = 1
}

needJoinSpec := false
if opts.Keyword != "" {
lowerKeyWord := strings.ToLower(opts.Keyword)
cond = cond.And(builder.Or(builder.Like{"LOWER(card_request.contact)", lowerKeyWord},
builder.Like{"LOWER(card_request.acc_cards_num)", lowerKeyWord},
builder.Like{"LOWER(card_request.description)", lowerKeyWord}, builder.Like{"LOWER(card_request.description)", lowerKeyWord},
builder.Like{"LOWER(card_request.phone_number)", lowerKeyWord}, builder.Like{"LOWER(card_request.org)", lowerKeyWord},
builder.Like{"LOWER(\"user\".name)", lowerKeyWord}))
}
if opts.UserID != 0 {
cond = cond.And(builder.Eq{"\"user\".id": opts.UserID})
}

if opts.ResourceType != 0 {
cond = cond.And(builder.Eq{"card_request.resource_type": opts.ResourceType})
}
if opts.AiCenterCode != "" {
needJoinSpec = true
cond = cond.And(builder.Eq{"resource_queue.ai_center_code": opts.AiCenterCode})
}
if opts.QueueId > 0 {
cond = cond.And(builder.Eq{"resource_queue.id": opts.QueueId})
needJoinSpec = true
}
if opts.ComputeResource != "" {
cond = cond.And(builder.Eq{"card_request.compute_resource": opts.ComputeResource})
}
if opts.AccCardType != "" {
cond = cond.And(builder.Eq{"card_request.card_type": opts.AccCardType})
}
if opts.Cluster != "" {
cond = cond.And(builder.Eq{"resource_queue.cluster": opts.Cluster})
needJoinSpec = true
}

if opts.UseBeginTime != 0 {
cond = cond.And(builder.Gte{"card_request.begin_unix": opts.UseBeginTime})
}
if opts.UseEndTime != 0 {
cond = cond.And(builder.Lte{"card_request.end_unix": opts.UseEndTime})
}

if opts.BeginTimeUnix != 0 {
cond = cond.And(builder.Gte{"card_request.created_unix": opts.BeginTimeUnix})
}
if opts.EndTimeUnix != 0 {
cond = cond.And(builder.Lte{"card_request.created_unix": opts.EndTimeUnix})
}
if opts.OrderBy == "" {
opts.OrderBy = OrderByIDDesc
}

cond = cond.And(builder.NewCond().Or(builder.Eq{"card_request.delete_unix": 0}).Or(builder.IsNull{"card_request.delete_unix"}))
cols := []string{"card_request.id", "card_request.compute_resource", "card_request.contact", "card_request.card_type", "card_request.acc_cards_num",
"card_request.disk_capacity", "card_request.resource_type", "card_request.begin_date", "card_request.end_date", "card_request.uid",
"card_request.phone_number", "card_request.email_address", "card_request.org", "card_request.description", "card_request.status", "card_request.review",
"card_request.created_unix"}
var count int64
var err error
if needJoinSpec {
count, err = x.Where(cond).
Distinct("card_request.id").
Join("INNER", "card_request_spec", "card_request_spec.request_id = card_request.id").
Join("INNER", "user", "\"user\".id = card_request.uid").
Join("INNER", "resource_specification", "resource_specification.id = card_request_spec.spec_id").
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id").
Count(&CardRequestSpecRes{})
if err != nil {
return 0, nil, err
}
} else {
count, err = x.Where(cond).
Distinct("card_request.id").
Join("INNER", "user", "\"user\".id = card_request.uid").
Count(&CardRequestSpecRes{})
}

r := make([]*CardRequestSpecRes, 0)
if needJoinSpec {
if err = x.Where(cond).Distinct(cols...).
Join("INNER", "card_request_spec", "card_request_spec.request_id = card_request.id").
Join("INNER", "user", "\"user\".id = card_request.uid").
Join("INNER", "resource_specification", "resource_specification.id = card_request_spec.spec_id").
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id").
OrderBy(opts.OrderBy).
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
Find(&r); err != nil {
return 0, nil, err
}
} else {
if err = x.Where(cond).Distinct(cols...).
Join("INNER", "user", "\"user\".id = card_request.uid").
OrderBy(opts.OrderBy).
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
Find(&r); err != nil {
return 0, nil, err
}
}

if len(r) == 0 {
return 0, r, err
}

for _, v := range r {
user, _ := GetUserByID(v.UID)
if user != nil {
v.UserName = user.Name
}

}

//find related specs
if opts.NeedSpec {
requestIds := make([]int64, 0, len(r))
for _, v := range r {
requestIds = append(requestIds, v.ID)
}

specs := make([]RequestSpecInfo, 0)

if err := x.Cols("resource_specification.id", "resource_specification.source_spec_id",
"resource_specification.acc_cards_num", "resource_specification.cpu_cores",
"resource_specification.mem_gi_b", "resource_specification.gpu_mem_gi_b",
"resource_specification.share_mem_gi_b", "resource_specification.unit_price",
"resource_specification.status", "resource_specification.updated_time",
"card_request_spec.request_id", "resource_queue.cluster",
"resource_queue.ai_center_code", "resource_queue.acc_card_type",
"resource_queue.id as queue_id", "resource_queue.compute_resource",
"resource_queue.queue_code", "resource_queue.ai_center_name",
"resource_queue.has_internet",
).In("card_request_spec.request_id", requestIds).
Join("INNER", "card_request_spec", "card_request_spec.spec_id = resource_specification.id").
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id").
OrderBy("resource_specification.acc_cards_num").
Find(&specs); err != nil {
return 0, nil, err
}

specsMap := make(map[int64][]RequestSpecInfo, 0)
for _, v := range specs {
if _, ok := specsMap[v.RequestId]; !ok {
specsMap[v.RequestId] = []RequestSpecInfo{v}
} else {
specsMap[v.RequestId] = append(specsMap[v.RequestId], v)
}
}

for i, v := range r {
s := specsMap[v.ID]
if s == nil {
s = make([]RequestSpecInfo, 0)
}
r[i].Specs = s
}
}

return count, r, nil
}

func UpdateCardRequest(cardRequest *CardRequest) error {
_, err := x.ID(cardRequest.ID).Cols("compute_resource", "contact", "card_type", "acc_cards_num", "disk_capacity", "resource_type", "begin_date", "end_date", "phone_number", "email_address", "org", "description", "begin_unix", "end_unix").Update(cardRequest)
return err
}

+ 2
- 0
models/models.go View File

@@ -177,6 +177,8 @@ func init() {
new(ModelartsDeploy),
new(ModelartsDeployQueue),
new(CloudbrainConfig),
new(CardRequest),
new(CardRequestSpec),
)

tablesStatistic = append(tablesStatistic,


+ 42
- 0
modules/structs/card_requests.go View File

@@ -0,0 +1,42 @@
package structs

type CardReq struct {
ID int64 `json:"id"`
ComputeResource string `json:"compute_resource" binding:"Required"`
CardType string `json:"card_type" binding:"Required"`
AccCardsNum string `json:"acc_cards_num" binding:"Required"`
DiskCapacity int64 `json:"disk_capacity"`
ResourceType int `json:"resource_type" binding:"Required"`
BeginDate string `json:"begin_date" binding:"Required"`
EndDate string `json:"end_date" binding:"Required"`
Contact string `json:"contact" binding:"Required"`
PhoneNumber string `json:"phone_number" binding:"Required"`
EmailAddress string `json:"email_address" binding:"Required;Email;MaxSize(254)"`
Org string `json:"org" binding:"MaxSize(500)"`
Description string `json:"description" binding:"MaxSize(3000)"`
Review string `json:"review"`
SpecIds []int64 `json:"spec_ids"`
}

type RequestSpecInfo struct {
ID int64
SourceSpecId string
AccCardsNum int
CpuCores int
MemGiB float32
GPUMemGiB float32
ShareMemGiB float32
UnitPrice int
Status int
UpdatedTime int64
RequestId int64
//queue
Cluster string
AiCenterCode string
AiCenterName string
QueueCode string
QueueId int64
ComputeResource string
AccCardType string
HasInternet int
}

+ 7
- 0
options/locale/locale_en-US.ini View File

@@ -338,6 +338,8 @@ robot = Robot
federated_learning = Federated learning
data_mining = Data mining
RISC-V_development = RISC-V development
computing_power = Computing power
computing_resources = Computing resources
domestic_computing_power = Domestic computing power

[auth]
@@ -852,6 +854,11 @@ email_notifications.onmention = Only Email on Mention
email_notifications.disable = Disable Email Notifications
email_notifications.submit = Set Email Preference

[card_request]
create_fail=Failed to create card requirement.
update_fail=Failed to update card requirement.
update_fail_no_record=The record does not exist.

[dataset]
alert = To initiate a cloud brain task, please upload the dataset in zip format.
dataset = Dataset


+ 7
- 0
options/locale/locale_zh-CN.ini View File

@@ -341,6 +341,8 @@ robot = 机器人
federated_learning = 联邦学习
data_mining = 数据挖掘
RISC-V_development = RISC-V开发
computing_power = 算力
computing_resources = 算力资源
domestic_computing_power = 国产算力

[auth]
@@ -855,6 +857,11 @@ email_notifications.enable=启用邮件通知
email_notifications.onmention=只在被提到时邮件通知
email_notifications.disable=停用邮件通知
email_notifications.submit=邮件通知设置
[card_request]
create_fail=创建算力需求失败。
update_fail=更新算力需求失败。
update_fail_no_record=修改的记录不存在。


[dataset]
alert=如果要发起云脑任务,请上传zip格式的数据集


+ 268
- 0
routers/card_request/card_request.go View File

@@ -0,0 +1,268 @@
package card_request

import (
"net/http"
"strings"
"time"

"code.gitea.io/gitea/modules/setting"

"code.gitea.io/gitea/modules/log"

api "code.gitea.io/gitea/modules/structs"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
cardrequestservice "code.gitea.io/gitea/services/card_request"
"golang.org/x/exp/slices"
)

func GetCreationInfo(ctx *context.Context) {

data, err := cardrequestservice.GetCreationInfo()

if err != nil {
log.Error("can not get creation info", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error()))
return
}

ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Data: data})

}

func GetCardRequestList(ctx *context.Context) {

page := ctx.QueryInt("page")
if page < 1 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize < 1 {
pageSize = setting.UI.DatasetPagingNum
}

opts := &models.CardRequestOptions{
OrderBy: models.OrderByIDDesc,
NeedSpec: false,
}
opts.ListOptions = models.ListOptions{
Page: page,
PageSize: pageSize,
}
getRequestShowList(ctx, opts, false)
}

func GetMyCardRequestList(ctx *context.Context) {

page := ctx.QueryInt("page")
if page < 1 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize < 1 {
pageSize = setting.UI.DatasetPagingNum
}

opts := &models.CardRequestOptions{
UserID: ctx.User.ID,
OrderBy: models.OrderByIDDesc,
NeedSpec: true,
}
opts.ListOptions = models.ListOptions{
Page: page,
PageSize: pageSize,
}
getRequestShowList(ctx, opts, true)
}

func GetAdminCardRequestList(ctx *context.Context) {

page := ctx.QueryInt("page")
if page < 1 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize < 1 {
pageSize = setting.UI.DatasetPagingNum
}
useBeginTime, _ := time.Parse(cardrequestservice.DATE_LAYOUT, ctx.Query("useBeginTime"))
useBeginTime.Unix()

opts := &models.CardRequestOptions{
OrderBy: models.OrderByStatus,
NeedSpec: true,
Keyword: strings.Trim(ctx.Query("q"), " "),
AiCenterCode: ctx.Query("center"),
Cluster: ctx.Query("cluster"),
ComputeResource: ctx.Query("resource"),
AccCardType: ctx.Query("cardType"),
QueueId: ctx.QueryInt64("queue"),
UseBeginTime: getTimeUnix(ctx.Query("useBeginTime")),
UseEndTime: getTimeUnix(ctx.Query("useEndTime")),
BeginTimeUnix: getTimeUnix(ctx.Query("beginTime")),
EndTimeUnix: getTimeUnix(ctx.Query("endTime")),
}
opts.ListOptions = models.ListOptions{
Page: page,
PageSize: pageSize,
}
getRequestShowList(ctx, opts, true)
}

func CreateCardRequest(ctx *context.Context, cardReq api.CardReq) {
data, err := cardrequestservice.GetCreationInfo()
if err != nil {
log.Error("can not get creation info", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error()))
return
}

if v, ok := data[cardReq.ComputeResource]; !ok {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.parameter_is_wrong")))
return
} else {
if !slices.Contains(v, cardReq.CardType) {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.parameter_is_wrong")))
return
}
}

if cardReq.ResourceType != models.RESOURCE_TYPE_SHARE && cardReq.ResourceType != models.RESOURCE_TYPE_EXCLUSIVE {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.parameter_is_wrong")))
return
}

err = cardrequestservice.CreateCardRequest(cardReq, ctx.User.ID)
if err != nil {
log.Error("can not create card request", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("card_request.create_fail")))
} else {
ctx.JSON(http.StatusOK, models.BaseOKMessageApi)
}

}

func UpdateCardRequestAndSpec(ctx *context.Context, cardReq api.CardReq) {

id := ctx.ParamsInt64(":id")
action := ctx.Query("action")

cardReq.ID = id
var err error
switch action {
case "agree":
err = cardrequestservice.AgreeRequest(cardReq)
case "disagree":
err = cardrequestservice.DisagreeRequest(cardReq)
case "modify":
err = cardrequestservice.UpdateCardRequestAdmin(cardReq)
}

if err != nil {
log.Error("Update error. %v", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("card_request.update_fail")))
return
}
ctx.JSON(http.StatusOK, models.BaseOKMessageApi)

}

func UpdateCardRequest(ctx *context.Context, cardReq api.CardReq) {
id := ctx.ParamsInt64(":id")

cardRequestInDB, err := models.GetCardRequestById(id)
if err != nil {
log.Error("can not get card request record", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("card_request.update_fail_no_record")))
return
}
if ctx.User.ID != cardRequestInDB.UID || cardRequestInDB.Status == models.CARD_REQEST_DISAGREE {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("common_error.insufficient_permission")))
return
}

data, err := cardrequestservice.GetCreationInfo()
if err != nil {
log.Error("can not get creation info", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error()))
return
}

if v, ok := data[cardReq.ComputeResource]; !ok {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.parameter_is_wrong")))
return
} else {
if !slices.Contains(v, cardReq.CardType) {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.parameter_is_wrong")))
return
}
}

if cardReq.ResourceType != models.RESOURCE_TYPE_SHARE && cardReq.ResourceType != models.RESOURCE_TYPE_EXCLUSIVE {
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.parameter_is_wrong")))
return
}
cardReq.ID = id
err = cardrequestservice.UpdateCardRequest(cardReq, cardRequestInDB)
if err != nil {
log.Error("Update card request failed", err)
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("card_request.update_fail")))
return
}
ctx.JSON(http.StatusOK, models.BaseOKMessageApi)
}

func getRequestShowList(ctx *context.Context, opts *models.CardRequestOptions, containsAllParams bool) {
total, res, err := models.SearchCardRequest(opts)
if err != nil {
log.Error("search card request err", err)
ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Data: models.CardRequestShowList{
CardRequestList: []*models.CardRequestSpecShow{},
}})
return
}

var show = make([]*models.CardRequestSpecShow, 0)
for _, v := range res {

customShow := &models.CardRequestSpecShow{
ID: v.ID,
ComputeResource: v.ComputeResource,
CardType: v.CardType,
AccCardsNum: v.AccCardsNum,
BeginDate: v.BeginDate,
EndDate: v.EndDate,
CreatedUnix: v.CreatedUnix,
Status: v.Status,
}
if containsAllParams {
customShow.UID = v.UID
customShow.UserName = v.UserName
customShow.Review = v.Review
customShow.PhoneNumber = v.PhoneNumber
customShow.EmailAddress = v.EmailAddress
customShow.Contact = v.Contact
customShow.Specs = v.Specs
customShow.Org = v.Org
customShow.Description = v.Description
customShow.ResourceType = v.ResourceType
customShow.DiskCapacity = v.DiskCapacity

}

show = append(show, customShow)
}
ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Data: models.CardRequestShowList{
Total: total,
CardRequestList: show,
}})
}

func getTimeUnix(value string) int64 {
timeParse, err := time.Parse(cardrequestservice.DATE_LAYOUT, value)
if err != nil {
return 0
}
return timeParse.Unix()
}

+ 9
- 4
routers/home.go View File

@@ -55,9 +55,10 @@ const (
tplRepoSquare base.TplName = "explore/repos/square"
tplRepoSearch base.TplName = "explore/repos/search"
tplRoshmci base.TplName = "explore/ros-hmci"

tplExploreCenterMap base.TplName = "explore/center_map"
tplExploreDomestic base.TplName = "explore/domestic"

tplComputingPowerDemand base.TplName = "computingpower/demand"
tplComputingPowerDomestic base.TplName = "computingpower/domestic"
)

// Home render home page
@@ -821,8 +822,12 @@ func ExploreImages(ctx *context.Context) {
ctx.HTML(200, tplExploreImages)
}

func ExploreDomestic(ctx *context.Context) {
ctx.HTML(200, tplExploreDomestic)
func ComputingPowerDemand(ctx *context.Context) {
ctx.HTML(200, tplComputingPowerDemand)
}

func ComputingPowerDomestic(ctx *context.Context) {
ctx.HTML(200, tplComputingPowerDomestic)
}

func ExploreDataAnalysisUserTrend(ctx *context.Context) {


+ 24
- 3
routers/routes/routes.go View File

@@ -12,6 +12,8 @@ import (
"text/template"
"time"

"code.gitea.io/gitea/routers/card_request"

"code.gitea.io/gitea/routers/super_compute"

"code.gitea.io/gitea/routers/tech"
@@ -398,6 +400,12 @@ func RegisterRoutes(m *macaron.Macaron) {
})
})

m.Group("/computingpower", func() {
m.Get("/demand", routers.ComputingPowerDemand)
m.Get("/domestic", routers.ComputingPowerDomestic)
}, ignSignIn)
operationReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, OperationRequired: true})
m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/explore/repos")
@@ -431,7 +439,22 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/data_analysis/Overview", routers.ExploreDataAnalysisOverview)
m.Get("/data_analysis/BrainAnalysis", routers.ExploreDataAnalysisBrainAnalysis)
m.Get("/center_map", reqSignIn, routers.CenterMapUI)
m.Get("/domestic", routers.ExploreDomestic)

m.Group("/card_request", func() {
m.Get("/creation/required", card_request.GetCreationInfo)
m.Get("/list", card_request.GetCardRequestList)

}, ignSignIn)

m.Group("/card_request", func() {
m.Post("/create", binding.Bind(structs.CardReq{}), card_request.CreateCardRequest)
m.Get("/my_list", card_request.GetMyCardRequestList)
m.Get("/admin_list", operationReq, card_request.GetAdminCardRequestList)
m.Get("/specification/list", operationReq, admin.GetAllResourceSpecificationList)
m.Put("/update/:id", binding.Bind(structs.CardReq{}), card_request.UpdateCardRequest)
m.Put("/admin/update/:id", operationReq, bindIgnErr(structs.CardReq{}), card_request.UpdateCardRequestAndSpec)

}, reqSignIn)

}, ignSignIn)
m.Combo("/install", routers.InstallInit).Get(routers.Install).
@@ -720,8 +743,6 @@ func RegisterRoutes(m *macaron.Macaron) {
}, adminReq)
// ***** END: Admin *****

operationReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, OperationRequired: true})

// ***** START: Operation *****
m.Group("/operation", func() {
m.Get("/config/recommend_org", operation.Organizations)


+ 146
- 0
services/card_request/card_request.go View File

@@ -0,0 +1,146 @@
package card_request

import (
"time"

"code.gitea.io/gitea/models"
api "code.gitea.io/gitea/modules/structs"
)

const DATE_LAYOUT = "2006-01-02"

func GetCreationInfo() (map[string][]string, error) {

xpuInfoBase, err := models.GetXPUInfos()

if err != nil {
return nil, err
}

var xpuInfoMap = make(map[string][]string)

for _, xpuInfo := range xpuInfoBase {
if _, ok := xpuInfoMap[xpuInfo.ResourceType]; ok {
xpuInfoMap[xpuInfo.ResourceType] = append(xpuInfoMap[xpuInfo.ResourceType], xpuInfo.CardTypeShow)
} else {
xpuInfoMap[xpuInfo.ResourceType] = []string{xpuInfo.CardTypeShow}
}
}
return xpuInfoMap, nil

}
func AgreeRequest(cardReq api.CardReq) error {
return models.AgreeCardRequest(models.CardRequestReview{
ID: cardReq.ID,
SpecIds: cardReq.SpecIds,
})
}

func DisagreeRequest(cardReq api.CardReq) error {
return models.DisagreeCardRequest(models.CardRequestReview{
ID: cardReq.ID,
Review: cardReq.Review,
})
}

func UpdateCardRequestAdmin(cardReq api.CardReq) error {
request := models.CardRequest{
ID: cardReq.ID,
ComputeResource: cardReq.ComputeResource,
CardType: cardReq.CardType,
AccCardsNum: cardReq.AccCardsNum,
EmailAddress: cardReq.EmailAddress,
DiskCapacity: cardReq.DiskCapacity,
Contact: cardReq.Contact,
PhoneNumber: cardReq.PhoneNumber,
BeginDate: cardReq.BeginDate,
EndDate: cardReq.EndDate,
Description: cardReq.Description,
Org: cardReq.Org,
ResourceType: cardReq.ResourceType,
}
beginTime, err := time.Parse(DATE_LAYOUT, cardReq.BeginDate)
if err != nil {
return err
}
endTime, err := time.Parse(DATE_LAYOUT, cardReq.EndDate)
if err != nil {
return err

}
request.BeginUnix = beginTime.Unix()
request.EndUnix = endTime.Unix()
return models.UpdateCardRequest(&request)
}

func UpdateCardRequest(cardReq api.CardReq, request *models.CardRequest) error {

request.DiskCapacity = cardReq.DiskCapacity
request.Org = cardReq.Org
request.Description = cardReq.Description

if request.Status == models.CARD_REQUEST_COMMIT {

request.ComputeResource = cardReq.ComputeResource
request.CardType = cardReq.CardType
request.AccCardsNum = cardReq.AccCardsNum
request.ResourceType = cardReq.ResourceType
request.BeginDate = cardReq.BeginDate
request.EndDate = cardReq.EndDate

request.Contact = cardReq.Contact
request.EmailAddress = cardReq.EmailAddress
request.PhoneNumber = cardReq.PhoneNumber

beginTime, err := time.Parse(DATE_LAYOUT, cardReq.BeginDate)
if err != nil {
return err
}
endTime, err := time.Parse(DATE_LAYOUT, cardReq.EndDate)
if err != nil {
return err

}
request.BeginUnix = beginTime.Unix()
request.EndUnix = endTime.Unix()

}

return models.UpdateCardRequest(request)

}

func CreateCardRequest(cardReq api.CardReq, uid int64) error {

bean := &models.CardRequest{
UID: uid,
ComputeResource: cardReq.ComputeResource,
CardType: cardReq.CardType,
AccCardsNum: cardReq.AccCardsNum,
EmailAddress: cardReq.EmailAddress,
DiskCapacity: cardReq.DiskCapacity,
Contact: cardReq.Contact,
PhoneNumber: cardReq.PhoneNumber,
BeginDate: cardReq.BeginDate,
EndDate: cardReq.EndDate,
Description: cardReq.Description,
Org: cardReq.Org,
ResourceType: cardReq.ResourceType,
Status: models.CARD_REQUEST_COMMIT,
}

beginTime, err := time.Parse(DATE_LAYOUT, cardReq.BeginDate)
if err != nil {
return err
}
endTime, err := time.Parse(DATE_LAYOUT, cardReq.EndDate)
if err != nil {
return err

}
bean.BeginUnix = beginTime.Unix()
bean.EndUnix = endTime.Unix()

return models.CreateCardRequest(bean)

}

+ 19
- 6
templates/base/head_navbar.tmpl View File

@@ -7,7 +7,7 @@
<i class="sidebar icon"></i>
</div>
</div>
<div class="item brand" style="padding-right:1.2rem">
<div class="item brand" style="padding-right:0.6rem">
<a href="/">
<!-- <img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg"> -->
<div>
@@ -46,7 +46,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui simple dropdown item" id='dropdown_explore'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -54,7 +62,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -94,8 +101,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui simple dropdown item" id='dropdown_PageHome'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -103,7 +117,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


+ 18
- 4
templates/base/head_navbar_fluid.tmpl View File

@@ -43,7 +43,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui dropdown item" id='dropdown_explore'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -51,7 +59,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -89,7 +96,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui dropdown item" id='dropdown_PageHome'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -97,7 +112,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


+ 18
- 4
templates/base/head_navbar_home.tmpl View File

@@ -35,7 +35,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui dropdown item" id='dropdown_explore'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -43,7 +51,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -83,7 +90,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new" style="margin-right: 20px;" style="margin-right: 20px;">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui dropdown item" id='dropdown_PageHome'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -91,7 +106,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


+ 18
- 4
templates/base/head_navbar_pro.tmpl View File

@@ -45,7 +45,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui dropdown item" id='dropdown_explore'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -53,7 +61,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -93,7 +100,15 @@
<a class="item" href="{{AppSubUrl}}/extension/modelbase"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_base"}}</span></a>
<a class="item" href="{{AppSubUrl}}/extension/mind"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "repo.model_pengcheng"}}</span></a>
</div>
</div>
</div>
<div class="ui simple dropdown item" >
<span class="menu-new-dot">{{.i18n.Tr "explore.computing_power"}}</span>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/computingpower/demand"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.computing_resources"}}</span></a>
<a class="item" href="{{AppSubUrl}}/computingpower/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>
</div>
</div>
<div class="ui dropdown item" id='dropdown_PageHome'>
<span>{{.i18n.Tr "explore"}}</span>
<i class="dropdown icon"></i>
@@ -101,7 +116,6 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


+ 8
- 0
templates/computingpower/demand.tmpl View File

@@ -0,0 +1,8 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-computingpower-demand.css?v={{MD5 AppVer}}"/>
{{if .IsOperator}}
<script>window.IS_OPERATOR = true;</script>
{{end}}
<div id="__vue-root"></div>
<script src="{{StaticUrlPrefix}}/js/vp-computingpower-demand.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 7
- 0
templates/computingpower/domestic.tmpl View File

@@ -0,0 +1,7 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-computingpower-domestic.css?v={{MD5 AppVer}}"/>
<div>
<div id="__vue-root"></div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-computingpower-domestic.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 0
- 7
templates/explore/domestic.tmpl View File

@@ -1,7 +0,0 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-explore-domestic.css?v={{MD5 AppVer}}"/>
<div>
<div id="__vue-root"></div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-explore-domestic.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 0
- 1
vendor/golang.org/x/crypto/acme/version_go112.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.12
// +build go1.12

package acme



+ 0
- 1
vendor/golang.org/x/crypto/argon2/blamka_amd64.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build amd64 && gc && !purego
// +build amd64,gc,!purego

package argon2



+ 0
- 1
vendor/golang.org/x/crypto/argon2/blamka_amd64.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build amd64 && gc && !purego
// +build amd64,gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/argon2/blamka_ref.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !amd64 || purego || !gc
// +build !amd64 purego !gc

package argon2



+ 0
- 1
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.7 && amd64 && gc && !purego
// +build go1.7,amd64,gc,!purego

package blake2b



+ 0
- 1
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.7 && amd64 && gc && !purego
// +build go1.7,amd64,gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !go1.7 && amd64 && gc && !purego
// +build !go1.7,amd64,gc,!purego

package blake2b



+ 0
- 1
vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build amd64 && gc && !purego
// +build amd64,gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/blake2b/blake2b_ref.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !amd64 || purego || !gc
// +build !amd64 purego !gc

package blake2b



+ 0
- 1
vendor/golang.org/x/crypto/blake2b/register.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.9
// +build go1.9

package blake2b



+ 1
- 2
vendor/golang.org/x/crypto/chacha20/chacha_arm64.go View File

@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build go1.11 && gc && !purego
// +build go1.11,gc,!purego
//go:build gc && !purego

package chacha20



+ 1
- 2
vendor/golang.org/x/crypto/chacha20/chacha_arm64.s View File

@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build go1.11 && gc && !purego
// +build go1.11,gc,!purego
//go:build gc && !purego

#include "textflag.h"



+ 1
- 2
vendor/golang.org/x/crypto/chacha20/chacha_noasm.go View File

@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build (!arm64 && !s390x && !ppc64le) || (arm64 && !go1.11) || !gc || purego
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 !gc purego
//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego

package chacha20



+ 0
- 1
vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

package chacha20



+ 0
- 1
vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s View File

@@ -20,7 +20,6 @@
// due to the calling conventions and initialization of constants.

//go:build gc && !purego
// +build gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/chacha20/chacha_s390x.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

package chacha20



+ 0
- 1
vendor/golang.org/x/crypto/chacha20/chacha_s390x.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

#include "go_asm.h"
#include "textflag.h"


+ 0
- 1
vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go View File

@@ -1,7 +1,6 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.

//go:build amd64 && gc && !purego
// +build amd64,gc,!purego

package field



+ 0
- 1
vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s View File

@@ -1,7 +1,6 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.

//go:build amd64 && gc && !purego
// +build amd64,gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !amd64 || !gc || purego
// +build !amd64 !gc purego

package field



+ 0
- 1
vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build arm64 && gc && !purego
// +build arm64,gc,!purego

package field



+ 0
- 1
vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build arm64 && gc && !purego
// +build arm64,gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !arm64 || !gc || purego
// +build !arm64 !gc purego

package field



+ 0
- 71
vendor/golang.org/x/crypto/ed25519/ed25519.go View File

@@ -1,71 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
package ed25519

import (
"crypto/ed25519"
"io"
)

const (
// PublicKeySize is the size, in bytes, of public keys as used in this package.
PublicKeySize = 32
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)

// PublicKey is the type of Ed25519 public keys.
//
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey

// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
//
// This type is an alias for crypto/ed25519's PrivateKey type.
// See the crypto/ed25519 package for the methods on this type.
type PrivateKey = ed25519.PrivateKey

// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
return ed25519.GenerateKey(rand)
}

// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
return ed25519.NewKeyFromSeed(seed)
}

// Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte {
return ed25519.Sign(privateKey, message)
}

// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
return ed25519.Verify(publicKey, message, sig)
}

+ 3
- 1
vendor/golang.org/x/crypto/hkdf/hkdf.go View File

@@ -56,7 +56,9 @@ func (f *hkdf) Read(p []byte) (int, error) {

// Fill the rest of the buffer
for len(p) > 0 {
f.expander.Reset()
if f.counter > 1 {
f.expander.Reset()
}
f.expander.Write(f.prev)
f.expander.Write(f.info)
f.expander.Write([]byte{f.counter})


+ 0
- 1
vendor/golang.org/x/crypto/internal/alias/alias.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !purego
// +build !purego

// Package alias implements memory aliasing tests.
package alias


+ 0
- 1
vendor/golang.org/x/crypto/internal/alias/alias_purego.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build purego
// +build purego

// Package alias implements memory aliasing tests.
package alias


+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !go1.13
// +build !go1.13

package poly1305



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.13
// +build go1.13

package poly1305



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego
// +build !amd64,!ppc64le,!s390x !gc purego

package poly1305



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

package poly1305



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

package poly1305



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

package poly1305



+ 0
- 1
vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

#include "textflag.h"



+ 0
- 1
vendor/golang.org/x/crypto/sha3/hashes_generic.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !gc || purego || !s390x
// +build !gc purego !s390x

package sha3



+ 0
- 1
vendor/golang.org/x/crypto/sha3/keccakf.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !amd64 || purego || !gc
// +build !amd64 purego !gc

package sha3



+ 0
- 1
vendor/golang.org/x/crypto/sha3/keccakf_amd64.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build amd64 && !purego && gc
// +build amd64,!purego,gc

package sha3



+ 0
- 1
vendor/golang.org/x/crypto/sha3/keccakf_amd64.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build amd64 && !purego && gc
// +build amd64,!purego,gc

// This code was translated into a form compatible with 6a from the public
// domain sources at https://github.com/gvanas/KeccakCodePackage


+ 0
- 1
vendor/golang.org/x/crypto/sha3/register.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.4
// +build go1.4

package sha3



+ 9
- 5
vendor/golang.org/x/crypto/sha3/sha3.go View File

@@ -121,11 +121,11 @@ func (d *state) padAndPermute(dsbyte byte) {
copyOut(d, d.buf)
}

// Write absorbs more data into the hash's state. It produces an error
// if more data is written to the ShakeHash after writing
// Write absorbs more data into the hash's state. It panics if any
// output has already been read.
func (d *state) Write(p []byte) (written int, err error) {
if d.state != spongeAbsorbing {
panic("sha3: write to sponge after read")
panic("sha3: Write after Read")
}
if d.buf == nil {
d.buf = d.storage.asBytes()[:0]
@@ -182,12 +182,16 @@ func (d *state) Read(out []byte) (n int, err error) {
}

// Sum applies padding to the hash state and then squeezes out the desired
// number of output bytes.
// number of output bytes. It panics if any output has already been read.
func (d *state) Sum(in []byte) []byte {
if d.state != spongeAbsorbing {
panic("sha3: Sum after Read")
}

// Make a copy of the original hash so that caller can keep writing
// and summing.
dup := d.clone()
hash := make([]byte, dup.outputLen)
hash := make([]byte, dup.outputLen, 64) // explicit cap to allow stack allocation
dup.Read(hash)
return append(in, hash...)
}

+ 6
- 5
vendor/golang.org/x/crypto/sha3/sha3_s390x.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

package sha3

@@ -49,7 +48,7 @@ type asmState struct {
buf []byte // care must be taken to ensure cap(buf) is a multiple of rate
rate int // equivalent to block size
storage [3072]byte // underlying storage for buf
outputLen int // output length if fixed, 0 if not
outputLen int // output length for full security
function code // KIMD/KLMD function code
state spongeDirection // whether the sponge is absorbing or squeezing
}
@@ -72,8 +71,10 @@ func newAsmState(function code) *asmState {
s.outputLen = 64
case shake_128:
s.rate = 168
s.outputLen = 32
case shake_256:
s.rate = 136
s.outputLen = 64
default:
panic("sha3: unrecognized function code")
}
@@ -108,7 +109,7 @@ func (s *asmState) resetBuf() {
// It never returns an error.
func (s *asmState) Write(b []byte) (int, error) {
if s.state != spongeAbsorbing {
panic("sha3: write to sponge after read")
panic("sha3: Write after Read")
}
length := len(b)
for len(b) > 0 {
@@ -192,8 +193,8 @@ func (s *asmState) Read(out []byte) (n int, err error) {
// Sum appends the current hash to b and returns the resulting slice.
// It does not change the underlying hash state.
func (s *asmState) Sum(b []byte) []byte {
if s.outputLen == 0 {
panic("sha3: cannot call Sum on SHAKE functions")
if s.state != spongeAbsorbing {
panic("sha3: Sum after Read")
}

// Copy the state to preserve the original.


+ 0
- 1
vendor/golang.org/x/crypto/sha3/sha3_s390x.s View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build gc && !purego
// +build gc,!purego

#include "textflag.h"



+ 14
- 15
vendor/golang.org/x/crypto/sha3/shake.go View File

@@ -17,26 +17,25 @@ package sha3

import (
"encoding/binary"
"hash"
"io"
)

// ShakeHash defines the interface to hash functions that
// support arbitrary-length output.
// ShakeHash defines the interface to hash functions that support
// arbitrary-length output. When used as a plain [hash.Hash], it
// produces minimum-length outputs that provide full-strength generic
// security.
type ShakeHash interface {
// Write absorbs more data into the hash's state. It panics if input is
// written to it after output has been read from it.
io.Writer
hash.Hash

// Read reads more output from the hash; reading affects the hash's
// state. (ShakeHash.Read is thus very different from Hash.Sum)
// It never returns an error.
// It never returns an error, but subsequent calls to Write or Sum
// will panic.
io.Reader

// Clone returns a copy of the ShakeHash in its current state.
Clone() ShakeHash

// Reset resets the ShakeHash to its initial state.
Reset()
}

// cSHAKE specific context
@@ -81,8 +80,8 @@ func leftEncode(value uint64) []byte {
return b[i-1:]
}

func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash {
c := cshakeState{state: &state{rate: rate, dsbyte: dsbyte}}
func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}

// leftEncode returns max 9 bytes
c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
@@ -119,7 +118,7 @@ func NewShake128() ShakeHash {
if h := newShake128Asm(); h != nil {
return h
}
return &state{rate: rate128, dsbyte: dsbyteShake}
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
}

// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
@@ -129,7 +128,7 @@ func NewShake256() ShakeHash {
if h := newShake256Asm(); h != nil {
return h
}
return &state{rate: rate256, dsbyte: dsbyteShake}
return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
}

// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
@@ -142,7 +141,7 @@ func NewCShake128(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake128()
}
return newCShake(N, S, rate128, dsbyteCShake)
return newCShake(N, S, rate128, 32, dsbyteCShake)
}

// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
@@ -155,7 +154,7 @@ func NewCShake256(N, S []byte) ShakeHash {
if len(N) == 0 && len(S) == 0 {
return NewShake256()
}
return newCShake(N, S, rate256, dsbyteCShake)
return newCShake(N, S, rate256, 64, dsbyteCShake)
}

// ShakeSum128 writes an arbitrary-length digest of data into hash.


+ 0
- 1
vendor/golang.org/x/crypto/sha3/shake_generic.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !gc || purego || !s390x
// +build !gc purego !s390x

package sha3



+ 0
- 1
vendor/golang.org/x/crypto/sha3/xor.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build (!amd64 && !386 && !ppc64le) || purego
// +build !amd64,!386,!ppc64le purego

package sha3



+ 0
- 2
vendor/golang.org/x/crypto/sha3/xor_unaligned.go View File

@@ -3,8 +3,6 @@
// license that can be found in the LICENSE file.

//go:build (amd64 || 386 || ppc64le) && !purego
// +build amd64 386 ppc64le
// +build !purego

package sha3



+ 10
- 5
vendor/golang.org/x/crypto/ssh/agent/client.go View File

@@ -16,6 +16,7 @@ import (
"bytes"
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"encoding/base64"
@@ -26,7 +27,6 @@ import (
"math/big"
"sync"

"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh"
)

@@ -141,9 +141,14 @@ const (
agentAddSmartcardKeyConstrained = 26

// 3.7 Key constraint identifiers
agentConstrainLifetime = 1
agentConstrainConfirm = 2
agentConstrainExtension = 3
agentConstrainLifetime = 1
agentConstrainConfirm = 2
// Constraint extension identifier up to version 2 of the protocol. A
// backward incompatible change will be required if we want to add support
// for SSH_AGENT_CONSTRAIN_MAXSIGN which uses the same ID.
agentConstrainExtensionV00 = 3
// Constraint extension identifier in version 3 and later of the protocol.
agentConstrainExtension = 255
)

// maxAgentResponseBytes is the maximum agent reply size that is accepted. This
@@ -205,7 +210,7 @@ type constrainLifetimeAgentMsg struct {
}

type constrainExtensionAgentMsg struct {
ExtensionName string `sshtype:"3"`
ExtensionName string `sshtype:"255|3"`
ExtensionDetails []byte

// Rest is a field used for parsing, not part of message


+ 2
- 2
vendor/golang.org/x/crypto/ssh/agent/server.go View File

@@ -7,6 +7,7 @@ package agent
import (
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"encoding/binary"
@@ -16,7 +17,6 @@ import (
"log"
"math/big"

"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh"
)

@@ -208,7 +208,7 @@ func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse
case agentConstrainConfirm:
confirmBeforeUse = true
constraints = constraints[1:]
case agentConstrainExtension:
case agentConstrainExtension, agentConstrainExtensionV00:
var msg constrainExtensionAgentMsg
if err = ssh.Unmarshal(constraints, &msg); err != nil {
return 0, false, nil, err


+ 30
- 8
vendor/golang.org/x/crypto/ssh/certs.go View File

@@ -16,8 +16,9 @@ import (

// Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear
// in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms.
// Unlike key algorithm names, these are not passed to AlgorithmSigner and don't
// appear in the Signature.Format field.
// Unlike key algorithm names, these are not passed to AlgorithmSigner nor
// returned by MultiAlgorithmSigner and don't appear in the Signature.Format
// field.
const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
@@ -255,10 +256,17 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
return nil, errors.New("ssh: signer and cert have different public key")
}

if algorithmSigner, ok := signer.(AlgorithmSigner); ok {
switch s := signer.(type) {
case MultiAlgorithmSigner:
return &multiAlgorithmSigner{
AlgorithmSigner: &algorithmOpenSSHCertSigner{
&openSSHCertSigner{cert, signer}, s},
supportedAlgorithms: s.Algorithms(),
}, nil
case AlgorithmSigner:
return &algorithmOpenSSHCertSigner{
&openSSHCertSigner{cert, signer}, algorithmSigner}, nil
} else {
&openSSHCertSigner{cert, signer}, s}, nil
default:
return &openSSHCertSigner{cert, signer}, nil
}
}
@@ -432,7 +440,9 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
}

// SignCert signs the certificate with an authority, setting the Nonce,
// SignatureKey, and Signature fields.
// SignatureKey, and Signature fields. If the authority implements the
// MultiAlgorithmSigner interface the first algorithm in the list is used. This
// is useful if you want to sign with a specific algorithm.
func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
c.Nonce = make([]byte, 32)
if _, err := io.ReadFull(rand, c.Nonce); err != nil {
@@ -440,8 +450,20 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
}
c.SignatureKey = authority.PublicKey()

// Default to KeyAlgoRSASHA512 for ssh-rsa signers.
if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
if v, ok := authority.(MultiAlgorithmSigner); ok {
if len(v.Algorithms()) == 0 {
return errors.New("the provided authority has no signature algorithm")
}
// Use the first algorithm in the list.
sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), v.Algorithms()[0])
if err != nil {
return err
}
c.Signature = sig
return nil
} else if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
// Default to KeyAlgoRSASHA512 for ssh-rsa signers.
// TODO: consider using KeyAlgoRSASHA256 as default.
sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512)
if err != nil {
return err


+ 85
- 31
vendor/golang.org/x/crypto/ssh/client_auth.go View File

@@ -71,7 +71,9 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
if err != nil {
return err
// We return the error later if there is no other method left to
// try.
ok = authFailure
}
if ok == authSuccess {
// success
@@ -101,6 +103,12 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
}
}
}

if auth == nil && err != nil {
// We have an error and there are no other authentication methods to
// try, so we return it.
return err
}
}
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
}
@@ -217,21 +225,45 @@ func (cb publicKeyCallback) method() string {
return "publickey"
}

func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as AlgorithmSigner, algo string) {
func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiAlgorithmSigner, string, error) {
var as MultiAlgorithmSigner
keyFormat := signer.PublicKey().Type()

// Like in sendKexInit, if the public key implements AlgorithmSigner we
// assume it supports all algorithms, otherwise only the key format one.
as, ok := signer.(AlgorithmSigner)
if !ok {
return algorithmSignerWrapper{signer}, keyFormat
// If the signer implements MultiAlgorithmSigner we use the algorithms it
// support, if it implements AlgorithmSigner we assume it supports all
// algorithms, otherwise only the key format one.
switch s := signer.(type) {
case MultiAlgorithmSigner:
as = s
case AlgorithmSigner:
as = &multiAlgorithmSigner{
AlgorithmSigner: s,
supportedAlgorithms: algorithmsForKeyFormat(underlyingAlgo(keyFormat)),
}
default:
as = &multiAlgorithmSigner{
AlgorithmSigner: algorithmSignerWrapper{signer},
supportedAlgorithms: []string{underlyingAlgo(keyFormat)},
}
}

getFallbackAlgo := func() (string, error) {
// Fallback to use if there is no "server-sig-algs" extension or a
// common algorithm cannot be found. We use the public key format if the
// MultiAlgorithmSigner supports it, otherwise we return an error.
if !contains(as.Algorithms(), underlyingAlgo(keyFormat)) {
return "", fmt.Errorf("ssh: no common public key signature algorithm, server only supports %q for key type %q, signer only supports %v",
underlyingAlgo(keyFormat), keyFormat, as.Algorithms())
}
return keyFormat, nil
}

extPayload, ok := extensions["server-sig-algs"]
if !ok {
// If there is no "server-sig-algs" extension, fall back to the key
// format algorithm.
return as, keyFormat
// If there is no "server-sig-algs" extension use the fallback
// algorithm.
algo, err := getFallbackAlgo()
return as, algo, err
}

// The server-sig-algs extension only carries underlying signature
@@ -245,15 +277,22 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as Alg
}
}

keyAlgos := algorithmsForKeyFormat(keyFormat)
// Filter algorithms based on those supported by MultiAlgorithmSigner.
var keyAlgos []string
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if contains(as.Algorithms(), underlyingAlgo(algo)) {
keyAlgos = append(keyAlgos, algo)
}
}

algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos)
if err != nil {
// If there is no overlap, try the key anyway with the key format
// algorithm, to support servers that fail to list all supported
// algorithms.
return as, keyFormat
// If there is no overlap, return the fallback algorithm to support
// servers that fail to list all supported algorithms.
algo, err := getFallbackAlgo()
return as, algo, err
}
return as, algo
return as, algo, nil
}

func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
@@ -267,14 +306,39 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
return authFailure, nil, err
}
var methods []string
for _, signer := range signers {
pub := signer.PublicKey()
as, algo := pickSignatureAlgorithm(signer, extensions)
var errSigAlgo error

origSignersLen := len(signers)
for idx := 0; idx < len(signers); idx++ {
signer := signers[idx]
pub := signer.PublicKey()
as, algo, err := pickSignatureAlgorithm(signer, extensions)
if err != nil && errSigAlgo == nil {
// If we cannot negotiate a signature algorithm store the first
// error so we can return it to provide a more meaningful message if
// no other signers work.
errSigAlgo = err
continue
}
ok, err := validateKey(pub, algo, user, c)
if err != nil {
return authFailure, nil, err
}
// OpenSSH 7.2-7.7 advertises support for rsa-sha2-256 and rsa-sha2-512
// in the "server-sig-algs" extension but doesn't support these
// algorithms for certificate authentication, so if the server rejects
// the key try to use the obtained algorithm as if "server-sig-algs" had
// not been implemented if supported from the algorithm signer.
if !ok && idx < origSignersLen && isRSACert(algo) && algo != CertAlgoRSAv01 {
if contains(as.Algorithms(), KeyAlgoRSA) {
// We retry using the compat algorithm after all signers have
// been tried normally.
signers = append(signers, &multiAlgorithmSigner{
AlgorithmSigner: as,
supportedAlgorithms: []string{KeyAlgoRSA},
})
}
}
if !ok {
continue
}
@@ -317,22 +381,12 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
// contain the "publickey" method, do not attempt to authenticate with any
// other keys. According to RFC 4252 Section 7, the latter can occur when
// additional authentication methods are required.
if success == authSuccess || !containsMethod(methods, cb.method()) {
if success == authSuccess || !contains(methods, cb.method()) {
return success, methods, err
}
}

return authFailure, methods, nil
}

func containsMethod(methods []string, method string) bool {
for _, m := range methods {
if m == method {
return true
}
}

return false
return authFailure, methods, errSigAlgo
}

// validateKey validates the key provided is acceptable to the server.


+ 8
- 3
vendor/golang.org/x/crypto/ssh/common.go View File

@@ -10,7 +10,6 @@ import (
"fmt"
"io"
"math"
"strings"
"sync"

_ "crypto/sha1"
@@ -128,6 +127,14 @@ func isRSA(algo string) bool {
return contains(algos, underlyingAlgo(algo))
}

func isRSACert(algo string) bool {
_, ok := certKeyAlgoNames[algo]
if !ok {
return false
}
return isRSA(algo)
}

// supportedPubKeyAuthAlgos specifies the supported client public key
// authentication algorithms. Note that this doesn't include certificate types
// since those use the underlying algorithm. This list is sent to the client if
@@ -140,8 +147,6 @@ var supportedPubKeyAuthAlgos = []string{
KeyAlgoDSA,
}

var supportedPubKeyAuthAlgosList = strings.Join(supportedPubKeyAuthAlgos, ",")

// unexpectedMessageError results when the SSH message that we received didn't
// match what we wanted.
func unexpectedMessageError(expected, got uint8) error {


+ 1
- 0
vendor/golang.org/x/crypto/ssh/doc.go View File

@@ -13,6 +13,7 @@ others.

References:

[PROTOCOL]: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL?rev=HEAD
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1



+ 37
- 14
vendor/golang.org/x/crypto/ssh/handshake.go View File

@@ -11,6 +11,7 @@ import (
"io"
"log"
"net"
"strings"
"sync"
)

@@ -50,6 +51,10 @@ type handshakeTransport struct {
// connection.
hostKeys []Signer

// publicKeyAuthAlgorithms is non-empty if we are the server. In that case,
// it contains the supported client public key authentication algorithms.
publicKeyAuthAlgorithms []string

// hostKeyAlgorithms is non-empty if we are the client. In that case,
// we accept these key types from the server as host key.
hostKeyAlgorithms []string
@@ -141,6 +146,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
t.hostKeys = config.hostKeys
t.publicKeyAuthAlgorithms = config.PublicKeyAuthAlgorithms
go t.readLoop()
go t.kexLoop()
return t
@@ -461,19 +467,24 @@ func (t *handshakeTransport) sendKexInit() error {
isServer := len(t.hostKeys) > 0
if isServer {
for _, k := range t.hostKeys {
// If k is an AlgorithmSigner, presume it supports all signature algorithms
// associated with the key format. (Ideally AlgorithmSigner would have a
// method to advertise supported algorithms, but it doesn't. This means that
// adding support for a new algorithm is a breaking change, as we will
// immediately negotiate it even if existing implementations don't support
// it. If that ever happens, we'll have to figure something out.)
// If k is not an AlgorithmSigner, we can only assume it only supports the
// algorithms that matches the key format. (This means that Sign can't pick
// a different default.)
// If k is a MultiAlgorithmSigner, we restrict the signature
// algorithms. If k is a AlgorithmSigner, presume it supports all
// signature algorithms associated with the key format. If k is not
// an AlgorithmSigner, we can only assume it only supports the
// algorithms that matches the key format. (This means that Sign
// can't pick a different default).
keyFormat := k.PublicKey().Type()
if _, ok := k.(AlgorithmSigner); ok {

switch s := k.(type) {
case MultiAlgorithmSigner:
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if contains(s.Algorithms(), underlyingAlgo(algo)) {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo)
}
}
case AlgorithmSigner:
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...)
} else {
default:
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
}
}
@@ -642,16 +653,21 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {

// On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO
// message with the server-sig-algs extension if the client supports it. See
// RFC 8308, Sections 2.4 and 3.1.
// RFC 8308, Sections 2.4 and 3.1, and [PROTOCOL], Section 1.9.
if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") {
supportedPubKeyAuthAlgosList := strings.Join(t.publicKeyAuthAlgorithms, ",")
extInfo := &extInfoMsg{
NumExtensions: 1,
Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)),
NumExtensions: 2,
Payload: make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)+4+16+4+1),
}
extInfo.Payload = appendInt(extInfo.Payload, len("server-sig-algs"))
extInfo.Payload = append(extInfo.Payload, "server-sig-algs"...)
extInfo.Payload = appendInt(extInfo.Payload, len(supportedPubKeyAuthAlgosList))
extInfo.Payload = append(extInfo.Payload, supportedPubKeyAuthAlgosList...)
extInfo.Payload = appendInt(extInfo.Payload, len("ping@openssh.com"))
extInfo.Payload = append(extInfo.Payload, "ping@openssh.com"...)
extInfo.Payload = appendInt(extInfo.Payload, 1)
extInfo.Payload = append(extInfo.Payload, "0"...)
if err := t.conn.writePacket(Marshal(extInfo)); err != nil {
return err
}
@@ -685,9 +701,16 @@ func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, a

func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
for _, k := range hostKeys {
if s, ok := k.(MultiAlgorithmSigner); ok {
if !contains(s.Algorithms(), underlyingAlgo(algo)) {
continue
}
}

if algo == k.PublicKey().Type() {
return algorithmSignerWrapper{k}
}

k, ok := k.(AlgorithmSigner)
if !ok {
continue


+ 338
- 57
vendor/golang.org/x/crypto/ssh/keys.go View File

@@ -11,13 +11,16 @@ import (
"crypto/cipher"
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/pem"
"errors"
@@ -26,7 +29,6 @@ import (
"math/big"
"strings"

"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
)

@@ -295,6 +297,18 @@ func MarshalAuthorizedKey(key PublicKey) []byte {
return b.Bytes()
}

// MarshalPrivateKey returns a PEM block with the private key serialized in the
// OpenSSH format.
func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error) {
return marshalOpenSSHPrivateKey(key, comment, unencryptedOpenSSHMarshaler)
}

// MarshalPrivateKeyWithPassphrase returns a PEM block holding the encrypted
// private key serialized in the OpenSSH format.
func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error) {
return marshalOpenSSHPrivateKey(key, comment, passphraseProtectedOpenSSHMarshaler(passphrase))
}

// PublicKey represents a public key using an unspecified algorithm.
//
// Some PublicKeys provided by this package also implement CryptoPublicKey.
@@ -321,7 +335,7 @@ type CryptoPublicKey interface {

// A Signer can create signatures that verify against a public key.
//
// Some Signers provided by this package also implement AlgorithmSigner.
// Some Signers provided by this package also implement MultiAlgorithmSigner.
type Signer interface {
// PublicKey returns the associated PublicKey.
PublicKey() PublicKey
@@ -336,9 +350,9 @@ type Signer interface {
// An AlgorithmSigner is a Signer that also supports specifying an algorithm to
// use for signing.
//
// An AlgorithmSigner can't advertise the algorithms it supports, so it should
// be prepared to be invoked with every algorithm supported by the public key
// format.
// An AlgorithmSigner can't advertise the algorithms it supports, unless it also
// implements MultiAlgorithmSigner, so it should be prepared to be invoked with
// every algorithm supported by the public key format.
type AlgorithmSigner interface {
Signer

@@ -349,6 +363,75 @@ type AlgorithmSigner interface {
SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
}

// MultiAlgorithmSigner is an AlgorithmSigner that also reports the algorithms
// supported by that signer.
type MultiAlgorithmSigner interface {
AlgorithmSigner

// Algorithms returns the available algorithms in preference order. The list
// must not be empty, and it must not include certificate types.
Algorithms() []string
}

// NewSignerWithAlgorithms returns a signer restricted to the specified
// algorithms. The algorithms must be set in preference order. The list must not
// be empty, and it must not include certificate types. An error is returned if
// the specified algorithms are incompatible with the public key type.
func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string) (MultiAlgorithmSigner, error) {
if len(algorithms) == 0 {
return nil, errors.New("ssh: please specify at least one valid signing algorithm")
}
var signerAlgos []string
supportedAlgos := algorithmsForKeyFormat(underlyingAlgo(signer.PublicKey().Type()))
if s, ok := signer.(*multiAlgorithmSigner); ok {
signerAlgos = s.Algorithms()
} else {
signerAlgos = supportedAlgos
}

for _, algo := range algorithms {
if !contains(supportedAlgos, algo) {
return nil, fmt.Errorf("ssh: algorithm %q is not supported for key type %q",
algo, signer.PublicKey().Type())
}
if !contains(signerAlgos, algo) {
return nil, fmt.Errorf("ssh: algorithm %q is restricted for the provided signer", algo)
}
}
return &multiAlgorithmSigner{
AlgorithmSigner: signer,
supportedAlgorithms: algorithms,
}, nil
}

type multiAlgorithmSigner struct {
AlgorithmSigner
supportedAlgorithms []string
}

func (s *multiAlgorithmSigner) Algorithms() []string {
return s.supportedAlgorithms
}

func (s *multiAlgorithmSigner) isAlgorithmSupported(algorithm string) bool {
if algorithm == "" {
algorithm = underlyingAlgo(s.PublicKey().Type())
}
for _, algo := range s.supportedAlgorithms {
if algorithm == algo {
return true
}
}
return false
}

func (s *multiAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if !s.isAlgorithmSupported(algorithm) {
return nil, fmt.Errorf("ssh: algorithm %q is not supported: %v", algorithm, s.supportedAlgorithms)
}
return s.AlgorithmSigner.SignWithAlgorithm(rand, data, algorithm)
}

type rsaPublicKey rsa.PublicKey

func (r *rsaPublicKey) Type() string {
@@ -512,6 +595,10 @@ func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
return k.SignWithAlgorithm(rand, data, k.PublicKey().Type())
}

func (k *dsaPrivateKey) Algorithms() []string {
return []string{k.PublicKey().Type()}
}

func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm != "" && algorithm != k.PublicKey().Type() {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
@@ -961,13 +1048,16 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.SignWithAlgorithm(rand, data, s.pubKey.Type())
}

func (s *wrappedSigner) Algorithms() []string {
return algorithmsForKeyFormat(s.pubKey.Type())
}

func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm == "" {
algorithm = s.pubKey.Type()
}

supportedAlgos := algorithmsForKeyFormat(s.pubKey.Type())
if !contains(supportedAlgos, algorithm) {
if !contains(s.Algorithms(), algorithm) {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
}

@@ -1142,16 +1232,27 @@ func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{},
return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err)
}

var result interface{}

switch block.Type {
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(buf)
result, err = x509.ParsePKCS1PrivateKey(buf)
case "EC PRIVATE KEY":
return x509.ParseECPrivateKey(buf)
result, err = x509.ParseECPrivateKey(buf)
case "DSA PRIVATE KEY":
return ParseDSAPrivateKey(buf)
result, err = ParseDSAPrivateKey(buf)
default:
return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
err = fmt.Errorf("ssh: unsupported key type %q", block.Type)
}
// Because of deficiencies in the format, DecryptPEMBlock does not always
// detect an incorrect password. In these cases decrypted DER bytes is
// random noise. If the parsing of the key returns an asn1.StructuralError
// we return x509.IncorrectPasswordError.
if _, ok := err.(asn1.StructuralError); ok {
return nil, x509.IncorrectPasswordError
}

return result, err
}

// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
@@ -1241,28 +1342,106 @@ func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
}
}

func unencryptedOpenSSHMarshaler(privKeyBlock []byte) ([]byte, string, string, string, error) {
key := generateOpenSSHPadding(privKeyBlock, 8)
return key, "none", "none", "", nil
}

func passphraseProtectedOpenSSHMarshaler(passphrase []byte) openSSHEncryptFunc {
return func(privKeyBlock []byte) ([]byte, string, string, string, error) {
salt := make([]byte, 16)
if _, err := rand.Read(salt); err != nil {
return nil, "", "", "", err
}

opts := struct {
Salt []byte
Rounds uint32
}{salt, 16}

// Derive key to encrypt the private key block.
k, err := bcrypt_pbkdf.Key(passphrase, salt, int(opts.Rounds), 32+aes.BlockSize)
if err != nil {
return nil, "", "", "", err
}

// Add padding matching the block size of AES.
keyBlock := generateOpenSSHPadding(privKeyBlock, aes.BlockSize)

// Encrypt the private key using the derived secret.

dst := make([]byte, len(keyBlock))
key, iv := k[:32], k[32:]
block, err := aes.NewCipher(key)
if err != nil {
return nil, "", "", "", err
}

stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(dst, keyBlock)

return dst, "aes256-ctr", "bcrypt", string(Marshal(opts)), nil
}
}

const privateKeyAuthMagic = "openssh-key-v1\x00"

type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error)
type openSSHEncryptFunc func(PrivKeyBlock []byte) (ProtectedKeyBlock []byte, cipherName, kdfName, kdfOptions string, err error)

type openSSHEncryptedPrivateKey struct {
CipherName string
KdfName string
KdfOpts string
NumKeys uint32
PubKey []byte
PrivKeyBlock []byte
}

type openSSHPrivateKey struct {
Check1 uint32
Check2 uint32
Keytype string
Rest []byte `ssh:"rest"`
}

type openSSHRSAPrivateKey struct {
N *big.Int
E *big.Int
D *big.Int
Iqmp *big.Int
P *big.Int
Q *big.Int
Comment string
Pad []byte `ssh:"rest"`
}

type openSSHEd25519PrivateKey struct {
Pub []byte
Priv []byte
Comment string
Pad []byte `ssh:"rest"`
}

type openSSHECDSAPrivateKey struct {
Curve string
Pub []byte
D *big.Int
Comment string
Pad []byte `ssh:"rest"`
}

// parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt
// function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used
// as the decrypt function to parse an unencrypted private key. See
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key.
func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) {
const magic = "openssh-key-v1\x00"
if len(key) < len(magic) || string(key[:len(magic)]) != magic {
if len(key) < len(privateKeyAuthMagic) || string(key[:len(privateKeyAuthMagic)]) != privateKeyAuthMagic {
return nil, errors.New("ssh: invalid openssh private key format")
}
remaining := key[len(magic):]

var w struct {
CipherName string
KdfName string
KdfOpts string
NumKeys uint32
PubKey []byte
PrivKeyBlock []byte
}
remaining := key[len(privateKeyAuthMagic):]

var w openSSHEncryptedPrivateKey
if err := Unmarshal(remaining, &w); err != nil {
return nil, err
}
@@ -1284,13 +1463,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
return nil, err
}

pk1 := struct {
Check1 uint32
Check2 uint32
Keytype string
Rest []byte `ssh:"rest"`
}{}

var pk1 openSSHPrivateKey
if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 {
if w.CipherName != "none" {
return nil, x509.IncorrectPasswordError
@@ -1300,18 +1473,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv

switch pk1.Keytype {
case KeyAlgoRSA:
// https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773
key := struct {
N *big.Int
E *big.Int
D *big.Int
Iqmp *big.Int
P *big.Int
Q *big.Int
Comment string
Pad []byte `ssh:"rest"`
}{}

var key openSSHRSAPrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
@@ -1337,13 +1499,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv

return pk, nil
case KeyAlgoED25519:
key := struct {
Pub []byte
Priv []byte
Comment string
Pad []byte `ssh:"rest"`
}{}

var key openSSHEd25519PrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
@@ -1360,14 +1516,7 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
copy(pk, key.Priv)
return &pk, nil
case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
key := struct {
Curve string
Pub []byte
D *big.Int
Comment string
Pad []byte `ssh:"rest"`
}{}

var key openSSHECDSAPrivateKey
if err := Unmarshal(pk1.Rest, &key); err != nil {
return nil, err
}
@@ -1415,6 +1564,131 @@ func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.Priv
}
}

func marshalOpenSSHPrivateKey(key crypto.PrivateKey, comment string, encrypt openSSHEncryptFunc) (*pem.Block, error) {
var w openSSHEncryptedPrivateKey
var pk1 openSSHPrivateKey

// Random check bytes.
var check uint32
if err := binary.Read(rand.Reader, binary.BigEndian, &check); err != nil {
return nil, err
}

pk1.Check1 = check
pk1.Check2 = check
w.NumKeys = 1

// Use a []byte directly on ed25519 keys.
if k, ok := key.(*ed25519.PrivateKey); ok {
key = *k
}

switch k := key.(type) {
case *rsa.PrivateKey:
E := new(big.Int).SetInt64(int64(k.PublicKey.E))
// Marshal public key:
// E and N are in reversed order in the public and private key.
pubKey := struct {
KeyType string
E *big.Int
N *big.Int
}{
KeyAlgoRSA,
E, k.PublicKey.N,
}
w.PubKey = Marshal(pubKey)

// Marshal private key.
key := openSSHRSAPrivateKey{
N: k.PublicKey.N,
E: E,
D: k.D,
Iqmp: k.Precomputed.Qinv,
P: k.Primes[0],
Q: k.Primes[1],
Comment: comment,
}
pk1.Keytype = KeyAlgoRSA
pk1.Rest = Marshal(key)
case ed25519.PrivateKey:
pub := make([]byte, ed25519.PublicKeySize)
priv := make([]byte, ed25519.PrivateKeySize)
copy(pub, k[32:])
copy(priv, k)

// Marshal public key.
pubKey := struct {
KeyType string
Pub []byte
}{
KeyAlgoED25519, pub,
}
w.PubKey = Marshal(pubKey)

// Marshal private key.
key := openSSHEd25519PrivateKey{
Pub: pub,
Priv: priv,
Comment: comment,
}
pk1.Keytype = KeyAlgoED25519
pk1.Rest = Marshal(key)
case *ecdsa.PrivateKey:
var curve, keyType string
switch name := k.Curve.Params().Name; name {
case "P-256":
curve = "nistp256"
keyType = KeyAlgoECDSA256
case "P-384":
curve = "nistp384"
keyType = KeyAlgoECDSA384
case "P-521":
curve = "nistp521"
keyType = KeyAlgoECDSA521
default:
return nil, errors.New("ssh: unhandled elliptic curve " + name)
}

pub := elliptic.Marshal(k.Curve, k.PublicKey.X, k.PublicKey.Y)

// Marshal public key.
pubKey := struct {
KeyType string
Curve string
Pub []byte
}{
keyType, curve, pub,
}
w.PubKey = Marshal(pubKey)

// Marshal private key.
key := openSSHECDSAPrivateKey{
Curve: curve,
Pub: pub,
D: k.D,
Comment: comment,
}
pk1.Keytype = keyType
pk1.Rest = Marshal(key)
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", k)
}

var err error
// Add padding and encrypt the key if necessary.
w.PrivKeyBlock, w.CipherName, w.KdfName, w.KdfOpts, err = encrypt(Marshal(pk1))
if err != nil {
return nil, err
}

b := Marshal(w)
block := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: append([]byte(privateKeyAuthMagic), b...),
}
return block, nil
}

func checkOpenSSHKeyPadding(pad []byte) error {
for i, b := range pad {
if int(b) != i+1 {
@@ -1424,6 +1698,13 @@ func checkOpenSSHKeyPadding(pad []byte) error {
return nil
}

func generateOpenSSHPadding(block []byte, blockSize int) []byte {
for i, l := 0, len(block); (l+i)%blockSize != 0; i++ {
block = append(block, byte(i+1))
}
return block
}

// FingerprintLegacyMD5 returns the user presentation of the key's
// fingerprint as described by RFC 4716 section 4.
func FingerprintLegacyMD5(pubKey PublicKey) string {


+ 14
- 0
vendor/golang.org/x/crypto/ssh/messages.go View File

@@ -349,6 +349,20 @@ type userAuthGSSAPIError struct {
LanguageTag string
}

// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPing = 192

type pingMsg struct {
Data string `sshtype:"192"`
}

// Transport layer OpenSSH extension. See [PROTOCOL], section 1.9
const msgPong = 193

type pongMsg struct {
Data string `sshtype:"193"`
}

// typeTags returns the possible type bytes for the given reflect.Type, which
// should be a struct. The possible values are separated by a '|' character.
func typeTags(structType reflect.Type) (tags []byte) {


+ 6
- 0
vendor/golang.org/x/crypto/ssh/mux.go View File

@@ -231,6 +231,12 @@ func (m *mux) onePacket() error {
return m.handleChannelOpen(packet)
case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
return m.handleGlobalPacket(packet)
case msgPing:
var msg pingMsg
if err := Unmarshal(packet, &msg); err != nil {
return fmt.Errorf("failed to unmarshal ping@openssh.com message: %w", err)
}
return m.sendMessage(pongMsg(msg))
}

// assume a channel packet.


+ 31
- 5
vendor/golang.org/x/crypto/ssh/server.go View File

@@ -64,6 +64,13 @@ type ServerConfig struct {
// Config contains configuration shared between client and server.
Config

// PublicKeyAuthAlgorithms specifies the supported client public key
// authentication algorithms. Note that this should not include certificate
// types since those use the underlying algorithm. This list is sent to the
// client if it supports the server-sig-algs extension. Order is irrelevant.
// If unspecified then a default set of algorithms is used.
PublicKeyAuthAlgorithms []string

hostKeys []Signer

// NoClientAuth is true if clients are allowed to connect without
@@ -201,6 +208,15 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
if fullConf.MaxAuthTries == 0 {
fullConf.MaxAuthTries = 6
}
if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
} else {
for _, algo := range fullConf.PublicKeyAuthAlgorithms {
if !contains(supportedPubKeyAuthAlgos, algo) {
return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
}
}
}
// Check if the config contains any unsupported key exchanges
for _, kex := range fullConf.KeyExchanges {
if _, ok := serverForbiddenKexAlgos[kex]; ok {
@@ -321,7 +337,7 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
}

func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
gssAPIServer := gssapiConfig.Server
defer gssAPIServer.DeleteSecContext()
@@ -331,7 +347,7 @@ func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *c
outToken []byte
needContinue bool
)
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
if err != nil {
return err, nil, nil
}
@@ -353,6 +369,7 @@ func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *c
if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
return nil, nil, err
}
token = userAuthGSSAPITokenReq.Token
}
packet, err := s.transport.readPacket()
if err != nil {
@@ -524,7 +541,7 @@ userAuthLoop:
return nil, parseError(msgUserAuthRequest)
}
algo := string(algoBytes)
if !contains(supportedPubKeyAuthAlgos, underlyingAlgo(algo)) {
if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
break
}
@@ -576,13 +593,22 @@ userAuthLoop:
if !ok || len(payload) > 0 {
return nil, parseError(msgUserAuthRequest)
}

// Ensure the declared public key algo is compatible with the
// decoded one. This check will ensure we don't accept e.g.
// ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public
// key type. The algorithm and public key type must be
// consistent: both must be certificate algorithms, or neither.
if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
pubKey.Type(), algo)
break
}
// Ensure the public key algo and signature algo
// are supported. Compare the private key
// algorithm name that corresponds to algo with
// sig.Format. This is usually the same, but
// for certs, the names differ.
if !contains(supportedPubKeyAuthAlgos, sig.Format) {
if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
break
}


+ 35
- 0
vendor/golang.org/x/crypto/ssh/tcpip.go View File

@@ -5,6 +5,7 @@
package ssh

import (
"context"
"errors"
"fmt"
"io"
@@ -332,6 +333,40 @@ func (l *tcpListener) Addr() net.Addr {
return l.laddr
}

// DialContext initiates a connection to the addr from the remote host.
//
// The provided Context must be non-nil. If the context expires before the
// connection is complete, an error is returned. Once successfully connected,
// any expiration of the context will not affect the connection.
//
// See func Dial for additional information.
func (c *Client) DialContext(ctx context.Context, n, addr string) (net.Conn, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
type connErr struct {
conn net.Conn
err error
}
ch := make(chan connErr)
go func() {
conn, err := c.Dial(n, addr)
select {
case ch <- connErr{conn, err}:
case <-ctx.Done():
if conn != nil {
conn.Close()
}
}
}()
select {
case res := <-ch:
return res.conn, res.err
case <-ctx.Done():
return nil, ctx.Err()
}
}

// Dial initiates a connection to the addr from the remote host.
// The resulting connection has a zero LocalAddr() and RemoteAddr().
func (c *Client) Dial(n, addr string) (net.Conn, error) {


+ 27
- 0
vendor/golang.org/x/exp/LICENSE View File

@@ -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.

+ 22
- 0
vendor/golang.org/x/exp/PATENTS View File

@@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)

"This implementation" means the copyrightable works distributed by
Google as part of the Go project.

Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

+ 50
- 0
vendor/golang.org/x/exp/constraints/constraints.go View File

@@ -0,0 +1,50 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package constraints defines a set of useful constraints to be used
// with type parameters.
package constraints

// Signed is a constraint that permits any signed integer type.
// If future releases of Go add new predeclared signed integer types,
// this constraint will be modified to include them.
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}

// Unsigned is a constraint that permits any unsigned integer type.
// If future releases of Go add new predeclared unsigned integer types,
// this constraint will be modified to include them.
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

// Integer is a constraint that permits any integer type.
// If future releases of Go add new predeclared integer types,
// this constraint will be modified to include them.
type Integer interface {
Signed | Unsigned
}

// Float is a constraint that permits any floating-point type.
// If future releases of Go add new predeclared floating-point types,
// this constraint will be modified to include them.
type Float interface {
~float32 | ~float64
}

// Complex is a constraint that permits any complex numeric type.
// If future releases of Go add new predeclared complex numeric types,
// this constraint will be modified to include them.
type Complex interface {
~complex64 | ~complex128
}

// Ordered is a constraint that permits any ordered type: any type
// that supports the operators < <= >= >.
// If future releases of Go add new ordered types,
// this constraint will be modified to include them.
type Ordered interface {
Integer | Float | ~string
}

+ 44
- 0
vendor/golang.org/x/exp/slices/cmp.go View File

@@ -0,0 +1,44 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package slices

import "golang.org/x/exp/constraints"

// min is a version of the predeclared function from the Go 1.21 release.
func min[T constraints.Ordered](a, b T) T {
if a < b || isNaN(a) {
return a
}
return b
}

// max is a version of the predeclared function from the Go 1.21 release.
func max[T constraints.Ordered](a, b T) T {
if a > b || isNaN(a) {
return a
}
return b
}

// cmpLess is a copy of cmp.Less from the Go 1.21 release.
func cmpLess[T constraints.Ordered](x, y T) bool {
return (isNaN(x) && !isNaN(y)) || x < y
}

// cmpCompare is a copy of cmp.Compare from the Go 1.21 release.
func cmpCompare[T constraints.Ordered](x, y T) int {
xNaN := isNaN(x)
yNaN := isNaN(y)
if xNaN && yNaN {
return 0
}
if xNaN || x < y {
return -1
}
if yNaN || x > y {
return +1
}
return 0
}

+ 499
- 0
vendor/golang.org/x/exp/slices/slices.go View File

@@ -0,0 +1,499 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package slices defines various functions useful with slices of any type.
package slices

import (
"unsafe"

"golang.org/x/exp/constraints"
)

// Equal reports whether two slices are equal: the same length and all
// elements equal. If the lengths are different, Equal returns false.
// Otherwise, the elements are compared in increasing index order, and the
// comparison stops at the first unequal pair.
// Floating point NaNs are not considered equal.
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
if len(s1) != len(s2) {
return false
}
for i := range s1 {
if s1[i] != s2[i] {
return false
}
}
return true
}

// EqualFunc reports whether two slices are equal using an equality
// function on each pair of elements. If the lengths are different,
// EqualFunc returns false. Otherwise, the elements are compared in
// increasing index order, and the comparison stops at the first index
// for which eq returns false.
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
if len(s1) != len(s2) {
return false
}
for i, v1 := range s1 {
v2 := s2[i]
if !eq(v1, v2) {
return false
}
}
return true
}

// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
// of elements. The elements are compared sequentially, starting at index 0,
// until one element is not equal to the other.
// The result of comparing the first non-matching elements is returned.
// If both slices are equal until one of them ends, the shorter slice is
// considered less than the longer one.
// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int {
for i, v1 := range s1 {
if i >= len(s2) {
return +1
}
v2 := s2[i]
if c := cmpCompare(v1, v2); c != 0 {
return c
}
}
if len(s1) < len(s2) {
return -1
}
return 0
}

// CompareFunc is like [Compare] but uses a custom comparison function on each
// pair of elements.
// The result is the first non-zero result of cmp; if cmp always
// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
// and +1 if len(s1) > len(s2).
func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
for i, v1 := range s1 {
if i >= len(s2) {
return +1
}
v2 := s2[i]
if c := cmp(v1, v2); c != 0 {
return c
}
}
if len(s1) < len(s2) {
return -1
}
return 0
}

// Index returns the index of the first occurrence of v in s,
// or -1 if not present.
func Index[S ~[]E, E comparable](s S, v E) int {
for i := range s {
if v == s[i] {
return i
}
}
return -1
}

// IndexFunc returns the first index i satisfying f(s[i]),
// or -1 if none do.
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
for i := range s {
if f(s[i]) {
return i
}
}
return -1
}

// Contains reports whether v is present in s.
func Contains[S ~[]E, E comparable](s S, v E) bool {
return Index(s, v) >= 0
}

// ContainsFunc reports whether at least one
// element e of s satisfies f(e).
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
return IndexFunc(s, f) >= 0
}

// Insert inserts the values v... into s at index i,
// returning the modified slice.
// The elements at s[i:] are shifted up to make room.
// In the returned slice r, r[i] == v[0],
// and r[i+len(v)] == value originally at r[i].
// Insert panics if i is out of range.
// This function is O(len(s) + len(v)).
func Insert[S ~[]E, E any](s S, i int, v ...E) S {
m := len(v)
if m == 0 {
return s
}
n := len(s)
if i == n {
return append(s, v...)
}
if n+m > cap(s) {
// Use append rather than make so that we bump the size of
// the slice up to the next storage class.
// This is what Grow does but we don't call Grow because
// that might copy the values twice.
s2 := append(s[:i], make(S, n+m-i)...)
copy(s2[i:], v)
copy(s2[i+m:], s[i:])
return s2
}
s = s[:n+m]

// before:
// s: aaaaaaaabbbbccccccccdddd
// ^ ^ ^ ^
// i i+m n n+m
// after:
// s: aaaaaaaavvvvbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
//
// a are the values that don't move in s.
// v are the values copied in from v.
// b and c are the values from s that are shifted up in index.
// d are the values that get overwritten, never to be seen again.

if !overlaps(v, s[i+m:]) {
// Easy case - v does not overlap either the c or d regions.
// (It might be in some of a or b, or elsewhere entirely.)
// The data we copy up doesn't write to v at all, so just do it.

copy(s[i+m:], s[i:])

// Now we have
// s: aaaaaaaabbbbbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
// Note the b values are duplicated.

copy(s[i:], v)

// Now we have
// s: aaaaaaaavvvvbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
// That's the result we want.
return s
}

// The hard case - v overlaps c or d. We can't just shift up
// the data because we'd move or clobber the values we're trying
// to insert.
// So instead, write v on top of d, then rotate.
copy(s[n:], v)

// Now we have
// s: aaaaaaaabbbbccccccccvvvv
// ^ ^ ^ ^
// i i+m n n+m

rotateRight(s[i:], m)

// Now we have
// s: aaaaaaaavvvvbbbbcccccccc
// ^ ^ ^ ^
// i i+m n n+m
// That's the result we want.
return s
}

// Delete removes the elements s[i:j] from s, returning the modified slice.
// Delete panics if s[i:j] is not a valid slice of s.
// Delete is O(len(s)-j), so if many items must be deleted, it is better to
// make a single call deleting them all together than to delete one at a time.
// Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those
// elements contain pointers you might consider zeroing those elements so that
// objects they reference can be garbage collected.
func Delete[S ~[]E, E any](s S, i, j int) S {
_ = s[i:j] // bounds check

return append(s[:i], s[j:]...)
}

// DeleteFunc removes any elements from s for which del returns true,
// returning the modified slice.
// When DeleteFunc removes m elements, it might not modify the elements
// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
// zeroing those elements so that objects they reference can be garbage
// collected.
func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
i := IndexFunc(s, del)
if i == -1 {
return s
}
// Don't start copying elements until we find one to delete.
for j := i + 1; j < len(s); j++ {
if v := s[j]; !del(v) {
s[i] = v
i++
}
}
return s[:i]
}

// Replace replaces the elements s[i:j] by the given v, and returns the
// modified slice. Replace panics if s[i:j] is not a valid slice of s.
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
_ = s[i:j] // verify that i:j is a valid subslice

if i == j {
return Insert(s, i, v...)
}
if j == len(s) {
return append(s[:i], v...)
}

tot := len(s[:i]) + len(v) + len(s[j:])
if tot > cap(s) {
// Too big to fit, allocate and copy over.
s2 := append(s[:i], make(S, tot-i)...) // See Insert
copy(s2[i:], v)
copy(s2[i+len(v):], s[j:])
return s2
}

r := s[:tot]

if i+len(v) <= j {
// Easy, as v fits in the deleted portion.
copy(r[i:], v)
if i+len(v) != j {
copy(r[i+len(v):], s[j:])
}
return r
}

// We are expanding (v is bigger than j-i).
// The situation is something like this:
// (example has i=4,j=8,len(s)=16,len(v)=6)
// s: aaaaxxxxbbbbbbbbyy
// ^ ^ ^ ^
// i j len(s) tot
// a: prefix of s
// x: deleted range
// b: more of s
// y: area to expand into

if !overlaps(r[i+len(v):], v) {
// Easy, as v is not clobbered by the first copy.
copy(r[i+len(v):], s[j:])
copy(r[i:], v)
return r
}

// This is a situation where we don't have a single place to which
// we can copy v. Parts of it need to go to two different places.
// We want to copy the prefix of v into y and the suffix into x, then
// rotate |y| spots to the right.
//
// v[2:] v[:2]
// | |
// s: aaaavvvvbbbbbbbbvv
// ^ ^ ^ ^
// i j len(s) tot
//
// If either of those two destinations don't alias v, then we're good.
y := len(v) - (j - i) // length of y portion

if !overlaps(r[i:j], v) {
copy(r[i:j], v[y:])
copy(r[len(s):], v[:y])
rotateRight(r[i:], y)
return r
}
if !overlaps(r[len(s):], v) {
copy(r[len(s):], v[:y])
copy(r[i:j], v[y:])
rotateRight(r[i:], y)
return r
}

// Now we know that v overlaps both x and y.
// That means that the entirety of b is *inside* v.
// So we don't need to preserve b at all; instead we
// can copy v first, then copy the b part of v out of
// v to the right destination.
k := startIdx(v, s[j:])
copy(r[i:], v)
copy(r[i+len(v):], r[i+k:])
return r
}

// Clone returns a copy of the slice.
// The elements are copied using assignment, so this is a shallow clone.
func Clone[S ~[]E, E any](s S) S {
// Preserve nil in case it matters.
if s == nil {
return nil
}
return append(S([]E{}), s...)
}

// Compact replaces consecutive runs of equal elements with a single copy.
// This is like the uniq command found on Unix.
// Compact modifies the contents of the slice s and returns the modified slice,
// which may have a smaller length.
// When Compact discards m elements in total, it might not modify the elements
// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
// zeroing those elements so that objects they reference can be garbage collected.
func Compact[S ~[]E, E comparable](s S) S {
if len(s) < 2 {
return s
}
i := 1
for k := 1; k < len(s); k++ {
if s[k] != s[k-1] {
if i != k {
s[i] = s[k]
}
i++
}
}
return s[:i]
}

// CompactFunc is like [Compact] but uses an equality function to compare elements.
// For runs of elements that compare equal, CompactFunc keeps the first one.
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
if len(s) < 2 {
return s
}
i := 1
for k := 1; k < len(s); k++ {
if !eq(s[k], s[k-1]) {
if i != k {
s[i] = s[k]
}
i++
}
}
return s[:i]
}

// Grow increases the slice's capacity, if necessary, to guarantee space for
// another n elements. After Grow(n), at least n elements can be appended
// to the slice without another allocation. If n is negative or too large to
// allocate the memory, Grow panics.
func Grow[S ~[]E, E any](s S, n int) S {
if n < 0 {
panic("cannot be negative")
}
if n -= cap(s) - len(s); n > 0 {
// TODO(https://go.dev/issue/53888): Make using []E instead of S
// to workaround a compiler bug where the runtime.growslice optimization
// does not take effect. Revert when the compiler is fixed.
s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)]
}
return s
}

// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
func Clip[S ~[]E, E any](s S) S {
return s[:len(s):len(s)]
}

// Rotation algorithm explanation:
//
// rotate left by 2
// start with
// 0123456789
// split up like this
// 01 234567 89
// swap first 2 and last 2
// 89 234567 01
// join first parts
// 89234567 01
// recursively rotate first left part by 2
// 23456789 01
// join at the end
// 2345678901
//
// rotate left by 8
// start with
// 0123456789
// split up like this
// 01 234567 89
// swap first 2 and last 2
// 89 234567 01
// join last parts
// 89 23456701
// recursively rotate second part left by 6
// 89 01234567
// join at the end
// 8901234567

// TODO: There are other rotate algorithms.
// This algorithm has the desirable property that it moves each element exactly twice.
// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes.
// The follow-cycles algorithm can be 1-write but it is not very cache friendly.

// rotateLeft rotates b left by n spaces.
// s_final[i] = s_orig[i+r], wrapping around.
func rotateLeft[E any](s []E, r int) {
for r != 0 && r != len(s) {
if r*2 <= len(s) {
swap(s[:r], s[len(s)-r:])
s = s[:len(s)-r]
} else {
swap(s[:len(s)-r], s[r:])
s, r = s[len(s)-r:], r*2-len(s)
}
}
}
func rotateRight[E any](s []E, r int) {
rotateLeft(s, len(s)-r)
}

// swap swaps the contents of x and y. x and y must be equal length and disjoint.
func swap[E any](x, y []E) {
for i := 0; i < len(x); i++ {
x[i], y[i] = y[i], x[i]
}
}

// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
func overlaps[E any](a, b []E) bool {
if len(a) == 0 || len(b) == 0 {
return false
}
elemSize := unsafe.Sizeof(a[0])
if elemSize == 0 {
return false
}
// TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.
// Also see crypto/internal/alias/alias.go:AnyOverlap
return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) &&
uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1)
}

// startIdx returns the index in haystack where the needle starts.
// prerequisite: the needle must be aliased entirely inside the haystack.
func startIdx[E any](haystack, needle []E) int {
p := &needle[0]
for i := range haystack {
if p == &haystack[i] {
return i
}
}
// TODO: what if the overlap is by a non-integral number of Es?
panic("needle not found")
}

// Reverse reverses the elements of the slice in place.
func Reverse[S ~[]E, E any](s S) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}

+ 195
- 0
vendor/golang.org/x/exp/slices/sort.go View File

@@ -0,0 +1,195 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -exp

package slices

import (
"math/bits"

"golang.org/x/exp/constraints"
)

// Sort sorts a slice of any ordered type in ascending order.
// When sorting floating-point numbers, NaNs are ordered before other values.
func Sort[S ~[]E, E constraints.Ordered](x S) {
n := len(x)
pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
}

// SortFunc sorts the slice x in ascending order as determined by the cmp
// function. This sort is not guaranteed to be stable.
// cmp(a, b) should return a negative number when a < b, a positive number when
// a > b and zero when a == b.
//
// SortFunc requires that cmp is a strict weak ordering.
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
n := len(x)
pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
}

// SortStableFunc sorts the slice x while keeping the original order of equal
// elements, using cmp to compare elements in the same way as [SortFunc].
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
stableCmpFunc(x, len(x), cmp)
}

// IsSorted reports whether x is sorted in ascending order.
func IsSorted[S ~[]E, E constraints.Ordered](x S) bool {
for i := len(x) - 1; i > 0; i-- {
if cmpLess(x[i], x[i-1]) {
return false
}
}
return true
}

// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
// comparison function as defined by [SortFunc].
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
for i := len(x) - 1; i > 0; i-- {
if cmp(x[i], x[i-1]) < 0 {
return false
}
}
return true
}

// Min returns the minimal value in x. It panics if x is empty.
// For floating-point numbers, Min propagates NaNs (any NaN value in x
// forces the output to be NaN).
func Min[S ~[]E, E constraints.Ordered](x S) E {
if len(x) < 1 {
panic("slices.Min: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
m = min(m, x[i])
}
return m
}

// MinFunc returns the minimal value in x, using cmp to compare elements.
// It panics if x is empty. If there is more than one minimal element
// according to the cmp function, MinFunc returns the first one.
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
if len(x) < 1 {
panic("slices.MinFunc: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
if cmp(x[i], m) < 0 {
m = x[i]
}
}
return m
}

// Max returns the maximal value in x. It panics if x is empty.
// For floating-point E, Max propagates NaNs (any NaN value in x
// forces the output to be NaN).
func Max[S ~[]E, E constraints.Ordered](x S) E {
if len(x) < 1 {
panic("slices.Max: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
m = max(m, x[i])
}
return m
}

// MaxFunc returns the maximal value in x, using cmp to compare elements.
// It panics if x is empty. If there is more than one maximal element
// according to the cmp function, MaxFunc returns the first one.
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
if len(x) < 1 {
panic("slices.MaxFunc: empty list")
}
m := x[0]
for i := 1; i < len(x); i++ {
if cmp(x[i], m) > 0 {
m = x[i]
}
}
return m
}

// BinarySearch searches for target in a sorted slice and returns the position
// where target is found, or the position where target would appear in the
// sort order; it also returns a bool saying whether the target is really found
// in the slice. The slice must be sorted in increasing order.
func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) {
// Inlining is faster than calling BinarySearchFunc with a lambda.
n := len(x)
// Define x[-1] < target and x[n] >= target.
// Invariant: x[i-1] < target, x[j] >= target.
i, j := 0, n
for i < j {
h := int(uint(i+j) >> 1) // avoid overflow when computing h
// i ≤ h < j
if cmpLess(x[h], target) {
i = h + 1 // preserves x[i-1] < target
} else {
j = h // preserves x[j] >= target
}
}
// i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
}

// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
// function. The slice must be sorted in increasing order, where "increasing"
// is defined by cmp. cmp should return 0 if the slice element matches
// the target, a negative number if the slice element precedes the target,
// or a positive number if the slice element follows the target.
// cmp must implement the same ordering as the slice, such that if
// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
n := len(x)
// Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
// Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
i, j := 0, n
for i < j {
h := int(uint(i+j) >> 1) // avoid overflow when computing h
// i ≤ h < j
if cmp(x[h], target) < 0 {
i = h + 1 // preserves cmp(x[i - 1], target) < 0
} else {
j = h // preserves cmp(x[j], target) >= 0
}
}
// i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i.
return i, i < n && cmp(x[i], target) == 0
}

type sortedHint int // hint for pdqsort when choosing the pivot

const (
unknownHint sortedHint = iota
increasingHint
decreasingHint
)

// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
type xorshift uint64

func (r *xorshift) Next() uint64 {
*r ^= *r << 13
*r ^= *r >> 17
*r ^= *r << 5
return uint64(*r)
}

func nextPowerOfTwo(length int) uint {
return 1 << bits.Len(uint(length))
}

// isNaN reports whether x is a NaN without requiring the math package.
// This will always return false if T is not floating-point.
func isNaN[T constraints.Ordered](x T) bool {
return x != x
}

+ 479
- 0
vendor/golang.org/x/exp/slices/zsortanyfunc.go View File

@@ -0,0 +1,479 @@
// Code generated by gen_sort_variants.go; DO NOT EDIT.

// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package slices

// insertionSortCmpFunc sorts data[a:b] using insertion sort.
func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
for i := a + 1; i < b; i++ {
for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
data[j], data[j-1] = data[j-1], data[j]
}
}
}

// siftDownCmpFunc implements the heap property on data[lo:hi].
// first is an offset into the array where the root of the heap lies.
func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
root := lo
for {
child := 2*root + 1
if child >= hi {
break
}
if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
child++
}
if !(cmp(data[first+root], data[first+child]) < 0) {
return
}
data[first+root], data[first+child] = data[first+child], data[first+root]
root = child
}
}

func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
first := a
lo := 0
hi := b - a

// Build heap with greatest element at top.
for i := (hi - 1) / 2; i >= 0; i-- {
siftDownCmpFunc(data, i, hi, first, cmp)
}

// Pop elements, largest first, into end of data.
for i := hi - 1; i >= 0; i-- {
data[first], data[first+i] = data[first+i], data[first]
siftDownCmpFunc(data, lo, i, first, cmp)
}
}

// pdqsortCmpFunc sorts data[a:b].
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
// C++ implementation: https://github.com/orlp/pdqsort
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
const maxInsertion = 12

var (
wasBalanced = true // whether the last partitioning was reasonably balanced
wasPartitioned = true // whether the slice was already partitioned
)

for {
length := b - a

if length <= maxInsertion {
insertionSortCmpFunc(data, a, b, cmp)
return
}

// Fall back to heapsort if too many bad choices were made.
if limit == 0 {
heapSortCmpFunc(data, a, b, cmp)
return
}

// If the last partitioning was imbalanced, we need to breaking patterns.
if !wasBalanced {
breakPatternsCmpFunc(data, a, b, cmp)
limit--
}

pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
if hint == decreasingHint {
reverseRangeCmpFunc(data, a, b, cmp)
// The chosen pivot was pivot-a elements after the start of the array.
// After reversing it is pivot-a elements before the end of the array.
// The idea came from Rust's implementation.
pivot = (b - 1) - (pivot - a)
hint = increasingHint
}

// The slice is likely already sorted.
if wasBalanced && wasPartitioned && hint == increasingHint {
if partialInsertionSortCmpFunc(data, a, b, cmp) {
return
}
}

// Probably the slice contains many duplicate elements, partition the slice into
// elements equal to and elements greater than the pivot.
if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
a = mid
continue
}

mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
wasPartitioned = alreadyPartitioned

leftLen, rightLen := mid-a, b-mid
balanceThreshold := length / 8
if leftLen < rightLen {
wasBalanced = leftLen >= balanceThreshold
pdqsortCmpFunc(data, a, mid, limit, cmp)
a = mid + 1
} else {
wasBalanced = rightLen >= balanceThreshold
pdqsortCmpFunc(data, mid+1, b, limit, cmp)
b = mid
}
}
}

// partitionCmpFunc does one quicksort partition.
// Let p = data[pivot]
// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
// On return, data[newpivot] = p
func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
data[a], data[pivot] = data[pivot], data[a]
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned

for i <= j && (cmp(data[i], data[a]) < 0) {
i++
}
for i <= j && !(cmp(data[j], data[a]) < 0) {
j--
}
if i > j {
data[j], data[a] = data[a], data[j]
return j, true
}
data[i], data[j] = data[j], data[i]
i++
j--

for {
for i <= j && (cmp(data[i], data[a]) < 0) {
i++
}
for i <= j && !(cmp(data[j], data[a]) < 0) {
j--
}
if i > j {
break
}
data[i], data[j] = data[j], data[i]
i++
j--
}
data[j], data[a] = data[a], data[j]
return j, false
}

// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
data[a], data[pivot] = data[pivot], data[a]
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned

for {
for i <= j && !(cmp(data[a], data[i]) < 0) {
i++
}
for i <= j && (cmp(data[a], data[j]) < 0) {
j--
}
if i > j {
break
}
data[i], data[j] = data[j], data[i]
i++
j--
}
return i
}

// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
const (
maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
shortestShifting = 50 // don't shift any elements on short arrays
)
i := a + 1
for j := 0; j < maxSteps; j++ {
for i < b && !(cmp(data[i], data[i-1]) < 0) {
i++
}

if i == b {
return true
}

if b-a < shortestShifting {
return false
}

data[i], data[i-1] = data[i-1], data[i]

// Shift the smaller one to the left.
if i-a >= 2 {
for j := i - 1; j >= 1; j-- {
if !(cmp(data[j], data[j-1]) < 0) {
break
}
data[j], data[j-1] = data[j-1], data[j]
}
}
// Shift the greater one to the right.
if b-i >= 2 {
for j := i + 1; j < b; j++ {
if !(cmp(data[j], data[j-1]) < 0) {
break
}
data[j], data[j-1] = data[j-1], data[j]
}
}
}
return false
}

// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
// that might cause imbalanced partitions in quicksort.
func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
length := b - a
if length >= 8 {
random := xorshift(length)
modulus := nextPowerOfTwo(length)

for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
other := int(uint(random.Next()) & (modulus - 1))
if other >= length {
other -= length
}
data[idx], data[a+other] = data[a+other], data[idx]
}
}
}

// choosePivotCmpFunc chooses a pivot in data[a:b].
//
// [0,8): chooses a static pivot.
// [8,shortestNinther): uses the simple median-of-three method.
// [shortestNinther,∞): uses the Tukey ninther method.
func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
const (
shortestNinther = 50
maxSwaps = 4 * 3
)

l := b - a

var (
swaps int
i = a + l/4*1
j = a + l/4*2
k = a + l/4*3
)

if l >= 8 {
if l >= shortestNinther {
// Tukey ninther method, the idea came from Rust's implementation.
i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
}
// Find the median among i, j, k and stores it into j.
j = medianCmpFunc(data, i, j, k, &swaps, cmp)
}

switch swaps {
case 0:
return j, increasingHint
case maxSwaps:
return j, decreasingHint
default:
return j, unknownHint
}
}

// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
if cmp(data[b], data[a]) < 0 {
*swaps++
return b, a
}
return a, b
}

// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
a, b = order2CmpFunc(data, a, b, swaps, cmp)
b, c = order2CmpFunc(data, b, c, swaps, cmp)
a, b = order2CmpFunc(data, a, b, swaps, cmp)
return b
}

// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
}

func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
i := a
j := b - 1
for i < j {
data[i], data[j] = data[j], data[i]
i++
j--
}
}

func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
for i := 0; i < n; i++ {
data[a+i], data[b+i] = data[b+i], data[a+i]
}
}

func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
blockSize := 20 // must be > 0
a, b := 0, blockSize
for b <= n {
insertionSortCmpFunc(data, a, b, cmp)
a = b
b += blockSize
}
insertionSortCmpFunc(data, a, n, cmp)

for blockSize < n {
a, b = 0, 2*blockSize
for b <= n {
symMergeCmpFunc(data, a, a+blockSize, b, cmp)
a = b
b += 2 * blockSize
}
if m := a + blockSize; m < n {
symMergeCmpFunc(data, a, m, n, cmp)
}
blockSize *= 2
}
}

// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
// Computer Science, pages 714-723. Springer, 2004.
//
// Let M = m-a and N = b-n. Wolog M < N.
// The recursion depth is bound by ceil(log(N+M)).
// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
//
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
// in the paper carries through for Swap operations, especially as the block
// swapping rotate uses only O(M+N) Swaps.
//
// symMerge assumes non-degenerate arguments: a < m && m < b.
// Having the caller check this condition eliminates many leaf recursion calls,
// which improves performance.
func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
// Avoid unnecessary recursions of symMerge
// by direct insertion of data[a] into data[m:b]
// if data[a:m] only contains one element.
if m-a == 1 {
// Use binary search to find the lowest index i
// such that data[i] >= data[a] for m <= i < b.
// Exit the search loop with i == b in case no such index exists.
i := m
j := b
for i < j {
h := int(uint(i+j) >> 1)
if cmp(data[h], data[a]) < 0 {
i = h + 1
} else {
j = h
}
}
// Swap values until data[a] reaches the position before i.
for k := a; k < i-1; k++ {
data[k], data[k+1] = data[k+1], data[k]
}
return
}

// Avoid unnecessary recursions of symMerge
// by direct insertion of data[m] into data[a:m]
// if data[m:b] only contains one element.
if b-m == 1 {
// Use binary search to find the lowest index i
// such that data[i] > data[m] for a <= i < m.
// Exit the search loop with i == m in case no such index exists.
i := a
j := m
for i < j {
h := int(uint(i+j) >> 1)
if !(cmp(data[m], data[h]) < 0) {
i = h + 1
} else {
j = h
}
}
// Swap values until data[m] reaches the position i.
for k := m; k > i; k-- {
data[k], data[k-1] = data[k-1], data[k]
}
return
}

mid := int(uint(a+b) >> 1)
n := mid + m
var start, r int
if m > mid {
start = n - b
r = mid
} else {
start = a
r = m
}
p := n - 1

for start < r {
c := int(uint(start+r) >> 1)
if !(cmp(data[p-c], data[c]) < 0) {
start = c + 1
} else {
r = c
}
}

end := n - start
if start < m && m < end {
rotateCmpFunc(data, start, m, end, cmp)
}
if a < start && start < mid {
symMergeCmpFunc(data, a, start, mid, cmp)
}
if mid < end && end < b {
symMergeCmpFunc(data, mid, end, b, cmp)
}
}

// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
// Data of the form 'x u v y' is changed to 'x v u y'.
// rotate performs at most b-a many calls to data.Swap,
// and it assumes non-degenerate arguments: a < m && m < b.
func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
i := m - a
j := b - m

for i != j {
if i > j {
swapRangeCmpFunc(data, m-i, m, j, cmp)
i -= j
} else {
swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
j -= i
}
}
// i == j
swapRangeCmpFunc(data, m-i, m, i, cmp)
}

+ 481
- 0
vendor/golang.org/x/exp/slices/zsortordered.go View File

@@ -0,0 +1,481 @@
// Code generated by gen_sort_variants.go; DO NOT EDIT.

// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package slices

import "golang.org/x/exp/constraints"

// insertionSortOrdered sorts data[a:b] using insertion sort.
func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) {
for i := a + 1; i < b; i++ {
for j := i; j > a && cmpLess(data[j], data[j-1]); j-- {
data[j], data[j-1] = data[j-1], data[j]
}
}
}

// siftDownOrdered implements the heap property on data[lo:hi].
// first is an offset into the array where the root of the heap lies.
func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) {
root := lo
for {
child := 2*root + 1
if child >= hi {
break
}
if child+1 < hi && cmpLess(data[first+child], data[first+child+1]) {
child++
}
if !cmpLess(data[first+root], data[first+child]) {
return
}
data[first+root], data[first+child] = data[first+child], data[first+root]
root = child
}
}

func heapSortOrdered[E constraints.Ordered](data []E, a, b int) {
first := a
lo := 0
hi := b - a

// Build heap with greatest element at top.
for i := (hi - 1) / 2; i >= 0; i-- {
siftDownOrdered(data, i, hi, first)
}

// Pop elements, largest first, into end of data.
for i := hi - 1; i >= 0; i-- {
data[first], data[first+i] = data[first+i], data[first]
siftDownOrdered(data, lo, i, first)
}
}

// pdqsortOrdered sorts data[a:b].
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
// C++ implementation: https://github.com/orlp/pdqsort
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
func pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) {
const maxInsertion = 12

var (
wasBalanced = true // whether the last partitioning was reasonably balanced
wasPartitioned = true // whether the slice was already partitioned
)

for {
length := b - a

if length <= maxInsertion {
insertionSortOrdered(data, a, b)
return
}

// Fall back to heapsort if too many bad choices were made.
if limit == 0 {
heapSortOrdered(data, a, b)
return
}

// If the last partitioning was imbalanced, we need to breaking patterns.
if !wasBalanced {
breakPatternsOrdered(data, a, b)
limit--
}

pivot, hint := choosePivotOrdered(data, a, b)
if hint == decreasingHint {
reverseRangeOrdered(data, a, b)
// The chosen pivot was pivot-a elements after the start of the array.
// After reversing it is pivot-a elements before the end of the array.
// The idea came from Rust's implementation.
pivot = (b - 1) - (pivot - a)
hint = increasingHint
}

// The slice is likely already sorted.
if wasBalanced && wasPartitioned && hint == increasingHint {
if partialInsertionSortOrdered(data, a, b) {
return
}
}

// Probably the slice contains many duplicate elements, partition the slice into
// elements equal to and elements greater than the pivot.
if a > 0 && !cmpLess(data[a-1], data[pivot]) {
mid := partitionEqualOrdered(data, a, b, pivot)
a = mid
continue
}

mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot)
wasPartitioned = alreadyPartitioned

leftLen, rightLen := mid-a, b-mid
balanceThreshold := length / 8
if leftLen < rightLen {
wasBalanced = leftLen >= balanceThreshold
pdqsortOrdered(data, a, mid, limit)
a = mid + 1
} else {
wasBalanced = rightLen >= balanceThreshold
pdqsortOrdered(data, mid+1, b, limit)
b = mid
}
}
}

// partitionOrdered does one quicksort partition.
// Let p = data[pivot]
// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
// On return, data[newpivot] = p
func partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) {
data[a], data[pivot] = data[pivot], data[a]
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned

for i <= j && cmpLess(data[i], data[a]) {
i++
}
for i <= j && !cmpLess(data[j], data[a]) {
j--
}
if i > j {
data[j], data[a] = data[a], data[j]
return j, true
}
data[i], data[j] = data[j], data[i]
i++
j--

for {
for i <= j && cmpLess(data[i], data[a]) {
i++
}
for i <= j && !cmpLess(data[j], data[a]) {
j--
}
if i > j {
break
}
data[i], data[j] = data[j], data[i]
i++
j--
}
data[j], data[a] = data[a], data[j]
return j, false
}

// partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
func partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) {
data[a], data[pivot] = data[pivot], data[a]
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned

for {
for i <= j && !cmpLess(data[a], data[i]) {
i++
}
for i <= j && cmpLess(data[a], data[j]) {
j--
}
if i > j {
break
}
data[i], data[j] = data[j], data[i]
i++
j--
}
return i
}

// partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end.
func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool {
const (
maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
shortestShifting = 50 // don't shift any elements on short arrays
)
i := a + 1
for j := 0; j < maxSteps; j++ {
for i < b && !cmpLess(data[i], data[i-1]) {
i++
}

if i == b {
return true
}

if b-a < shortestShifting {
return false
}

data[i], data[i-1] = data[i-1], data[i]

// Shift the smaller one to the left.
if i-a >= 2 {
for j := i - 1; j >= 1; j-- {
if !cmpLess(data[j], data[j-1]) {
break
}
data[j], data[j-1] = data[j-1], data[j]
}
}
// Shift the greater one to the right.
if b-i >= 2 {
for j := i + 1; j < b; j++ {
if !cmpLess(data[j], data[j-1]) {
break
}
data[j], data[j-1] = data[j-1], data[j]
}
}
}
return false
}

// breakPatternsOrdered scatters some elements around in an attempt to break some patterns
// that might cause imbalanced partitions in quicksort.
func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) {
length := b - a
if length >= 8 {
random := xorshift(length)
modulus := nextPowerOfTwo(length)

for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
other := int(uint(random.Next()) & (modulus - 1))
if other >= length {
other -= length
}
data[idx], data[a+other] = data[a+other], data[idx]
}
}
}

// choosePivotOrdered chooses a pivot in data[a:b].
//
// [0,8): chooses a static pivot.
// [8,shortestNinther): uses the simple median-of-three method.
// [shortestNinther,∞): uses the Tukey ninther method.
func choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) {
const (
shortestNinther = 50
maxSwaps = 4 * 3
)

l := b - a

var (
swaps int
i = a + l/4*1
j = a + l/4*2
k = a + l/4*3
)

if l >= 8 {
if l >= shortestNinther {
// Tukey ninther method, the idea came from Rust's implementation.
i = medianAdjacentOrdered(data, i, &swaps)
j = medianAdjacentOrdered(data, j, &swaps)
k = medianAdjacentOrdered(data, k, &swaps)
}
// Find the median among i, j, k and stores it into j.
j = medianOrdered(data, i, j, k, &swaps)
}

switch swaps {
case 0:
return j, increasingHint
case maxSwaps:
return j, decreasingHint
default:
return j, unknownHint
}
}

// order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) {
if cmpLess(data[b], data[a]) {
*swaps++
return b, a
}
return a, b
}

// medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int {
a, b = order2Ordered(data, a, b, swaps)
b, c = order2Ordered(data, b, c, swaps)
a, b = order2Ordered(data, a, b, swaps)
return b
}

// medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int {
return medianOrdered(data, a-1, a, a+1, swaps)
}

func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) {
i := a
j := b - 1
for i < j {
data[i], data[j] = data[j], data[i]
i++
j--
}
}

func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) {
for i := 0; i < n; i++ {
data[a+i], data[b+i] = data[b+i], data[a+i]
}
}

func stableOrdered[E constraints.Ordered](data []E, n int) {
blockSize := 20 // must be > 0
a, b := 0, blockSize
for b <= n {
insertionSortOrdered(data, a, b)
a = b
b += blockSize
}
insertionSortOrdered(data, a, n)

for blockSize < n {
a, b = 0, 2*blockSize
for b <= n {
symMergeOrdered(data, a, a+blockSize, b)
a = b
b += 2 * blockSize
}
if m := a + blockSize; m < n {
symMergeOrdered(data, a, m, n)
}
blockSize *= 2
}
}

// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using
// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
// Computer Science, pages 714-723. Springer, 2004.
//
// Let M = m-a and N = b-n. Wolog M < N.
// The recursion depth is bound by ceil(log(N+M)).
// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
//
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
// in the paper carries through for Swap operations, especially as the block
// swapping rotate uses only O(M+N) Swaps.
//
// symMerge assumes non-degenerate arguments: a < m && m < b.
// Having the caller check this condition eliminates many leaf recursion calls,
// which improves performance.
func symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) {
// Avoid unnecessary recursions of symMerge
// by direct insertion of data[a] into data[m:b]
// if data[a:m] only contains one element.
if m-a == 1 {
// Use binary search to find the lowest index i
// such that data[i] >= data[a] for m <= i < b.
// Exit the search loop with i == b in case no such index exists.
i := m
j := b
for i < j {
h := int(uint(i+j) >> 1)
if cmpLess(data[h], data[a]) {
i = h + 1
} else {
j = h
}
}
// Swap values until data[a] reaches the position before i.
for k := a; k < i-1; k++ {
data[k], data[k+1] = data[k+1], data[k]
}
return
}

// Avoid unnecessary recursions of symMerge
// by direct insertion of data[m] into data[a:m]
// if data[m:b] only contains one element.
if b-m == 1 {
// Use binary search to find the lowest index i
// such that data[i] > data[m] for a <= i < m.
// Exit the search loop with i == m in case no such index exists.
i := a
j := m
for i < j {
h := int(uint(i+j) >> 1)
if !cmpLess(data[m], data[h]) {
i = h + 1
} else {
j = h
}
}
// Swap values until data[m] reaches the position i.
for k := m; k > i; k-- {
data[k], data[k-1] = data[k-1], data[k]
}
return
}

mid := int(uint(a+b) >> 1)
n := mid + m
var start, r int
if m > mid {
start = n - b
r = mid
} else {
start = a
r = m
}
p := n - 1

for start < r {
c := int(uint(start+r) >> 1)
if !cmpLess(data[p-c], data[c]) {
start = c + 1
} else {
r = c
}
}

end := n - start
if start < m && m < end {
rotateOrdered(data, start, m, end)
}
if a < start && start < mid {
symMergeOrdered(data, a, start, mid)
}
if mid < end && end < b {
symMergeOrdered(data, mid, end, b)
}
}

// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
// Data of the form 'x u v y' is changed to 'x v u y'.
// rotate performs at most b-a many calls to data.Swap,
// and it assumes non-degenerate arguments: a < m && m < b.
func rotateOrdered[E constraints.Ordered](data []E, a, m, b int) {
i := m - a
j := b - m

for i != j {
if i > j {
swapRangeOrdered(data, m-i, m, j)
i -= j
} else {
swapRangeOrdered(data, m-i, m+j-i, i)
j -= i
}
}
// i == j
swapRangeOrdered(data, m-i, m, i)
}

+ 1
- 1
vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go View File

@@ -13,7 +13,7 @@ import (
"sync"
)

// Regexp is a wrapper around regexp.Regexp, where the underlying regexp will be
// Regexp is a wrapper around [regexp.Regexp], where the underlying regexp will be
// compiled the first time it is needed.
type Regexp struct {
str string


+ 15
- 15
vendor/golang.org/x/mod/module/module.go View File

@@ -4,7 +4,7 @@

// Package module defines the module.Version type along with support code.
//
// The module.Version type is a simple Path, Version pair:
// The [module.Version] type is a simple Path, Version pair:
//
// type Version struct {
// Path string
@@ -12,7 +12,7 @@
// }
//
// There are no restrictions imposed directly by use of this structure,
// but additional checking functions, most notably Check, verify that
// but additional checking functions, most notably [Check], verify that
// a particular path, version pair is valid.
//
// # Escaped Paths
@@ -140,7 +140,7 @@ type ModuleError struct {
Err error
}

// VersionError returns a ModuleError derived from a Version and error,
// VersionError returns a [ModuleError] derived from a [Version] and error,
// or err itself if it is already such an error.
func VersionError(v Version, err error) error {
var mErr *ModuleError
@@ -169,7 +169,7 @@ func (e *ModuleError) Unwrap() error { return e.Err }
// An InvalidVersionError indicates an error specific to a version, with the
// module path unknown or specified externally.
//
// A ModuleError may wrap an InvalidVersionError, but an InvalidVersionError
// A [ModuleError] may wrap an InvalidVersionError, but an InvalidVersionError
// must not wrap a ModuleError.
type InvalidVersionError struct {
Version string
@@ -193,8 +193,8 @@ func (e *InvalidVersionError) Error() string {
func (e *InvalidVersionError) Unwrap() error { return e.Err }

// An InvalidPathError indicates a module, import, or file path doesn't
// satisfy all naming constraints. See CheckPath, CheckImportPath,
// and CheckFilePath for specific restrictions.
// satisfy all naming constraints. See [CheckPath], [CheckImportPath],
// and [CheckFilePath] for specific restrictions.
type InvalidPathError struct {
Kind string // "module", "import", or "file"
Path string
@@ -294,7 +294,7 @@ func fileNameOK(r rune) bool {
}

// CheckPath checks that a module path is valid.
// A valid module path is a valid import path, as checked by CheckImportPath,
// A valid module path is a valid import path, as checked by [CheckImportPath],
// with three additional constraints.
// First, the leading path element (up to the first slash, if any),
// by convention a domain name, must contain only lower-case ASCII letters,
@@ -380,7 +380,7 @@ const (
// checkPath returns an error describing why the path is not valid.
// Because these checks apply to module, import, and file paths,
// and because other checks may be applied, the caller is expected to wrap
// this error with InvalidPathError.
// this error with [InvalidPathError].
func checkPath(path string, kind pathKind) error {
if !utf8.ValidString(path) {
return fmt.Errorf("invalid UTF-8")
@@ -532,7 +532,7 @@ var badWindowsNames = []string{
// they require ".vN" instead of "/vN", and for all N, not just N >= 2.
// SplitPathVersion returns with ok = false when presented with
// a path whose last path element does not satisfy the constraints
// applied by CheckPath, such as "example.com/pkg/v1" or "example.com/pkg/v1.2".
// applied by [CheckPath], such as "example.com/pkg/v1" or "example.com/pkg/v1.2".
func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) {
if strings.HasPrefix(path, "gopkg.in/") {
return splitGopkgIn(path)
@@ -582,7 +582,7 @@ func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) {
// MatchPathMajor reports whether the semantic version v
// matches the path major version pathMajor.
//
// MatchPathMajor returns true if and only if CheckPathMajor returns nil.
// MatchPathMajor returns true if and only if [CheckPathMajor] returns nil.
func MatchPathMajor(v, pathMajor string) bool {
return CheckPathMajor(v, pathMajor) == nil
}
@@ -622,7 +622,7 @@ func CheckPathMajor(v, pathMajor string) error {
// PathMajorPrefix returns the major-version tag prefix implied by pathMajor.
// An empty PathMajorPrefix allows either v0 or v1.
//
// Note that MatchPathMajor may accept some versions that do not actually begin
// Note that [MatchPathMajor] may accept some versions that do not actually begin
// with this prefix: namely, it accepts a 'v0.0.0-' prefix for a '.v1'
// pathMajor, even though that pathMajor implies 'v1' tagging.
func PathMajorPrefix(pathMajor string) string {
@@ -643,7 +643,7 @@ func PathMajorPrefix(pathMajor string) string {
}

// CanonicalVersion returns the canonical form of the version string v.
// It is the same as semver.Canonical(v) except that it preserves the special build suffix "+incompatible".
// It is the same as [semver.Canonical] except that it preserves the special build suffix "+incompatible".
func CanonicalVersion(v string) string {
cv := semver.Canonical(v)
if semver.Build(v) == "+incompatible" {
@@ -652,8 +652,8 @@ func CanonicalVersion(v string) string {
return cv
}

// Sort sorts the list by Path, breaking ties by comparing Version fields.
// The Version fields are interpreted as semantic versions (using semver.Compare)
// Sort sorts the list by Path, breaking ties by comparing [Version] fields.
// The Version fields are interpreted as semantic versions (using [semver.Compare])
// optionally followed by a tie-breaking suffix introduced by a slash character,
// like in "v0.0.1/go.mod".
func Sort(list []Version) {
@@ -793,7 +793,7 @@ func unescapeString(escaped string) (string, bool) {
}

// MatchPrefixPatterns reports whether any path prefix of target matches one of
// the glob patterns (as defined by path.Match) in the comma-separated globs
// the glob patterns (as defined by [path.Match]) in the comma-separated globs
// list. This implements the algorithm used when matching a module path to the
// GOPRIVATE environment variable, as described by 'go help module-private'.
//


+ 1
- 1
vendor/golang.org/x/mod/module/pseudo.go View File

@@ -125,7 +125,7 @@ func IsPseudoVersion(v string) bool {
}

// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base,
// timestamp, and revision, as returned by ZeroPseudoVersion.
// timestamp, and revision, as returned by [ZeroPseudoVersion].
func IsZeroPseudoVersion(v string) bool {
return v == ZeroPseudoVersion(semver.Major(v))
}


+ 3
- 3
vendor/golang.org/x/mod/semver/semver.go View File

@@ -140,7 +140,7 @@ func Compare(v, w string) int {
// Max canonicalizes its arguments and then returns the version string
// that compares greater.
//
// Deprecated: use Compare instead. In most cases, returning a canonicalized
// Deprecated: use [Compare] instead. In most cases, returning a canonicalized
// version is not expected or desired.
func Max(v, w string) string {
v = Canonical(v)
@@ -151,7 +151,7 @@ func Max(v, w string) string {
return w
}

// ByVersion implements sort.Interface for sorting semantic version strings.
// ByVersion implements [sort.Interface] for sorting semantic version strings.
type ByVersion []string

func (vs ByVersion) Len() int { return len(vs) }
@@ -164,7 +164,7 @@ func (vs ByVersion) Less(i, j int) bool {
return vs[i] < vs[j]
}

// Sort sorts a list of semantic version strings using ByVersion.
// Sort sorts a list of semantic version strings using [ByVersion].
func Sort(list []string) {
sort.Sort(ByVersion(list))
}


+ 0
- 1
vendor/golang.org/x/net/context/go17.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.7
// +build go1.7

package context



+ 0
- 1
vendor/golang.org/x/net/context/go19.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build go1.9
// +build go1.9

package context



+ 0
- 1
vendor/golang.org/x/net/context/pre_go17.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !go1.7
// +build !go1.7

package context



+ 0
- 1
vendor/golang.org/x/net/context/pre_go19.go View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.

//go:build !go1.9
// +build !go1.9

package context



+ 31
- 28
vendor/golang.org/x/net/http2/databuffer.go View File

@@ -20,41 +20,44 @@ import (
// TODO: Benchmark to determine if the pools are necessary. The GC may have
// improved enough that we can instead allocate chunks like this:
// make([]byte, max(16<<10, expectedBytesRemaining))
var (
dataChunkSizeClasses = []int{
1 << 10,
2 << 10,
4 << 10,
8 << 10,
16 << 10,
}
dataChunkPools = [...]sync.Pool{
{New: func() interface{} { return make([]byte, 1<<10) }},
{New: func() interface{} { return make([]byte, 2<<10) }},
{New: func() interface{} { return make([]byte, 4<<10) }},
{New: func() interface{} { return make([]byte, 8<<10) }},
{New: func() interface{} { return make([]byte, 16<<10) }},
}
)
var dataChunkPools = [...]sync.Pool{
{New: func() interface{} { return new([1 << 10]byte) }},
{New: func() interface{} { return new([2 << 10]byte) }},
{New: func() interface{} { return new([4 << 10]byte) }},
{New: func() interface{} { return new([8 << 10]byte) }},
{New: func() interface{} { return new([16 << 10]byte) }},
}

func getDataBufferChunk(size int64) []byte {
i := 0
for ; i < len(dataChunkSizeClasses)-1; i++ {
if size <= int64(dataChunkSizeClasses[i]) {
break
}
switch {
case size <= 1<<10:
return dataChunkPools[0].Get().(*[1 << 10]byte)[:]
case size <= 2<<10:
return dataChunkPools[1].Get().(*[2 << 10]byte)[:]
case size <= 4<<10:
return dataChunkPools[2].Get().(*[4 << 10]byte)[:]
case size <= 8<<10:
return dataChunkPools[3].Get().(*[8 << 10]byte)[:]
default:
return dataChunkPools[4].Get().(*[16 << 10]byte)[:]
}
return dataChunkPools[i].Get().([]byte)
}

func putDataBufferChunk(p []byte) {
for i, n := range dataChunkSizeClasses {
if len(p) == n {
dataChunkPools[i].Put(p)
return
}
switch len(p) {
case 1 << 10:
dataChunkPools[0].Put((*[1 << 10]byte)(p))
case 2 << 10:
dataChunkPools[1].Put((*[2 << 10]byte)(p))
case 4 << 10:
dataChunkPools[2].Put((*[4 << 10]byte)(p))
case 8 << 10:
dataChunkPools[3].Put((*[8 << 10]byte)(p))
case 16 << 10:
dataChunkPools[4].Put((*[16 << 10]byte)(p))
default:
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
}
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
}

// dataBuffer is an io.ReadWriter backed by a list of data chunks.


+ 0
- 30
vendor/golang.org/x/net/http2/go111.go View File

@@ -1,30 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build go1.11
// +build go1.11

package http2

import (
"net/http/httptrace"
"net/textproto"
)

func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
return trace != nil && trace.WroteHeaderField != nil
}

func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
if trace != nil && trace.WroteHeaderField != nil {
trace.WroteHeaderField(k, []string{v})
}
}

func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if trace != nil {
return trace.Got1xxResponse
}
return nil
}

+ 0
- 27
vendor/golang.org/x/net/http2/go115.go View File

@@ -1,27 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build go1.15
// +build go1.15

package http2

import (
"context"
"crypto/tls"
)

// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
dialer := &tls.Dialer{
Config: cfg,
}
cn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
return tlsCn, nil
}

+ 0
- 17
vendor/golang.org/x/net/http2/go118.go View File

@@ -1,17 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build go1.18
// +build go1.18

package http2

import (
"crypto/tls"
"net"
)

func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
return tc.NetConn()
}

+ 0
- 21
vendor/golang.org/x/net/http2/not_go111.go View File

@@ -1,21 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build !go1.11
// +build !go1.11

package http2

import (
"net/http/httptrace"
"net/textproto"
)

func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { return false }

func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {}

func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
return nil
}

+ 0
- 31
vendor/golang.org/x/net/http2/not_go115.go View File

@@ -1,31 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build !go1.15
// +build !go1.15

package http2

import (
"context"
"crypto/tls"
)

// dialTLSWithContext opens a TLS connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
cn, err := tls.Dial(network, addr, cfg)
if err != nil {
return nil, err
}
if err := cn.Handshake(); err != nil {
return nil, err
}
if cfg.InsecureSkipVerify {
return cn, nil
}
if err := cn.VerifyHostname(cfg.ServerName); err != nil {
return nil, err
}
return cn, nil
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save